I am new to java GUI, and am trying to learn it. I want to move a circle on screen automatically(i.e not by pressing any key or doing any other action). I found a way to move it by doing some action but thats not what i needed. Please could anybody tell me the simplest way of doing that?
I want to remove the action listener in the following code, so that circles move automatically:
public class MyFirstGraphics extends JFrame {
int x = 100;
int y = 100;
MyFirstGraphics() {
super("Circle");
setSize(800, 800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setBackground(Color.pink);
JButton f = new JButton("circle");
f.addActionListener(new re());
add(f, BorderLayout.NORTH);
}
private class re implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (int i = 1; i < 50; i++) {
x++;
y++;
repaint();
}
}
}
public void paint(Graphics g) {
super.paint(g);
g.drawOval(x, y, 100, 100);
}
public static void main(String[] args) {
MyFirstGraphics l = new MyFirstGraphics();
l.setVisible(true);
}
}
Lets start with the fact that animation is the illusion of change over time. Also, Swing is a single threaded environment. You can't "block" the Swing thread (aka the Event Dispatching Thread) and have it paint updates, you need some way to schedule updates at a regular bases so you can apply a change and then have the change repainted...
So your first problem is in your actionPerformed
method...
for (int i = 1; i < 50; i++) {
x++;
y++;
repaint();
}
Basically, the only thing that will get painted is the ball at 150x150, nothing else in between will be painted.
Instead, you need to change it to something more like...
public void actionPerformed(ActionEvent e) {
if (x < 150 && y < 150) {
x++;
y++;
} else {
((Timer)e.getSource()).stop();
}
repaint();
}
Take a look at:
- Performing Custom Painting
- 2D Graphics
- Concurrency in Swing
- How to Use Swing Timers
For more details
A basic "bouncy" ball example
import java.awt.BorderLayout;
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 BounceyDot {
public static void main(String[] args) {
new BounceyDot();
}
public BounceyDot() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int x = 0;
private int y = 100;
private int radius = 20;
private int xDelta = 2;
public TestPane() {
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
x += xDelta;
if (x + (radius * 2) > getWidth()) {
x = getWidth() - (radius * 2);
xDelta *= -1;
} else if (x < 0) {
x = 0;
xDelta *= -1;
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(x, y - radius, radius * 2, radius * 2);
}
}
}
To animate that code, use a Swing based Timer
with the re
ActionListener
as one argument in the constructor (the other argument is the delay).
See How to Use Swing Timers for details and working examples.