In this simple code example for an animation of a bouncing ball:
import javax.swing.JApplet;
import javax.swing.JFrame;
import java.awt.*;
public class GraphicsMovement extends JApplet
{
public static void pause()
{
try {
Thread.sleep(10);
} catch(InterruptedException e) {
}
}
public static void main(String args[])
{
JApplet example = new GraphicsMovement();
JFrame frame = new JFrame("Movement");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(example);
frame.setSize(new Dimension(500,300)); //Sets the dimensions of panel to appear when run
frame.setVisible(true);
}
public void paint (Graphics page)
{
int width = getWidth(); // width = the width of the panel which appears when run
int height = getHeight(); // height = the height of the panel which appears when run.
//Changes background color to a blueish color
page.setColor(new Color (140,214,225));
page.fillRect(0,0,width,height);
for(int i = 0; i <= 5; i++)
{
for (int j = 0; j <= 100; j++)
{
page.setColor(Color.YELLOW);
page.fillOval(100,55 + j,100,100); //draws a yellow oval
pause();
page.setColor(new Color (140,214,225));
page.fillOval(100,55 + j,100,100); //draws a blueish oval over the yellow oval
}
for (int k = 100; k >= 0; k--)
{
page.setColor(Color.YELLOW);
page.fillOval(100,55 + k,100,100); //draws a yellow oval
pause();
if (k != 0)
{
page.setColor(new Color (140,214,225)); //draws a blueish oval over the yellow oval
page.fillOval(100,55 + k,100,100);
}
}
}
}
}
The animation is drawn fine and runs on a Windows machine (using JCreator), but will not run on Mac OS X compiled with either IntelliJ or Eclipse. Tried on two different OS X machines, and both will draw the ball and background (after a long wait) but will not proceed with the animation.
Is there some sort of platform-specific code in here that I am missing?
Thanks!
Never do anything in any paint
method that would either block or might trigger a repaint request.
You should always call super.paintXxx
, these methods do a lot of work in the background, usually a lot better then you can.
You shouldn't need to (very rare cases) extend from top level containers, like JApplet
or JFrame
. You are better of creating a custom container (such as JPanel
) and add your components to it (or perform your custom painting). Apart from the double buffering support, you also gain flexibility in deployment choices.
Don't kid yourself, you don't control the paint process, it's up to the repaint manager to make those decisions, you can however, "encourage" it to update. This causes the most pain when people start playing with animation.
You should modify the "state" of the animation outside of the influence of the Event Dispatching Thread (EDT) or in your case, out side the paint
context.
You problem is simple enough that a simple javax.swing.Timer
will solve it. More complex animations might require a "animation" thread.
public class GraphicsMovement extends JApplet {
@Override
public void init() {
setLayout(new BorderLayout());
add(new AnimatedPane());
}
@Override
public void start() {
}
public class AnimatedPane extends JPanel {
private Timer timer;
private boolean colorSwitch = false;
private int yOffset = 0;
private int direction = 1;
public AnimatedPane() {
timer = new Timer(10, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// colorSwitch = !colorSwitch;
yOffset += direction;
if (yOffset > 100) {
direction = -1;
yOffset = 100;
} else if (yOffset < 0){
direction = 1;
yOffset = 0;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
setBackground(new Color(140, 214, 225));
}
@Override
protected void paintComponent(Graphics page) {
super.paintComponent(page);
int width = getWidth(); // width = the width of the panel which appears when run
int height = getHeight(); // height = the height of the panel which appears when run.
if (colorSwitch) {
page.setColor(new Color(140, 214, 225));
} else {
page.setColor(Color.YELLOW);
}
page.fillOval(100, 55 + yOffset, 100, 100); //draws a yellow oval
}
}
}
I'm concerned with the "delay" of 10 milliseconds, it's enough to want me to face a fit :P
You might find reading through...
- Concurrency
- Concurrency in Swing
- How to Use Swing Timers
- Performing Custom Painting
- Painting in AWT and Swing
Of some interest
paint()
method is called in the UI thread, and it should return as fast as possible.
So where will you put the animation code then?The answer is simple: you will need to put the code into a separate thread.
For the difference between Windows and OS X, all I can say is that it should be related on how they schedule threads, or something like that.