Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 2 of 2

Thread: Help with simple "bouncing" ball Swing application

  1. #1
    Member
    Join Date
    May 2011
    Posts
    61
    My Mood
    Busy
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Help with simple "bouncing" ball Swing application

    Hi, I'm trying to build simple bounching ball (eventually), so I thought I'd start with unrealistic bouncing so balls goes from top to bottom of returns back to the top in a loop. So currently the ball moves vertically in increments of 10 (the ball height), and the animation works but the question I have is I wanted a JFrame height of 180, but I noticed that the blue border (or whatever color border) in the Swing JFrame window that opens is actually part of the JFrame's height so I had to have my if statement indicate if ball_y (y distance travelled so far) to not go past windows' height (JFrame's height) to 140px which I played around to get it to otherwise the ball goes past the Swing window. So shouldn't the height be not including the border of the JFrame? I also tried moving just horizontally and I set JFrame height and width to be same: 180px but I noticed for looping the animation, it's 160px before it reaches right side of JFrame window, why the discrepancy?

    import java.awt.Color;
    import java.awt.event.ActionListener;
    import java.awt.event.ActionEvent;
    import java.awt.*;//other stuff like layout managers
    import javax.swing.Timer;
    import javax.swing.*;
     
    public class Ball_Animation_v0 extends JFrame
    {
     
    	private static final long serialVersionUID = 1L;//Q: what is this?//look up (I just let IDE add a default for me)
    	private int ball_x = 0;//cur x component of where ball is 
    	private int ball_y = 0;//cur y component of where ball is 
    	private int ball_width = 10;//(move in increments of 10px) (b/c 10 is a factor of JFrame ht: 180) 
    	private int ball_height = 10;//(move in increments of 10px)
    	private int window_width = 180;//width of JFrame (for version 2, I can't set this b/c I want the JFrame ht to be resizable)
    	private int window_height = 180;//height of JFrame (for ver 2, I can't set this b/c I want JFrame width to be resizable)
    	private int delay = 120;
    	private Canvas aCanvas;
    	private boolean is_reached_bottom = false;
     
    	public Ball_Animation_v0()
    	{
    		this.setSize(window_width, window_height);
    		this.setVisible(true);
    		this.setResizable(false);
    		aCanvas = new Canvas();
    		this.add(aCanvas);
     
    		//the Timer is listener to determine when to update position of ball
    		Timer t = new Timer(delay, new ActionListener(){
     
    			public void actionPerformed(ActionEvent e)
    			{
    				change_position();
    				repaint();
    			}
     
    		});
     
    		t.start();
    	}
     
    	//make sure to go back up when ball encounters the JFrame edge
    	private void change_position()//update position of ball
    	{
    		//System.out.println("cur ball_y: " + ball_y);
     
    		if ( ball_y == 0 )
    			is_reached_bottom = false;//reset
     
    		if ( ball_y < 140 && !is_reached_bottom )//the blue border also part of JFrame...so I can't use 180
    			ball_y = ball_y + ball_height;
    		else//keep moving back towards ceiling until you're at ceiling of JFrame
    		{
    			is_reached_bottom = true;
    			ball_y = ball_y - ball_height;	
    		}
    	}
     
     
    	private class Canvas extends JPanel//lightweight component (=> it doesn't have its own window by accessing native OS's window creation)
    	{
    		public void paintComponent(Graphics g)
    		{	
    			super.paintComponent(g);//need this b/c of something to do w/ UI delegates...need to look up to refresh
    			Graphics2D g2d = (Graphics2D)g;
     
    			g2d.setColor(Color.red);
    			g2d.fillOval(ball_x, ball_y, ball_width, ball_height);
     
    		}
    	}
     
    	public static void main(String[] args)
    	{
    		new Ball_Animation_v0();
    	}
    }

    Also, I read it's important to not have to repaint the entire graphics but just update where the animation needs updated, so I tried using parameter repaint method, but then when I run program, the red ball stays stuck at starting position, any help appreciated.

    here is what I mean (this is constructor from above program)
    public Ball_Animation_v0()
    	{
    		this.setSize(window_width, window_height);
    		this.setVisible(true);
    		this.setResizable(false);
    		aCanvas = new Canvas();
    		this.add(aCanvas);
     
    		//the Timer is listener to determine when to update position of ball
    		Timer t = new Timer(delay, new ActionListener(){
     
    			public void actionPerformed(ActionEvent e)
    			{
    				change_position();
    				repaint(ball_x, ball_y, ball_width, ball_height);//Problem here: why can't I use parameter repaint to 
                                     // just update the actually ball and not repaint entire items in canvas? (because red ball just shows
                                     //  up at starting position
    			}
     
    		});
     
    		t.start();
    	}
     
    private void change_position()//update position of ball
    	{
    		//System.out.println("cur ball_y: " + ball_y);
     
    		if ( ball_y == 0 )
    			is_reached_bottom = false;//reset
     
    		if ( ball_y < 140 && !is_reached_bottom )//the blue border also part of JFrame...so I can't use 180
    			ball_y = ball_y + ball_height;
    		else//keep moving back towards ceiling until you're at ceiling of JFrame
    		{
    			is_reached_bottom = true;
    			ball_y = ball_y - ball_height;	
    		}
    	}


    --- Update ---

    Ok, I decided to draw inside the Canvas canvas and the now the red ball animation seems *almost* fine, but it's just when it reaches bottom, it still goes slightly off screen (out of view from JFrame window), any help appreciated.

    Updated program
    import javax.swing.*;//Timer here
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.*;
    import javax.swing.SwingUtilities;
     
    public class Ball_Animation_v0_1 extends JFrame
    {
    	private static final long serialVersionUID = 1L;//Q: what is this?//look up (I just let IDE add a default for me)
    	private int ball_x = 0;//cur x component of where ball is 
    	private int ball_y = 0;//cur y component of where ball is 
    	private int ball_width = 10;//(move in increments of 10px) (b/c 10 is a factor of JFrame ht: 180) 
    	private int ball_height = 10;//(move in increments of 10px)
    	private int canvas_width = 180;
    	private int canvas_height = 180;
    	private int delay = 120;
    //	private Canvas aCanvas;
    	private boolean is_reached_bottom = false;
    	private boolean is_reached_right_side = false;
     
    	public Ball_Animation_v0_1()
    	{
    		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //		this.setSize(window_width, window_height);		
    		this.setVisible(true);
    		this.setResizable(false);
    		this.add(new Canvas() );
    		this.pack();
     
    		//the Timer is listener to determine when to update position of ball
    		Timer t = new Timer(delay, new ActionListener(){
     
    			public void actionPerformed(ActionEvent e)
    			{
    				change_position();
    				repaint(/**ball_x, ball_y, ball_width, ball_height*/);//how do I only redraw necessary updates and not entire graphics for the red ball?
    			}
     
    		});
     
    		t.start();
    	}
     
    	//Drawing inside Canvas BUT when it reaches bottom, red ball still slight goes off screen...
    	public void change_position()
    	{
    		if ( ball_x == 0 && ball_y == 0 )
    		{
    			is_reached_bottom = false;//reset
    			is_reached_right_side = false;//reset
    		}
     
    		if ( !is_reached_bottom && !is_reached_right_side && ball_y < canvas_height && ball_x < canvas_width )//move forward
    		{
    			ball_x = ball_x + ball_width;
    			ball_y = ball_y + ball_height;
     
    		}
    		else//move backwards
    		{
    			is_reached_bottom = true;
    			is_reached_right_side = true;
    			ball_x = ball_x - ball_width;
    			ball_y = ball_y - ball_height;
    		}
    	}
     
    	//REMEMBER: a lightwt container can also have its own layout manager
    	private class Canvas extends JPanel//eg of named inner class
    	{
    		public Canvas() {
    	        setBorder(BorderFactory.createLineBorder(Color.black));
    	    }
     
    	    public Dimension getPreferredSize() {//overridden method
    	        return new Dimension(180,180);
    	    }
     
    		public void paintComponent(Graphics g)
    		{
    			super.paintComponent(g);
    			Graphics2D g2d = (Graphics2D)g;
     
    			g.setColor(Color.RED);
    			g.fillOval(ball_x, ball_y, ball_width, ball_height);
     
    		}
     
    	}
     
    	//Q: what does invokeLater mean? (look up)
    	public static void main(String[] args) {
    		SwingUtilities.invokeLater(new Runnable() {//anonymous inner class (used to ensure Swing/GUI/Event-handling run in EDT
    			// as this will prevent potential race conditions that could lead to deadlock.
                public void run() {
                    new Ball_Animation_v0_1();
                }
            });
     
    	}
     
    }


  2. #2
    Super Moderator helloworld922's Avatar
    Join Date
    Jun 2009
    Posts
    2,895
    Thanks
    23
    Thanked 619 Times in 561 Posts
    Blog Entries
    18

    Default Re: Help with simple "bouncing" ball Swing application

    fillOval Javadoc

    The fillOval method takes the x/y coordinates from the top-left corner, so you're checking the wrong "corner" of the ball for collision with the bottom right corner.

    The problem you're running into with repainting I believe has to deal with overriding the JFrame class. The default implementation of the customized repaint method doesn't repaint child components, so your canvas never gets repainted. JFrame is the actual Window frame, and generally you don't extend this. Instead, I extend the JPanel class since this is the actual component I want to modify painting for. This component can then be added to a standard JFrame.

    Oh, and with repainting only a specific area you need to make sure the old ball gets erased first. You can either use 2 repaint calls (one to erase the old ball and one to draw the new one), or just use a larger repaint area which will cover the location of the old ball as well as the new ball.

Similar Threads

  1. What's the difference between "import.javax.swing*" and JFrame inheritance
    By Johnny Bravo in forum Object Oriented Programming
    Replies: 5
    Last Post: August 14th, 2012, 09:28 AM
  2. Replies: 3
    Last Post: December 7th, 2011, 02:03 AM
  3. Java tip Sep 22, 2010 - "Screenshots" of swing components
    By helloworld922 in forum Java Swing Tutorials
    Replies: 3
    Last Post: June 6th, 2011, 01:25 AM
  4. Java tip Sep 22, 2010 - "Screenshots" of swing components
    By helloworld922 in forum Java Code Snippets and Tutorials
    Replies: 3
    Last Post: June 6th, 2011, 01:25 AM
  5. "showMessageDialog" method in swing package
    By Delmi in forum Java Theory & Questions
    Replies: 1
    Last Post: May 13th, 2010, 02:52 PM