简体   繁体   中英

New to java can't figure out how to use paint method

I am trying to learn the paint method and get a ball to move across the frame. here is my code so far. w=.

I currently have two classes One is the main and one for the ball.

this is the main class import java.awt. ; import javax.swing. ;

public class PaintTest extends JPanel {
int x = 0;
int y = 0;

public void moveBall(){
    x = x + 1;
    y = y + 1;
}
public static void main(String[] args){
    JFrame frame = new JFrame();
    frame.setSize(500,500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    Ball ball = new Ball(x,y);

    while(true){
        ball.moveBall();
        repaint();
    }
    }
protected void paintComponent(Graphics g){
    super.paintComponent(g);

    Graphics2D g2 = (Graphics2D) g;

    g.setColor(Color.magenta);
    g.drawLine(0,100,500,100);
    g.drawLine(0,101,500,101);
    g.drawLine(0,102,500,102);
    g.drawLine(0,103,500,103);

    g2.fillOval(x,y,35,35);
}
}

and here is the ball class

 public class Ball {

   int x,y;

   public Ball(int x, int y){
this.x = x;
this.y = y;
}
}

now when i compile I get an error saying cannot find symbol ball in class PaintTest even though I am calling it from the class Ball. I am aware of the repaint error as i do not know what to put in front of it.

  1. Draw in a JPanel
  2. In its paintComponent method not in its paint method -- this gives you double buffering.
  3. Call the super's paintComponent method in your override. This allows the JPanel to do housekeeping drawing including erasing the oval image at its old position.
  4. Don't use a while (true) loop as this can cause serious Swing threading issues. Use a Swing Timer instead.
  5. In the Swing Timer, increment your animation variables and then call repaint() . This will tell Swing to repaint the component which will re-draw the oval in the new location.
  6. Don't guess at this stuff as that leads to frustration since Swing graphics coding is a different beast. Instead check the tutorials. You can find links to the Swing tutorials and to other Swing resources here: Swing Info . Also check out Performing Custom Painting with Swing .
  7. Graphics2D goodies: RenderingHints can be used to smooth out your image jaggies.
  8. More Graphics2D goodies: Stroke can be used to draw thicker lines when needed.

For example:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class PaintTest extends JPanel {
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private static final int TIMER_DELAY = 20;
   private static final Stroke STROKE = new BasicStroke(5f);
   private int x;
   private int y;

   public PaintTest() {
      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;

      // to smooth graphics
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

      g2.setColor(Color.magenta);
      Stroke initialStroke = g2.getStroke();
      g2.setStroke(STROKE);
      g.drawLine(0, 100, 500, 100);
      g2.setStroke(initialStroke);

      g2.fillOval(x, y, 35, 35);
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         x++;
         y++;
         repaint();
      }
   }

   private static void createAndShowGui() {
      PaintTest mainPanel = new PaintTest();

      JFrame frame = new JFrame("PaintTest");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

You have to put the paintComponent method in a JPanel. You can do it by using something like this.

JPanel panel = new JPanel(){

    @Overide
    public void paintComponent(Graphics g){
        super.paint();
        // Draw Stuff Here

    }

};

The reason you are not getting the ball to move across the frame is that you are not calling the repaint method. You should do so on a thread.

Thread th = new Thread(new Runnable(){
    @Overide
    public void run(){
        while(frame.isVisible()){
            ball.moveBall();     
            panel.repaint();
            try{Thread.sleep(5);}catch(Exception e){e.printStackTrace();}
        }
    }
});

Also, why are you making ball a instance of the PaintTest class? To get only one frame and ball you would want to add a class named Ball and use that to make an instance:

public class Ball{

    int x, y;

    public Ball(int x, int y){
        this.x = x;
        this.y = y;
    }
} 

That is why you were getting 2 frames.

Then you would want to get rid of the x and y variables in the main class. To make an instance using this class you would do:

Ball ball = new Ball(x, y);

Then to paint the ball in the paintComponent method you would do:

g.fillOval(ball.x, ball.y, 35, 35);
  • You didn't call the repaint(); method.
  • You don't need the y + 1 part.
  • Instead of using the while(true) loop, you should use a for loop.
  • You didn't call the super.paint() method.
  • You didn't use any Thread.sleep() , which made the ball move across instantaneously.

Here is the code:

import java.awt.*;
import javax.swing.*;

public class PaintTest extends JFrame {
int x = 8;
int y = 30;

public void moveBall(){
x = x + 1;
//y = y + 1;
try{
    Thread.sleep(500);
} catch(InterruptedException e){

}
repaint();
}
public static void main(String[] args){
PaintTest frame1 = new PaintTest();
PaintTest ball = new PaintTest();

for(int i = 0; i<100; i++){
//while(true){
    ball.moveBall();
}
}

public PaintTest() {
super("Paint Test");
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


setVisible(true);
}

public void paint(Graphics g){

Graphics2D g2 = (Graphics2D) g;
super.paint(g);
super.paint(g2);
g.setColor(Color.magenta);
g.drawLine(0,100,500,100);
g.drawLine(0,101,500,101);
g.drawLine(0,102,500,102);
g.drawLine(0,103,500,103);

g.fillOval(x,y,35,35);
}
}

This code will make the ball move across the screen VERY slowly. If you want to speed it up, change the number of miliseconds in the Thread.sleep(miliseconds) part to a smaller number of miliseconds.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM