I think my title pretty well sums up my problem. I'm really new to programming (about 2-3 weeks of self teaching using Head First Java) and I am trying to use Action Listener to make a square move back and forth on screen until the user terminates the program. My issue is that I have one Timer and 2 classes implementing Action Listener. I can get it to run back and forth once, but that's all I can get it to do.
package Animation;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Window extends JPanel implements ActionListener{
int x = 100;
Timer timer = new Timer(5, this);
int velX = 2;
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.BLACK);
g.setColor(Color.BLUE);
g.fill3DRect(x, 150, 200, 200, true);
timer.start();
if(x >= 1000){
timer.addActionListener(new HandlerClass());
}//end if
}//end paintComponent
public void actionPerformed(ActionEvent e){
x += velX;
repaint();
}//end actionP method
public class HandlerClass implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(x >= 100){
x -= velX;
repaint();
}
}//end actionP
}//end Handler
}//end Window
I've seen questions where people use buttons to move things back and forth or move things a set number of times, but I want the timer to do everything till the user exits. That way the user only has to watch. I Didn't include the class with my main method because that just sets up the gui and calls this class.
First, take a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing.
Basically, Swing uses a passive rendering algorithm, this means that a paint cycle may occur at any time for any reason, most of the time without your direct intervention.
You should never change the state of a component from within any paint method, paint methods should paint, that's it.
There are a number of small problems, to start with, you are adding the Window
class AND the HandlerClass
as ActionListener
's to the Timer
, this means that you could potentially get into a position where these two listeners compete with each other over which way the object should move. Better to place your movement logic into a single method, for example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Window extends JPanel {
int x = 100;
Timer timer = new Timer(5, new HandlerClass());
int velX = 2;
public Window() {
this.setBackground(Color.BLACK);
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fill3DRect(x, 150, 200, 200, true);
}//end paintComponent
public class HandlerClass implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
x += velX;
if (x + 200 >= getWidth()) {
x = getWidth() - 200;
velX *= -1;
} else if (x < 0) {
x = 0;
velX *= -1;
}
repaint();
}//end actionP
}//end Handler
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Window());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}//end Window
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.