I have a small GUI java program I'm working on but designing how the pieces should work together is frustrating me. Basically what I need to do is draw a "car" on a panel and attach that panel to a frame. Then animate the panel to give the illusion of movement.
My problem is that I don't understand how to move the code that does the animation to its own class开发者_运维问答. When I started working on this I made the UI elements first. Then I came across the Timer class and used that class in what was supposed to be just a UI element class (CarBody). The way my code works now is that as soon as I run the program the "car" starts moving because I don't have it set up to be triggered by a button press. I don't understand how to move the animation code to its on class and trigger it with a button press.
I could solve this in two seconds IF I could call repaint() in the performAction() method. The problem is I can't do that! It wont compile that way.
What I have done is
class CarBody extends JPanel {
private int xCoordinate = 0;
CarBody(){
Timer timer = new Timer(1000,new TimerListener());
timer.start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
//g.fillRect(10, 10, 60, 50);
if(xCoordinate > getWidth()){
xCoordinate = -20;
}
xCoordinate +=100;
g.fillRect(xCoordinate,10,60,50);
}
class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
repaint();
}
}
}
I could solve this in two seconds IF I could call repaint() in the performAction() method.
You should not be changing the car coordinates in the paintComponent() method. You should have a method that sets the coordinates and then repaints the car.
When you create the ActionListener class then pass in the panel you want to repaint as a parameter to the class. Then you can invoke the "changeLocation" method which will update the location of the car and then invoke repaint() on itself.
For another approach you can add an Icon to a label and just change the location of the label and it will repaint itself automatically. Here is a simple example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerAnimation extends JLabel implements ActionListener
{
int deltaX = 2;
int deltaY = 3;
int directionX = 1;
int directionY = 1;
public TimerAnimation(
int startX, int startY,
int deltaX, int deltaY,
int directionX, int directionY,
int delay)
{
this.deltaX = deltaX;
this.deltaY = deltaY;
this.directionX = directionX;
this.directionY = directionY;
setIcon( new ImageIcon("dukewavered.gif") );
// setIcon( new ImageIcon("copy16.gif") );
setSize( getPreferredSize() );
setLocation(startX, startY);
new javax.swing.Timer(delay, this).start();
}
public void actionPerformed(ActionEvent e)
{
Container parent = getParent();
// Determine next X position
int nextX = getLocation().x + (deltaX * directionX);
if (nextX < 0)
{
nextX = 0;
directionX *= -1;
}
if ( nextX + getSize().width > parent.getSize().width)
{
nextX = parent.getSize().width - getSize().width;
directionX *= -1;
}
// Determine next Y position
int nextY = getLocation().y + (deltaY * directionY);
if (nextY < 0)
{
nextY = 0;
directionY *= -1;
}
if ( nextY + getSize().height > parent.getSize().height)
{
nextY = parent.getSize().height - getSize().height;
directionY *= -1;
}
// Move the label
setLocation(nextX, nextY);
}
public static void main(String[] args)
{
JPanel panel = new JPanel();
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().setLayout(null);
// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
frame.getContentPane().add( new TimerAnimation(300, 100, 3, 2, -1, 1, 20) );
// frame.getContentPane().add( new TimerAnimation(0, 000, 5, 0, 1, 1, 20) );
frame.getContentPane().add( new TimerAnimation(0, 200, 5, 0, 1, 1, 80) );
frame.setSize(400, 400);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
// frame.getContentPane().add( new TimerAnimation(10, 10, 3, 0, 1, 1, 10) );
}
}
This example, doesn't do custom painting and the animation is done by invoking the setlocation(...) method on the label which will cause a repaint() so the solution is slightly different than yours, but the key point is NOT to change the location values in the paintComponent() method.
精彩评论