Results 1 to 6 of 6
Like Tree1Likes
  • 1 Post By DarrylBurke

Thread: Animating a moving ball - repainting one component

  1. #1
    Zyril is offline Senior Member
    Join Date
    Oct 2011
    Location
    Sweden
    Posts
    124
    Rep Power
    0

    Default Animating a moving ball - repainting one component

    Hello!

    Time for me to start a thread about a problem that I've run into. The course I'm taking is at the moment focusing on graphics and drawing components with Java. Personally, I couldn't find this less interesting, but nonetheless I'll just have to deal with it and do it.

    I'm trying to create a program in which a ball bounces around inside a JPanel. My layout is a GridBagLayout where I've placed two buttons and a JPanel inside a first JPanel. The buttons are to alter the speed of the ball movement.

    When running the code, it appears as if the "repaint()" method repaints the whole JPanel in which the ball is moving. This is, when I'm thinking of it, quite logic, but not what I want it to do. Of course, I only want to repaint the ball inside the panel, not repaint the panel inside the panel itself.

    This is what it looks like when I'm commenting out the repaint()-method.

    Animating a moving ball - repainting one component-8upic.jpg

    When the repaint()-method is called:

    Animating a moving ball - repainting one component-rd5lq.jpg

    The code that I'm using:

    BallDemo.java
    Nothing is wrong here, though to compile this is needed. This creates a new object of the BallPanel class.
    Java Code:
    import java.awt.Color;
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.UIManager;
    import javax.swing.UIManager.LookAndFeelInfo;
    import javax.swing.border.EmptyBorder;
    import java.awt.GridBagLayout;
    import java.awt.GridBagConstraints;
    import javax.swing.JButton;
    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    
    public class BallDemo extends JFrame {
    
    	private static final long serialVersionUID = 1L;
    	private JPanel contentPane;
    
    	/**
    	 * Launch the application.
    	 */
    	public static void main(String[] args) {
    		EventQueue.invokeLater(new Runnable() {
    			public void run() {
    				try {
    				    for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
    				        if ("Nimbus".equals(info.getName())) {
    				            UIManager.setLookAndFeel(info.getClassName());
    				            break;
    				        }
    				    }
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    				try {
    					BallDemo frame = new BallDemo();
    					frame.setTitle("BallDemo!");
    					frame.setVisible(true);
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		});
    	}
    
    	/**
    	 * Create the frame.
    	 */
    	public BallDemo() {
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		setBounds(100, 100, 800, 600);
    		contentPane = new JPanel();
    		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    		setContentPane(contentPane);
    		GridBagLayout gbl_contentPane = new GridBagLayout();
    		gbl_contentPane.columnWidths = new int[]{0, 0};
    		gbl_contentPane.rowHeights = new int[]{0, 0, 0, 0, 0};
    		gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE};
    		gbl_contentPane.rowWeights = new double[]{1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
    		contentPane.setLayout(gbl_contentPane);
    		
    		
    		//Create the panel on which to draw
    		BallPanel panelCanvas = new BallPanel();
    		GridBagConstraints gbc = new GridBagConstraints();
    		gbc.gridheight = 2;
    		gbc.gridwidth = 2;
    		gbc.insets = new Insets(0, 0, 5, 0);
    		gbc.fill = GridBagConstraints.BOTH;
    		gbc.gridx = 0;
    		gbc.gridy = 0;
    		contentPane.add(panelCanvas, gbc);
    		panelCanvas.setBackground(Color.GRAY);
    		
    		//Controller button for speed change (decrease)
    		JButton decrButton = new JButton("Decrease speed");
    		gbc.gridx = 0;
    		gbc.gridy = 3;
    		gbc.weightx = 0.5;
    		gbc.gridwidth = 2;
    		contentPane.add(decrButton, gbc);
    		
    		decrButton.addActionListener(new ActionListener(){
    			public void actionPerformed(ActionEvent e) {
    				// TODO add code here for decreasing speed
    			}
    		});
    		
    		//Controller button for speed change (increase)
    		JButton incrButton = new JButton("Increase speed");
    		gbc.gridx = 0;
    		gbc.gridy = 1;
    		gbc.weightx = 0.5;
    		contentPane.add(incrButton, gbc);
    		
    		incrButton.addActionListener(new ActionListener(){
    			public void actionPerformed(ActionEvent e) {
    				// TODO add code here for increasings speed
    			}
    		});
    		
    	}
    
    }
    BallPanel.java
    This is where repaint()-method is called within the ActionListener to the timer that sets the update interval for the animation.
    Java Code:
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BorderFactory;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    
    
    public class BallPanel extends JPanel{
    	
    	private Ball ball = new Ball(1, 1);
    	private int animationUpdater = 40;
    	private Timer timer;
    
    	
    	/**
    	 * Constructor for BallPanel that is the canvas where the ball is moving.
    	 */
    	public BallPanel(){
    		 setBorder(BorderFactory.createLineBorder(Color.BLACK));
    		 timer = new Timer(animationUpdater, performer);
    		 timer.start();
    	}
    	
    	public void paintComponent(Graphics g){
    		g.setColor(Color.GREEN);
    		ball.draw(g);
    	}
    	
    	/**
    	 * ActionListener that runs accordingly to timer.
    	 */
    	private ActionListener performer = new ActionListener(){
    		public void actionPerformed(ActionEvent arg0) {
    			ball.setBounds(getWidth(), getHeight());
    			ball.animate();
    			repaint();
    		}
    	};
    }
    Ball.java
    This is the code for the ball itself.
    Java Code:
    import java.awt.Graphics;
    
    
    
    /**
     * Class for a Ball object that is moved inside a JPanel.
     * When constructor called, creates a Ball with random diameter somewhere between 15 and 45 pixels.
     *
     */
    public class Ball {
    	
    	int d = 25;
    	int rightBorder;
    	int topBorder;
    	private int x;
    	private int y;
    	private int speedX = 3;
    	private int speedY = 3;
    	
    	/**
    	 * Constructor for Ball object.
    	 * @param x
    	 * @param y
    	 */
    	public Ball(int x, int y){
    		this.x = x;
    		this.y = y;
    	}
    	
    	
        /**
         * Draw method for Ball object.
         * @param g
         */
        public void draw(Graphics g){
        	System.out.println(x);
            g.fillOval(x, y, d, d);
        }
        
        /**
         * Define the boundaries of the area that the ball is moving within.
         * @param width Width of ball
         * @param height
         */
        public void setBounds(int width, int height){
            rightBorder  = width  - d;
            topBorder = height - d;
        }
        
        
        /**
         * Method for animating the movement of the ball.
         */
        public void animate(){
        	
        	//Set the new location of the coordinates.
            x += speedX;
            y += speedY;        
            
            //Check if the X-coordinate is at the left side of the panel, set to zero and then reverse direction.
            if (x < 0){
            	
                x = 0;          		  
                x = -speedX;
                
            //Check if X-coordinate is at the right side of panel, reverse direction.
            }else if(x > rightBorder){ 
    	        x = rightBorder;    
    	        x = -speedX;  
    	    }
          
            //Check the same for the Y-coordinates.
            if (y < 0){
                y = 0;
                y = -speedY;
            }else if(y > topBorder){
    	        y = topBorder;
    	        y = -speedY;
    	    }
        }
    
        
    //	public int getX() {
    //		return x;
    //	}
    //
    //
    //	public void setX(int x) {
    //		this.x = x;
    //	}
    }
    So, what could be my problem?
    When looking at program while running, or just the second picture above, one sees that there are many several balls that together form a line. Why isn't the ball repainted? It appears as if it's being drawn all over again and leaving previous ball(s) in place.

    Also, you can see that the borderline of the panel BallPanel is duplicated to the left in the second pic. This suggest to me that the whole panel is being redrawn, though perhaps only one time? (Otherwise more borderlines would appear?)

    And finally, one of the buttons appear in the top when the repaint()-method is called. It is not click-able, though it's highlighted when the bottom button is highlighted, and it also changes to the other button when you hover the mouse over the other bottom button.

    I'm grateful for any thoughts and tips!

    On a more off topic question, what is the general view of importance of graphics in Java? I have no plans on becoming a game developer or anything close to graphics designer, so why would I (sorry for the harsh words) waste my time learning to do this? Of course I am interested in coding GUI's, but I don't see this as very close to that.

    Thank you,
    Z!

    EDIT:
    I changed the code of the Ball class so it looks like this:

    Java Code:
    	private int speedX = 26;
    	private int speedY = 26;
    This show that I was correct about the idea that repaint()-method draws a new ball and leaves the old one. I get several balls instead of one long green line.
    Last edited by Zyril; 09-04-2012 at 08:03 PM.

  2. #2
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,453
    Rep Power
    25

    Default Re: Animating a moving ball - repainting one component

    The streaked green strip looks like a history of where the ball has been. If you clear the screen by calling the super.paintComponent() method, the history will be erased before the new ball is drawn.
    If you don't understand my response, don't ignore it, ask a question.

  3. #3
    Zyril is offline Senior Member
    Join Date
    Oct 2011
    Location
    Sweden
    Posts
    124
    Rep Power
    0

    Default Re: Animating a moving ball - repainting one component

    That did the trick, thank you Norm!

    So, let me see if I understand this correctly.

    I'm overriding the JComponents paintmethod with my own paintComponent(), and if I then want to clear the background area where I'm painting, I have to call the parentclass paintComponent()..?

    Following, should super.paintComponent() always be called, or are there are scenarios when you can omit this?

    The visual artifacts I had when I didn't call super.paintComponent(), were they there because I didn't draw the entire background?

  4. #4
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,453
    Rep Power
    25

    Default Re: Animating a moving ball - repainting one component

    Most of the time you should call the super method. I don't know when not to.
    If you don't understand my response, don't ignore it, ask a question.

  5. #5
    DarrylBurke's Avatar
    DarrylBurke is offline Member
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,244
    Rep Power
    19

    Default Re: Animating a moving ball - repainting one component

    Quote Originally Posted by Zyril View Post
    should super.paintComponent() always be called, or are there are scenarios when you can omit this?
    If your custom painting code addresses every pixel of the component's client area, you can safely omit the call to the super implementation. An example could be
    Java Code:
    g.drawImage(0, 0, getWidth(), getHeight(), this);
    Another example could be when you paint a gradient or tiled background scaled to the size of the component.

    But. Whenever I write such code, I leave a commented-out call to the super implementation to remind me or anyone else who reads the code that the omission was intentional. I find that more effective than a comment to the same effect.
    Java Code:
      @Override
      protected void paintComponent(Graphics g) {
        // super.paintComponent(g);
        ... other painting code ..
      }
    db
    Zyril likes this.
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  6. #6
    Zyril is offline Senior Member
    Join Date
    Oct 2011
    Location
    Sweden
    Posts
    124
    Rep Power
    0

    Default Re: Animating a moving ball - repainting one component

    Thank you guys!

    Darryl, that was very informative! =)

Similar Threads

  1. Ball moving across the screen?
    By Slicknife in forum New To Java
    Replies: 1
    Last Post: 05-29-2012, 11:53 PM
  2. Moving a ball
    By jsmasand in forum Java 2D
    Replies: 5
    Last Post: 04-27-2012, 03:34 AM
  3. Ball Move to mouse not animating.
    By Jossos in forum New To Java
    Replies: 6
    Last Post: 01-05-2012, 01:42 PM
  4. Ball not moving
    By Eleeist in forum New To Java
    Replies: 7
    Last Post: 01-04-2012, 11:27 PM
  5. Moving a ball with Arrow Keys
    By kekcklemen in forum Java Applets
    Replies: 5
    Last Post: 02-25-2011, 10:15 PM

Posting Permissions

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