Results 1 to 10 of 10
  1. #1
    JCollier is offline Member
    Join Date
    Aug 2008
    Location
    Boston
    Posts
    11
    Rep Power
    0

    Default Swing Basics Round 2

    I'm having a issue with the structure of my code. I have a class that creates a JFrame, 2 classes that create JPanels (which are added to the JFrame), 1 class that creates a Ball object to be drawn on one of the JPanels. My issue is that I have a timer associated with one of the JPanels that is controlled by buttons on the other JPanel. As of now I have a static timer, however, when I perform the action to redraw the ball on the JPanel, I can't make a call to the non-static paint method using repaint(). Can someone give advice of a better way to structure my code. I'm including all files in code snippets below. I apologize for the fact that portions are not fully implemented.

    Java Code:
    public class Pong {
    	public Pong() {
    		GameWindow window = new GameWindow();		
    		window.loadGame();
    	}
    	
    	public static void main(String[] args) {
    		new Pong();
    	}
    }
    Java Code:
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Graphics;
    
    import javax.swing.JFrame;
    
    
    public class GameWindow extends JFrame {
    	
    	// Default Serial Version UID
    	private static final long serialVersionUID = 1L;
    
    	private static Dimension currentWindowSize = Preferences.MEDIUM_WINDOW_SIZE;
    	
    	public GameWindow() {
    		this(Preferences.MEDIUM_WINDOW_SIZE);
    	}
    
    	public GameWindow(Dimension windowSize) {
    		setTitle("Bouncing Balls");
    		setSize(windowSize);
    		setVisible(true);
    		setResizable(false);
    		setDefaultCloseOperation(EXIT_ON_CLOSE);
    	}
    	
    	public static Dimension getCurrentWindowSize() {
    		return currentWindowSize;
    	}
    	
    	public void setWindowSize(Dimension newWindowSize) {
    		this.setSize(newWindowSize);
    		currentWindowSize = newWindowSize;
    	}
    	
    	void loadGame() {
    		GameControlPanel gameControlPanel = new GameControlPanel();
    		GamePanel gamePanel = new GamePanel();
    		Ball ball = new Ball();
    		
    		gamePanel.addBall(ball);
    		
    		this.setLayout(new BorderLayout());
    		this.add(gameControlPanel, BorderLayout.NORTH);
    		this.add(gamePanel, BorderLayout.CENTER);
    		
    		repaint();
    	}
    	
    	public void paint(Graphics g) {
    		super.paintComponents(g);
    	}
    }
    Java Code:
    import java.awt.Color;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JPanel;
    
    public class GameControlPanel extends JPanel {
    
    	// Default Serial Version UID
    	private static final long serialVersionUID = 1L;
    
    	public GameControlPanel() {
    		this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    		
    		JButton startButton = new JButton("Start");
    		JButton stopButton = new JButton("Stop");
    		
    		startButton.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				GamePanel.startMovement();
    			}			
    		});
    		
    		stopButton.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				GamePanel.stopMovement();
    			}
    		});
    		
    		this.setLayout(new FlowLayout());
    		this.add(startButton);
    		this.add(stopButton);
    	}
    }
    Java Code:
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    public class GamePanel extends JPanel {
    
    	// Default Serial Version UID
    	private static final long serialVersionUID = 1L;
    	
    	private static ArrayList<Ball> gameBalls = new ArrayList<Ball>();
    
    	private static int timerInterval = 100;
    	
    	private static Timer timer = new Timer(timerInterval, new ActionListener() {
    		public void actionPerformed(ActionEvent e) {
    			for (int i = 0; i < gameBalls.size(); i++) {
    				gameBalls.get(i).move();
    			}
    		}
    		
    		repaint(); // PROBLEMATIC CODE
    	});
    	
    	public GamePanel() {		
    	}
    	
    	void addBall(Ball ball) {
    		gameBalls.add(ball);
    		
    		repaint();
    	}
    	
    	public static void startMovement() {
    		timer.start();
    	}
    	
    	public static void stopMovement() {
    		timer.stop();
    	}
    	
    	public void paint(Graphics g) {
    		super.paintComponent(g);
    		
    		for (int i = 0; i < gameBalls.size(); i++) {
    			Ball currentBall = gameBalls.get(i);
    			g.fillOval(currentBall.getXCoordinate(), currentBall.getYCoordinate(), currentBall.getWidth(), currentBall.getHeight());
    		}
    	}
    }
    Java Code:
    import java.util.Random;
    
    public class Ball extends Thread {
    
    	private int width = Preferences.BALL_WIDTH;
    	private int height = Preferences.BALL_HEIGHT;
    	private int xCoordinate;
    	private int yCoordinate;
    	private int maximumXCoordinate = GameWindow.getCurrentWindowSize().width - width;
    	private int maximumYCoordinate = GameWindow.getCurrentWindowSize().height - height;
    	
    	private int xDirection;
    	private int yDirection;
    	
    	private static int LEFT = -1;
    	private static int RIGHT = 1;
    	private static int UP = -1;
    	private static int DOWN = 1;
    	
    	
    	private static int movementInterval = 2;
    	
    	public Ball() {	
    		xCoordinate = getStartingXCoordinate();
    		yCoordinate = getStartingYCoordinate();
    		
    		if (this.getXCoordinate() > maximumXCoordinate / 2)
    			this.xDirection = LEFT;
    		else
    			this.xDirection = RIGHT;
    		
    		if (this.getYCoordinate() > maximumYCoordinate / 2)
    			this.yDirection = UP;
    		else
    			this.yDirection = DOWN;
    	}
    	
    	public int getWidth() {
    		return width;
    	}
    	
    	public void setWidth(int width) {
    		this.width = width;
    	}
    	
    	public int getHeight() {
    		return height;
    	}
    	
    	public void setHeight(int height) {
    		this.height = height;
    	}
    	
    	public int getXCoordinate() {
    		return xCoordinate;
    	}
    	
    	public void setXCoordinate(int xCoordinate) {
    		this.xCoordinate = xCoordinate;
    	}
    	
    	public int getYCoordinate() {
    		return yCoordinate;
    	}
    	
    	public void setYCoordinate(int yCoordinate) {
    		this.yCoordinate = yCoordinate;
    	}
    	
    	public static int getMovementInterval() {
    		return movementInterval;
    	}
    	
    	public void setMovementInterval(int newMovementInterval) {
    		movementInterval = newMovementInterval;
    	}
    	
    	private int getStartingXCoordinate() {
    		Random randomGenerator = new Random();
    		return randomGenerator.nextInt(maximumXCoordinate);
    	}
    	
    	private int getStartingYCoordinate() {
    		Random randomGenerator = new Random();
    		return randomGenerator.nextInt(maximumYCoordinate);
    	}
    	
    	void move() {
    		if (this.xDirection == RIGHT) {
    			if (this.xCoordinate + movementInterval > maximumXCoordinate) {
    				this.xCoordinate = maximumXCoordinate;
    				this.xDirection = LEFT;
    			}
    		} else if (this.xDirection == LEFT) {
    			if (this.xCoordinate - movementInterval < 0) {
    				this.xCoordinate = 0;
    				this.xDirection = RIGHT;
    			}
    		}
    		
    		if (this.yDirection == DOWN) {
    			if (this.yCoordinate + movementInterval > maximumYCoordinate) {
    				this.yCoordinate = maximumYCoordinate;
    				this.yDirection = UP;
    			}
    		} else if (this.yDirection == UP) {
    			if (this.yCoordinate - movementInterval < 0) {
    				this.yCoordinate = 0;
    				this.yDirection = DOWN;
    			}
    		}
    	}
    }
    Java Code:
    import java.awt.Color;
    import java.awt.Dimension;
    
    public class Preferences {
    	
    	final static Dimension SMALL_WINDOW_SIZE = new Dimension(400, 500);
    	final static Dimension MEDIUM_WINDOW_SIZE = new Dimension(600, 800);
    	final static Dimension LARGE_WINDOW_SIZE = new Dimension(800, 1200);
    	
    	Boolean isFullScreen = new Boolean(false);
    	
    	final static int BALL_WIDTH = 30;
    	final static int BALL_HEIGHT = 30;
    	final static Color BALL_COLOR = Color.BLACK;
    	
    	final static int DEFAULT_GAME_SPEED = 5;
    	
    //	final static int DEFAULT_POINTS_TO_WIN = 10;
    }
    I'm trying to become a better coder, so any advice regarding my code, even if it doesn't pertain to the immediate question would be appreciated (I'm looking for a better structure of my classes, etc.). Thanks in advance for any help.

  2. #2
    JCollier is offline Member
    Join Date
    Aug 2008
    Location
    Boston
    Posts
    11
    Rep Power
    0

    Default

    I added the repaint() with the comment // PROBLEMATIC CODE to show where the problem was. This is incorrectly placed, and should be directly after the for loop in the actionPerformed method.

  3. #3
    JCollier is offline Member
    Join Date
    Aug 2008
    Location
    Boston
    Posts
    11
    Rep Power
    0

    Default

    I've added the amended code below. I still haven't had any responses to this post, and input would be greatly appreciated.

    Java Code:
    	private static Timer timer = new Timer(timerInterval, new ActionListener() {
    		public void actionPerformed(ActionEvent e) {
    			for (int i = 0; i < gameBalls.size(); i++) {
    				gameBalls.get(i).move();
    			}
    
    			repaint(); // PROBLEMATIC CODE
    		}
    	});

  4. #4
    KevinWorkman's Avatar
    KevinWorkman is offline Crazy Cat Lady
    Join Date
    Oct 2010
    Location
    Washington, DC
    Posts
    3,879
    Rep Power
    8

    Default

    You probably haven't received a response yet because nobody likes reading through that much code (an SSCCE is much better), plus it's only been a few hours, plus oftentimes people don't look at posts that already have responses.

    But why make the Timer static in the first place?
    How to Ask Questions the Smart Way
    Static Void Games - Play indie games, learn from game tutorials and source code, upload your own games!

  5. #5
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Agree. I think that you are abusing the static modifier and have thus painted yourself in a corner. The only thing that should be static in your code are your static final constants and the main method. Anything else you will need to fully justify it to us. I strongly suspect that fixing this problem with fix your code problem.

  6. #6
    JCollier is offline Member
    Join Date
    Aug 2008
    Location
    Boston
    Posts
    11
    Rep Power
    0

    Default

    Quote Originally Posted by KevinWorkman View Post
    You probably haven't received a response yet because nobody likes reading through that much code (an SSCCE is much better), plus it's only been a few hours, plus oftentimes people don't look at posts that already have responses.

    But why make the Timer static in the first place?
    I can completely understand not wanting to sift through this much code, and I was struggling with the idea of putting only snippets and having parts of the functionality be obfuscated.

    I have the following Constructs:

    a JFrame which contains 2 JPanels. One JPanel has a start and a stop button to control movement of a ball that's drawn in the second JPanel. The issue is that the JPanel that draws the ball has the paint method which will be used via repaint() to redraw the ball in its new position whenever movement happens (movement is controlled by a timer that turns on and off based on the start and stop buttons on the other JPanel). The panel with the two buttons makes a static call to the panel that draws the ball, as it doesn't have access to a particular instance. Since the call is static, the methods that control movement in the ball-drawing JPanel must be static, and as such, their reference to timer object force it to be static as well. The problem is inside the class defined anonymously in the timer object that handles what happens every "tick". Because the timer is static, I can't make a call to the non-static repaint() method for the ball drawing JPanel, and as such, I can't display the "movement" of the ball. I hope that wasn't too convoluted an explanation, I tend to over-do it sometimes.

    Thanks,
    Jared

  7. #7
    JCollier is offline Member
    Join Date
    Aug 2008
    Location
    Boston
    Posts
    11
    Rep Power
    0

    Default

    I won't have time to work on this until Sunday, however, I'll do what I can to remove static methods at that time, and post again if I'm still running into issues. Thanks for your help.

    Jared

  8. #8
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default

    Quote Originally Posted by JCollier View Post
    ...The problem is inside the class defined anonymously in the timer object that handles what happens every "tick". Because the timer is static, I can't make a call to the non-static repaint() method for the ball drawing JPanel, and as such, I can't display the "movement" of the ball. I hope that wasn't too convoluted an explanation, I tend to over-do it sometimes.
    Yes, your problem is that by using statics inappropriately you are running into trouble when you try to use non-static code. . Again, get rid of everything static except constants and the main method, everything. This will fix the problem.

  9. #9
    JCollier is offline Member
    Join Date
    Aug 2008
    Location
    Boston
    Posts
    11
    Rep Power
    0

    Default

    So a quick overview of what I'm planning is as follows (and thanks for all your help):

    Create a JFrame
    Create a timer object in the JFrame
    Create a JPanel with buttons that control movement of the ball in another JPanel and pass in my timer object as a parameter. Via the reference to this object, it can control the actual Timer object that's passed in.
    Create a JPanel that displays the ball
    Add the Ball object to the second JPanel, and add both JPanels to the JFrame
    Implement the action method in the JFrame which fires on each "tick" of my timer, and will be able to call repaint() in the JPanel that draws the ball image.

    In this way I won't need any static methods except main, would you modify this process or does it look like the appropriate way to handle restructuring of the above code?

  10. #10
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

Similar Threads

  1. Swing Basics
    By JCollier in forum New To Java
    Replies: 5
    Last Post: 01-21-2011, 06:59 AM
  2. going round and round in class..
    By sonny in forum New To Java
    Replies: 52
    Last Post: 04-02-2010, 10:56 AM
  3. About swing basics
    By harithaspa in forum AWT / Swing
    Replies: 2
    Last Post: 12-13-2008, 12:07 PM
  4. How to round a double?
    By Valeriano in forum New To Java
    Replies: 1
    Last Post: 05-31-2007, 03:50 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •