So this program that I wrote is supposed to draw a circle everytime click on the panel. For some reason I initially have a semicircle in the top right hand corner upon startup, and I can't get it to draw a circle. Can anyone see what's wrong with it? The circle should be 20 px in diameter, drawn with the clicked point at its center.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class QuizActionsInitial extends JFrame {
public JButton redButton = new JButton("red");
public JButton clearButton = new JButton("clear");
boolean isRed = false;
int x1,y1;
boolean clear = false;
CirclePanel myPanel;
public QuizActionsInitial() {
myPanel = new CirclePanel();
add(myPanel, BorderLayout.SOUTH);
JPanel southPanel = new JPanel(new FlowLayout());
clearButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
clear = true;
}
});
myPanel.addMouseListener(new CircleListener());
southPanel.add(redButton);
southPanel.add(clearButton);
add(southPanel, BorderLayout.NORTH);
pack();
setVisible(true);
} // end constructor
public class CirclePanel extends JPanel {
public CirclePanel() {
setPreferredSize(new Dimension(400,300));
setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
}
public void paintComponent(Graphics gc){
super.paintComponent(gc);
gc.fillOval(x1-10,y1-10,20,20);
}
} // end class CirclePanel
// end class CirclePanel
public class CircleListener extends MouseAdapter{
public void mouseClicked(MouseEvent e){
if (clear = false){
x1 = e.getX();
y1 = e.getY();
}
repaint();
clear = false;
}
}
public static void main(String args[]) {
new QuizActionsInitial();
} // end main
} // end class QuizActionsInitial
int x1,y1; initialise the values to 0, so you it will always draw an initial circle at -10x-10
Trying using a java.awt.Point class instead, and when it's null, don't paint anything...
//int x1,y1;
private Point point;
//...
public void paintComponent(Graphics gc){
super.paintComponent(gc);
if (point != null) {
gc.fillOval(point.x-10,point.y-10,20,20);
}
}
//...
public void mouseClicked(MouseEvent e){
if (!clear){
point = evt.getPoint();
}
clear = false;
repaint();
}
Oh, and if (clear = false){ is an assignment (making clear equal to false, so that the if statement will ALWAYS fail)
Related
Im using JPanel and JFrame to create a program that can draw lines and circles. The problem is that my program only redraws the last object added.
I have tried moving around the repaint. For some reason, when I directly draw shapes onto the graphic in paintComponent(), they show up and refresh each frame. However, I have methods inside of paintComponent that pass the graphic variable to elsewhere methods that draw to the graphic object, these are the shapes that do not show up.
Painter Class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Painter implements ActionListener, MouseListener, MouseMotionListener {
/**
*
*/
Color temp = Color.RED;
// 0 = line, 1 = circle
int object = 0;
PaintingPanel canvas;
Point startPoint = new Point();
Point endPoint = new Point();
Painter() {
//buttons
JButton circleBut = new JButton();
JButton lineBut = new JButton();
//frame
//close operation
//resizes
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
//holder holds the information
JPanel holder = new JPanel();
JPanel leftPanel = new JPanel();
holder.setLayout(new BorderLayout());
leftPanel.setLayout(new GridLayout(3, 1)); // 3 by 1 grid
JPanel northPanel = new JPanel();
northPanel.setLayout(new GridLayout(1, 2)); // 3 by 1 grid
frame.add(holder);
// circle and line buttons
circleBut.setText("Circle");
lineBut.setText("Line");
northPanel.add(circleBut);
northPanel.add(lineBut);
circleBut.setActionCommand("1");
lineBut.setActionCommand("0");
//
holder.add(northPanel, BorderLayout.NORTH);
// red
JButton redPaint = new JButton();
redPaint.setBackground(Color.RED);
redPaint.setOpaque(true);
redPaint.setBorderPainted(false);
leftPanel.add(redPaint);
redPaint.setActionCommand("red");
// green
JButton greenPaint = new JButton();
greenPaint.setBackground(Color.GREEN);
greenPaint.setOpaque(true);
greenPaint.setBorderPainted(false);
leftPanel.add(greenPaint);
greenPaint.setActionCommand("green");
// blue
JButton bluePaint = new JButton();
bluePaint.setBackground(Color.BLUE);
bluePaint.setOpaque(true);
bluePaint.setBorderPainted(false);
leftPanel.add(bluePaint);
bluePaint.setActionCommand("blue");
holder.add(leftPanel, BorderLayout.WEST);
// still need to add painting panel to the CENTER panel
canvas = new PaintingPanel();
holder.add(canvas, BorderLayout.CENTER);
circleBut.addActionListener(this);
lineBut.addActionListener(this);
redPaint.addActionListener(this);
greenPaint.addActionListener(this);
bluePaint.addActionListener(this);
canvas.addMouseListener(this);
//holder.addMouseMotionListener(this);
// still need to add chat panel to the SOUTH panel
frame.setContentPane(holder);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("red")) {
temp = Color.RED;
System.out.println("received r");
} else if (e.getActionCommand().equals("green")) {
temp = Color.GREEN;
System.out.println("received g");
} else if (e.getActionCommand().equals("blue")) {
temp = Color.BLUE;
System.out.println("received b");
} else if (e.getActionCommand().equals("0")) {
object = 0;
System.out.println("received 0");
} else if (e.getActionCommand().equals("1")) {
object = 1;
System.out.println("received 1");
}
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
startPoint.setLocation(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
// and this one
endPoint.setLocation(e.getPoint());
if (object == 0) {
canvas.addPrimitive(new Line(startPoint, endPoint, temp));
}
if (object == 1){
canvas.addPrimitive(new Circle(startPoint, endPoint, temp));
}
canvas.repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
Painter game1 = new Painter();
}
}
PaintingPrimitives:
`
import java.awt.Graphics;
import java.awt.Color;
public abstract class PaintingPrimitive{
Color color;
PaintingPrimitive(Color color) {
this.color = color;
}
// This is an example of the Template Design Pattern
// this is all invariant code
public final void draw(Graphics g) {
g.setColor(color);
drawGeometry(g);
}
public void setColor(Color color) {
this.color = color;
}
protected abstract void drawGeometry(Graphics g);
}
Line Class:
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Color;
public class Line extends PaintingPrimitive{
Point startPoint = new Point();
Point endPoint = new Point();
public Line(Point start, Point end, Color c) {
super(c);
this.startPoint = start;
this.endPoint = end;
}
public void drawGeometry(Graphics g) {
System.out.println("graw geo called");
g.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
}
#Override
public String toString() {
return "Line";
}
}
Painting Panel:
import java.util.ArrayList;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class PaintingPanel extends JPanel {
ArrayList<PaintingPrimitive> primitives = new ArrayList<PaintingPrimitive>();
PaintingPanel() {
setBackground(Color.WHITE);
}
public void addPrimitive(PaintingPrimitive obj) {
primitives.add(obj);
this.repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// i'm confident that this is not painting to the right graphics
for (PaintingPrimitive shape : primitives) {
//g.dispose();
//this line works. this line is drawn each time its updated.
g.drawLine(0,0,100,100);
shape.draw(g);
}
}
}
`
Okay, that was weird, until it wasn't. Your problem basic centers around...
public void mousePressed(MouseEvent e) {
startPoint.setLocation(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
// and this one
endPoint.setLocation(e.getPoint());
if (object == 0) {
canvas.addPrimitive(new Line(startPoint, endPoint, temp));
}
You create a single instance of startPoint and endPoint and simply update the location of each Point. You then pass these to each primitive you create. This means that each primitive is using the SAME instance of startPoint and endPoint. So, each time you call setLocation ALL the primitives are been updated.
Instead, do something more like...
#Override
public void mousePressed(MouseEvent e) {
startPoint = new Point(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
// and this one
endPoint = new Point(e.getPoint());
And because I'm paranoid and don't trust any one, I'd probably also do...
public class Line extends PaintingPrimitive {
Point startPoint = new Point();
Point endPoint = new Point();
public Line(Point start, Point end, Color c) {
super(c);
this.startPoint = new Point(start);
this.endPoint = new Point(end);
}
Just to be sure
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
My main problem is I am confused on where to implement the listener classes so that whenever an action is made (whether it be a key press or mouse click) the applet is updated. I realize my compiling issue is from my CanvasPanel method in my CanvasPanel class and not having arguments in my actionPerformed method. However at this point I'm not sure how these listeners should be implemented correctly. Have tried looking over different questions already posted, so sorry if it is a duplicate.
Here is my code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class WholePanel extends JPanel
{
private Color foregroundColor, backgroundColor;
private int currentDiameter, x1, y1;
private CanvasPanel canvas;
private JPanel buttonPanel;
private JRadioButton filledRadio, unfilledRadio;
private JRadioButton redRadio, greenRadio;
private boolean fill;
private Graphics myCircle;
public WholePanel()
{
backgroundColor = Color.CYAN;
foregroundColor = Color.RED;
currentDiameter = 100;
x1 = 200; y1 = 100;
unfilledRadio = new JRadioButton("Unfilled", true);
filledRadio = new JRadioButton("Filled", false);
redRadio = new JRadioButton("Red", true);
greenRadio = new JRadioButton("Green", false);
buttonPanel = new JPanel();
buttonPanel.add(unfilledRadio);
buttonPanel.add(filledRadio);
buttonPanel.add(redRadio);
buttonPanel.add(greenRadio);
canvas = new CanvasPanel();
JSplitPane sPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, buttonPanel, canvas);
setLayout(new BorderLayout());
add(sPane, BorderLayout.CENTER);
}
private class ColorListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (redRadio.isSelected()) {
greenRadio.setSelected(false);
backgroundColor = Color.RED;
}
else if (greenRadio.isSelected()) {
redRadio.setSelected(false);
backgroundColor = Color.GREEN;
}
// ...extra else/if statements
}
} // end of ColorListener
private class FillListener implements ActionListener
{
private boolean fill;
public void actionPerformed(ActionEvent event)
{
if (filledRadio.isSelected()) {
unfilledRadio.setSelected(false);
fill = true;
paintComponent(myCircle);
}
else if (unfilledRadio.isSelected()) {
filledRadio.setSelected(false);
fill = false;
paintComponent(myCircle);
}
}
}
private class CanvasPanel extends JPanel
{
public CanvasPanel( )
{
addKeyListener(new DirectionListener());
addMouseListener(new PointListener());
setBackground(backgroundColor);
//This method needs to be called for this panel to listen to keys
//When panel listens to other things, and go back to listen
//to keys, this method needs to be called again.
ColorListener.actionPerformed();
FillListener.actionPerformed();
requestFocus();
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
setBackground(backgroundColor);
page.setColor(foregroundColor);
page.drawOval(x1, y1, currentDiameter, currentDiameter);
if (fill == true) {
page.fillOval(x1, y1, currentDiameter, currentDiameter);
}
}
/** This method is overriden to enable keyboard focus */
public boolean isFocusable()
{
return true;
}
private class DirectionListener implements KeyListener
{
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e)
{
currentDiameter = 100;
x1 = 200; y1 = 100;
int keyCode = e.getKeyCode();
// switch statement here
}
}
} // end of DirectionListener
public class PointListener implements MouseListener
{
public void mousePressed (MouseEvent event)
{
canvas.requestFocus();
}
public void mouseClicked (MouseEvent event) {}
public void mouseReleased (MouseEvent event) {}
public void mouseEntered (MouseEvent event) {}
public void mouseExited (MouseEvent event) {}
} // end of PointListener
} // end of Canvas Panel Class
} // end of Whole Panel Class
Some major problems in that code:
You're calling paintComponent directly, something you should never do. Instead change a state field of your class, call repaint()and then have paintComponent use the state field to decide what it should paint.
Same for using a Graphics field -- don't. Instead only use the Graphics object given to your paintComponent method by the JVM. The Swing Graphics tutorial will explain this.
You're trying to call your listener call back methods directly, which is the exact opposite of how listeners are supposed to work and negates the benefits of using listeners. Instead ADD your listeners to the components that will use them -- including adding the ActionListeners to the buttons that need them, the KeyListeners to the components that need them, MouseListeners... etc...
For instance, let's look at a much simpler example, one that uses two JRadioButtons and that's it:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class PartialPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final int CIRC_W = 200;
private int circleX = 300;
private int circleY = 200;
private Color circleColor = null;
private ButtonGroup buttonGroup = new ButtonGroup();
private JRadioButton blueButton = new JRadioButton("Blue");
private JRadioButton redButton = new JRadioButton("Red");
public PartialPanel() {
ColorListener colorListener = new ColorListener();
blueButton.addActionListener(colorListener);
redButton.addActionListener(colorListener);
buttonGroup.add(blueButton);
buttonGroup.add(redButton);
JPanel buttonPanel = new JPanel();
buttonPanel.add(blueButton);
buttonPanel.add(redButton);
add(buttonPanel);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (circleColor != null) {
g.setColor(circleColor);
g.fillOval(circleX, circleY, CIRC_W, CIRC_W);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
private class ColorListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == blueButton) {
circleColor = Color.BLUE;
} else if (e.getSource() == redButton) {
circleColor = Color.RED;
}
repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
PartialPanel mainPanel = new PartialPanel();
JFrame frame = new JFrame("PartialPanel");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Here we add a ColorListener to the JRadioButtons. In the listener, we change the state of the class's circColor field, and then call repaint(). The paintComponent method then uses circColor's value to decide what color to use when drawing a circle.
I am having a problem with my code, if I click on rectangle and do the mouse clicks on the screen it will show the shape and it works fine.. but if I clicked on the circle after that, all the rec
tangles that have been stored stays on same location but changes to circle. how can I prevent the shapes that have been stored from changing?
First Class:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class MouseClick implements ActionListener{
private static int x,y;
private static DrawingObjects object = new DrawingObjects();
JPanel panel = new JPanel();
JFrame frame = new JFrame("MouseClick");
MouseClick(){
dObjects();
}
void dObjects() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(2,2));
frame.add(object);
frame.add(panel);
panel.setBackground(Color.WHITE);
panel.setSize(10, 300);
panel.setLocation(100, 200);
panel.setLayout(new GridLayout(1,2));
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setSize(400, 400);
object.addMouseListener(new AL());
Button rect = new Button("Rectangle");
Button oval = new Button("Circle");
panel.add(rect);
panel.add(oval);
rect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
object.setType(1);
}
});
oval.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
object.setType(2);
}
}); }
public static void main(String[] args){
new MouseClick();
}
static class AL extends MouseAdapter{
public void mouseClicked (MouseEvent e){
x = e.getX();
y = e.getY();
object.drawing(x, y);
}
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
Second Class:
import javax.swing.*;
import javafx.scene.input.MouseEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
public class DrawingObjects extends JPanel{
private ArrayList<Point> points = new ArrayList<>();
public int shapetype ;
public void drawing(int x, int y){
points.add(new Point(x, y));
repaint();
}
public void setType(int choice){
if(choice==1){
shapetype = 1;
}
else if (choice ==2){
shapetype = 2;
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(shapetype == 1){
for(Point p : points){
g.fillRect(p.x, p.y, 60, 20);
g.setColor(Color.GREEN);
repaint();
}
}
else if (shapetype == 2){
for(Point p : points){
g.fillOval(p.x, p.y, 20, 20);
g.setColor(Color.RED);
repaint();
}
}
}
}
The problem occurs because the shapetype is not stored along with the points on which the shapes are drawn. As a result, within the paintComponent method, when all shapes in locations stored in points array get redrawn, they use the current value of shapetype. Not the value of shapetype when the shape was created for the first time.
A simple (yet not the best) solution, with minimum code change would be to store the shapetype as follows.
In DrawingObjects class, add another array to store the shapetype.
private ArrayList<Integer> shapeTypes = new ArrayList<>();
Update the drawing method as follows to store the current shapetype along with the point.
public void drawing(int x, int y) {
points.add(new Point(x, y));
shapeTypes.add(shapetype);
repaint();
}
Refer the stored shapetype when repainting the shapes as follows.
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < points.size(); i++) {
Point p = points.get(i);
if (shapeTypes.get(i) == 1) {
g.fillRect(p.x, p.y, 60, 20);
g.setColor(Color.GREEN);
repaint();
} else if (shapeTypes.get(i) == 2) {
g.fillOval(p.x, p.y, 20, 20);
g.setColor(Color.RED);
repaint();
}
}
}
A better design would be to create a separate class with the capability to store the location as well as the shape type with the implementation on how it should be painted.
I am a bit new to threading, so bear with me. All relevant classes will be below the text in one place for easier reference.
Backstory:
I created a simple pong-like game following this tutorial: http://www.edu4java.com/en/game/game1.html
Everything worked perfectly, then I made modifications to better understand how it all works. In the tutorial, there is a main method from which the animations are played continuously. According to the tutorial author, Thread.sleep(10) "...tells the processor that the thread which is being run must sleep for 10 ms, which allows the processor to execute other threads and in particular the AWT-EventQueue thread which calls the paint method."
Now, my question is this:
(Just for fun and to practice Java,) I have created a "launcher" for all the various small programs and games I make. I have yet to get the pong game to work inside the launcher. Without a main method inside the pong frame, the animation never runs. I left the main method in in the code below, so that it works. How would I go about launching the animation from somewhere other than main?
Here's the code:
The Frame and main method:
package pongGame;
import javax.swing.*;
public class PongMainGUI extends JFrame
{
private static final int WINDOW_WIDTH = 500;
private static final int WINDOW_HEIGHT = 800;
private static AnimationPanel panel;
public PongMainGUI()
{
//This line sets the title, and, since it calls the super constructor, it calls setTitle().
super("Pong!");
panel = new AnimationPanel(this);
//This method simply makes the screen appear in the center of whatever size screen you are using.
setLocationRelativeTo(null);
setSize(WINDOW_WIDTH,WINDOW_HEIGHT);
add(panel);
setVisible(true);
}
public static void main(String args[]) throws InterruptedException
{
new PongMainGUI();
while(true)
{
System.out.println("PongMainGUI");
panel.repaint();
panel.move();
Thread.sleep(10);
}
}
}
The Animation Panel:
package pongGame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;
#SuppressWarnings("serial")
public class AnimationPanel extends JPanel
{
PongMainGUI frame;
Ball ballClass;
Racquet racquetClass;
boolean bool = false;
public AnimationPanel(PongMainGUI frame)
{
this.frame = frame;
addMouseListener(new MouseListener()
{
#Override
public void mouseClicked(MouseEvent arg0)
{
}
#Override
public void mouseEntered(MouseEvent arg0)
{
}
#Override
public void mouseExited(MouseEvent arg0)
{
}
#Override
public void mousePressed(MouseEvent arg0)
{
}
#Override
public void mouseReleased(MouseEvent arg0)
{
}
});
addMouseMotionListener(new MouseMotionListener()
{
#Override
public void mouseDragged(MouseEvent e)
{
}
#Override
public void mouseMoved(MouseEvent e)
{
}
});
addKeyListener(new KeyListener()
{
#Override
public void keyPressed(KeyEvent e)
{
racquetClass.keyPressed(e);
}
#Override
public void keyReleased(KeyEvent e)
{
racquetClass.keyReleased(e);
}
#Override
public void keyTyped(KeyEvent e)
{
}
});
//This is needed to ensure that the keyboard will register properly and receive focus.
setFocusable(true);
ballClass = new Ball(this);
racquetClass = new Racquet(this);
}
public void move()
{
//ballClass.moveBall();
racquetClass.moveRacquet();
}
#Override
public void paint(Graphics g)
{
System.out.println("AnimationPanel paint method");
//This method clears the panel so it appears as if the circle is moving.
super.paint(g);
//Better version of Graphics.
Graphics2D g2d = (Graphics2D) g;
//This method turns antialiasing on, which cleans up the corners.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ballClass.paint(g2d);
racquetClass.paint(g2d);
}
public void gameOver()
{
System.out.println("Game over method");
JOptionPane.showMessageDialog(null, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
}
The Ball "sprite":
package pongGame;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball
{
int xCoordinate = 0;
int yCoordinate = 0;
//1 = right movement, -1 = left
int xDirection = 1;
int yDirection = 1;
private final static byte ballWidth = 30;
private final static byte ballHeight = 30;
private AnimationPanel panel;
public Ball(AnimationPanel panel)
{
this.panel = panel;
}
public void paint(Graphics2D g2d)
{
//This creates the actual circle with a specified width and height.
//Because super.paint(g) is called at the start, a new circle is created each time.
g2d.fillOval(xCoordinate, yCoordinate, ballWidth, ballHeight);
System.out.println("Ball paint method");
moveBall();
}
//What this method does is add 1 to the x and y coordinates each time it's called. However, getWidth() and getHeight() are used to determine the current panel size, not the frame size.
//Then, whatever the width and/or height is is subtracted so the circle does not completely disappear from view.
public void moveBall()
{
if (xCoordinate + xDirection < 0)
{
xDirection = 1;
}
else if (xCoordinate + xDirection > panel.getWidth() - ballWidth)
{
xDirection = -1;
}
if (yCoordinate + yDirection < 0)
{
yDirection = 1;
}
else if (yCoordinate + yDirection > panel.getHeight() - ballHeight)
{
System.out.println("Ball moveBall method");
panel.gameOver();
}
if (collision() == true)
{
yDirection = -1;
yCoordinate = panel.racquetClass.getPaddleHeight() - ballHeight;
}
xCoordinate = xCoordinate + xDirection;
yCoordinate = yCoordinate + yDirection;
}
public Rectangle getBounds()
{
return new Rectangle(xCoordinate, yCoordinate, ballWidth, ballHeight);
}
private boolean collision()
{
return panel.racquetClass.getBounds().intersects(getBounds());
}
}
And finally, the Racquet "sprite":
package pongGame;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet
{
private AnimationPanel panel;
private int xCoordinate = 0;
//0 = no movement, 1 is right, -1 is left.
private byte direction = 0;
//All of the following values are in pixels.
private final static byte PADDLE_OFFSET = 100;
private final static byte PADDLE_WIDTH = 120;
private final static byte PADDLE_HEIGHT = 10;
public Racquet(AnimationPanel panel)
{
this.panel = panel;
}
public void moveRacquet()
{
if (xCoordinate + direction > 0 && xCoordinate + direction < panel.getWidth()-60)
xCoordinate = xCoordinate + direction;
}
public void paint(Graphics2D g)
{
g.fillRect(xCoordinate, getPaddleHeight(), PADDLE_WIDTH, PADDLE_HEIGHT);
//move();
}
public void keyReleased(KeyEvent e)
{
direction = 0;
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_LEFT)
direction = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
direction = 1;
}
public Rectangle getBounds()
{
return new Rectangle(xCoordinate, getPaddleHeight(), PADDLE_WIDTH, PADDLE_HEIGHT);
}
public int getPaddleHeight()
{
return panel.getHeight() - PADDLE_OFFSET;
}
}
This may or may not help, but this is the code for the launcher I wanted to use to open the game:
This is the "main menu":
package GUI;
import javax.swing.*;
import painter.MainPainterGUI;
import java.awt.*;
import java.awt.event.*;
/**
* This class serves to create the launcher gui for the program.
* It extends JFrame.
* #author Jackson Murrell
*/
#SuppressWarnings("serial")
public class LauncherGUI extends JFrame implements ActionListener
{
//A couple constants that are used for sizing things.
private final short WINDOW_HEIGHT = 225;
private final short WINDOW_WIDTH = 550;
private final byte BLANK_SPACE = 25;
//Panels to use for adding in components.
JPanel textPanel, buttonPanel, mainPanel;
//Buttons for user input and selection.
JButton calculator, colorChooser, timer, exit, primeNumberTester, game, painter;
//A text label that will be used for giving the user
//instructions on the program.
JLabel textLabel;
//A constructor to create the GUI components when an object of this class is created.
public LauncherGUI()
{
//This call's the parent method's (JFrame) setTitle method.
super("Omni-program");
//These methods set various options for the JFrame.
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLocationRelativeTo(null);
textPanel = new JPanel();
buttonPanel = new JPanel();
mainPanel = new JPanel();
calculator = new JButton("Calculator");
colorChooser = new JButton("Color Chooser");
timer = new JButton("Timer");
primeNumberTester = new JButton("Prime Number Tester");
game = new JButton("Games");
exit = new JButton("Exit Launcher and Programs");
painter = new JButton("Painter");
calculator.addActionListener(this);
colorChooser.addActionListener(this);
timer.addActionListener(this);
exit.addActionListener(this);
primeNumberTester.addActionListener(this);
game.addActionListener(this);
painter.addActionListener(this);
textLabel = new JLabel("Welcome to the launcher! Click the button for the mini-program you would like to run.", 0);
textPanel.add(Box.createVerticalStrut(BLANK_SPACE));
textPanel.add(textLabel);
buttonPanel.add(calculator);
buttonPanel.add(colorChooser);
buttonPanel.add(timer);
buttonPanel.add(primeNumberTester);
buttonPanel.add(game);
buttonPanel.add(painter);
buttonPanel.add(exit);
mainPanel.setLayout(new GridLayout(2,1));
mainPanel.add(textPanel);
mainPanel.add(buttonPanel);
//mainPanel.add(Box.createVerticalStrut(BLANK_SPACE));
add(mainPanel);
//pack();
//Having this line at the end instead of the top ensures that once everything is added it is all set to be visible.
setVisible(true);
}
//This method is required since ActionListener is implemented.
//It will be used to process user input.
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == calculator)
{
new CalculatorGUI();
dispose();
}
else if (e.getSource() == colorChooser)
{
new ColorChooserGUI();
dispose();
}
else if(e.getSource() == timer)
{
new TimerGUI();
dispose();
}
else if (e.getSource() == primeNumberTester)
{
new PrimeNumberTesterGUI();
dispose();
}
else if(e.getSource() == exit)
{
System.exit(0);
}
else if(e.getSource() == painter)
{
new MainPainterGUI();
dispose();
}
else if(e.getSource() == game)
{
new GameLauncherGUI();
dispose();
}
}
}
Here's the actual game launcher:
package GUI;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import pongGame.PongMainGUI;
public class GameLauncherGUI extends JFrame implements ActionListener
{
//A couple constants that are used for sizing things.
private final short WINDOW_HEIGHT = 225;
private final short WINDOW_WIDTH = 550;
private JButton adventureGame, pong, back;
private JLabel label;
private JPanel mainPanel, buttonPanel, textPanel;
public GameLauncherGUI()
{
//This call's the parent method's (JFrame) setTitle method.
super("Omni-program");
//These methods set various options for the JFrame.
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setLocationRelativeTo(null);
adventureGame = new JButton("Adventure Game (Broken)");
adventureGame.addActionListener(this);
pong = new JButton("Pong");
pong.addActionListener(this);
back = new JButton("Back");
back.addActionListener(this);
label = new JLabel("Click the button below for the game you wish to play,\nor click back to go to the previous screen.");
mainPanel = new JPanel();
buttonPanel = new JPanel();
textPanel = new JPanel();
textPanel.add(label);
buttonPanel.add(adventureGame);
buttonPanel.add(pong);
buttonPanel.add(back);
mainPanel.add(textPanel);
mainPanel.add(buttonPanel);
add(mainPanel);
//Having this line at the end instead of the top ensures that once everything is added it is all set to be visible.
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == back)
{
new LauncherGUI();
dispose();
}
else if(e.getSource() == pong)
{
new PongMainGUI();
dispose();
}
}
}
mainis a static method like others, so you can call it from your launcher:
PongMainGUI.main(null); // launch the pong game
However, note that, in order to avoid lots of trouble, Swing components must be created from the Event Dispatch Thread, as shown in this example. So you should wrap the content of your main method inside a Runnable and launch it with SwingUtilities.invokeLater().
However (again), by doing so, your Thread.sleep(10) will run on the EDT, blocking the GUI responsiveness again. Fortunately, Swing thought of that problem and created a utility called javax.swing.Timer that runs tasks periodically on the EDT (without blocking it):
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new PongMainGUI();
Timer timer = new Timer(10, new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("PongMainGUI");
panel.repaint();
panel.move();
}
});
timer.start();
}
});
}
This main() method will run safely in standalone, or from your launcher.
For my assignment, I had to write a program that will either print some text, an oval, or a rectangle depending on which button is pressed at the top of the screen, however; when I press a button nothing happens, how would I fix this? This is my first GUI and I would appreciate any help! I'll end up needing the program to: start out with a rectangle, make whichever shape happens to be on screen stay in the center of the drawing area when the window gets resized, and my ovals and rectangles have to have half the width and height of the display area. I'm taking this one step at a time so I'll try to figure those out once I can actually get a shape on the screen, thanks :-).
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class firstGUI extends JFrame
implements ActionListener
{
private boolean showText = false;
private boolean showRect = false;
private boolean showOval = false;
private JButton text;
private JButton oval;
private JButton rectangle;
private JPanel buttonPanel;
public firstGUI()
{
super("First GUI");
setSize(512, 512);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1,3));
text = new JButton("Text");
text.addActionListener(this);
buttonPanel.add(text);
oval = new JButton("Oval");
oval.addActionListener(this);
buttonPanel.add(oval);
rectangle = new JButton("Rectangle");
rectangle.addActionListener(this);
buttonPanel.add(rectangle);
//JComponent drawArea = new JComponent();
drawStuff d = new drawStuff();
Container contentPane = this.getContentPane();
contentPane.add(buttonPanel, BorderLayout.NORTH);
contentPane.add(d);
}
public void actionPerformed(ActionEvent event)
{
Object source = event.getSource();
if (source == text)
{
showText = true;
}
else if (source == oval)
{
showOval = true;
}
else if (source == rectangle)
{
showRect = true;
}
}
public void draw(Graphics g)
{
if(showText)
{
g.drawString("Hello", 0, 0);
}
else if (showOval)
{
g.drawOval(0, 0, 100, 100);
}
else if (showRect)
{
g.drawRect(0, 0, 100, 100);
}
}
public static void main(String [] args)
{
firstGUI myTest = new firstGUI();
myTest.setVisible(true);
}
}
class drawStuff extends JPanel
{
public void paint(Graphics g)
{
super.paint(g);
}
}
Try this. I added some repaint()s and helped you out with centering the objects being painted. I also changed the draw to paintComponent. This is what you should use when drawing on JComponents
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class firstGUI extends JFrame
implements ActionListener {
private boolean showText = false;
private boolean showRect = true;
private boolean showOval = false;
private JButton text;
private JButton oval;
private JButton rectangle;
private JPanel buttonPanel;
private DrawStuff drawPanel = new DrawStuff();
public firstGUI() {
super("First GUI");
setSize(512, 512);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 3));
text = new JButton("Text");
text.addActionListener(this);
buttonPanel.add(text);
oval = new JButton("Oval");
oval.addActionListener(this);
buttonPanel.add(oval);
rectangle = new JButton("Rectangle");
rectangle.addActionListener(this);
buttonPanel.add(rectangle);
Container contentPane = this.getContentPane();
contentPane.add(buttonPanel, BorderLayout.NORTH);
add(drawPanel);
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == text) {
showText = true;
repaint();
} else if (source == oval) {
showOval = true;
repaint();
} else if (source == rectangle) {
showRect = true;
repaint();
}
}
public static void main(String[] args) {
firstGUI myTest = new firstGUI();
myTest.setVisible(true);
}
class DrawStuff extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (showText) {
g.drawString("Hello", getHeight() / 2, getWidth() / 2);
showText = false;
} else if (showOval) {
g.drawOval(getWidth() / 4, getHeight() / 4, getWidth() / 2, getHeight() / 2);
showOval = false;
} else if (showRect) {
g.drawRect(getWidth() / 4, getHeight() / 4, getWidth() / 2, getHeight() / 2);
showRect = false;
}
}
}
}
You have all the building blocks, but after the button is pressed, the draw() method isn't called. Once you set your state (which item to draw) you need to re-draw()
Take a look at Performing Custom Painting.
Don't override paint but instead use paintComponent.
Take your draw method and move it to your drawStuff class. Call drawStuff from your paintComponent method
Set up some kind of flag (in drawStuff) that determines what should be painted
When you handle the button event, change the state flag on the panel and repaint the panel....
This will require your frame to have a reference to drawStuff
You may also want to take a look at and use Code Conventions for the Java Programming Language