I am working on a Java program that uses a JApplet which makes a ball bounce up and down. I am able to paint the shape onto the JApplet and everything like that. I just can't seem to get it to move. I have looked into this and saw that I need to create a method that pauses the shape then clears it from the JApplet, changes coordinates, and then redraws the shape in the new area but for some reason it's just not working for me.
Thank you in advance for the help.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
public class Circle extends JApplet {
int x=100;
int y=100;
int diameter=50;
public void paint(Graphics g) {
int xResize=500;
int yResize=500;
super.paint(g);
resize(xResize,yResize);
g.drawOval(x, y, diameter, diameter);
}
public Circle (int startX, int startY,int startDiameter) {
this.x=startX;
this.y=startY;
this.diameter=startDiameter;
}
public int getX() {
return x;
}
public void setX(int startX){
x=startX;
}
public int getY() {
return y;
}
public void setY(int startY){
y=startY;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int startDiameter){
diameter=startDiameter;
}
while (ball.getY() + ballDiameter < windowHeight) {
g.clearRect(x-1,100,20,20);
g.fillOval(x,100,20,20);
try
{
Thread.sleep(70);
}
catch(Exception e)
{
}
pause.wait(0.05);
//g.clearRect(0,0,windowWidth,windowHeight);
g.clearRect(x-1,100,20,20);
g.fillOval(x,100,20,20);
try
{
Thread.sleep(70);
}
catch(Exception e)
{
}
ball.setY( ball.getY()+spacer);
}
while (ball.getY() + ballDiameter > 0) {
g.clearRect(x-1,100,20,20);
g.fillOval(x,100,20,20);
try
{
Thread.sleep(70);
}
catch(Exception e)
{
}
pause.wait(0.05);
//g.clearRect(0,0, windowWidth, windowHeight);
ball.setY(ball.getY()-spacer);
}
Bouncing Ball Class:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
public class BouncingBall extends JApplet {
public void paint(Graphics g) {
super.paint(g);
final int x = 0;
int y = 0;
final int diameter = 15;
final int spacer = 5;
int windowWidth = getWidth();
int windowHeight = getHeight();
Circle ball = new Circle(x, y, diameter);
Pause pause = new Pause();
int ballDiameter = ball.getDiameter();
int roof = getHeight();
Firstly, animation is the illusion of change over time. So first, you need some way to update your values on a regular bases.
Secondly, Swing is a single threaded framework, this means that anything that blocks this thread will stop the Event Dispatching Thread from process new events, including repaint requests.
Thirdly, all interactions, changes or updates to the UI are expected to be executed from within the context of the EDT.
This means, you need some way to wait in the background (off the EDT), which can notify you when it's time to perform an update and have those updates synched back to the EDT.
javax.swing.Timer
is a perfect candidate for this purpose. It can wait in the background for a specified period of time; It will notify theActionListener
within the context of the EDT when the time period expires and it can repeat.Start by overriding the
init
,start
andstop
methods of theJApplet
Basically, this constructs a
Timer
, starts and stops it appropriately.Next, we need to supply some logic for the animation...
As I said before, animation is the illusion of movement over time. We have the time part taken care of (more or less), now we need the movement.
The basic idea is to apply a small amount of change to the current value and provide boundary checking and finally repaint the result.
Here, I've declared
delta
as instance variable within the applet and set it's value to2
. This logic should be added to theactionPerformed
method of theActionListener
registered with theTimer
To get this to run, you will need to remove your constructor, as applets should must have a default/empty constructor.
You should also remove the
resize
call from thepaint
method, as this is just going to cause more repaint requests to be issued, which will eventually consume your CPU.When you run it, you might get lucky and see the circle, occasionally (or it will flicker). This is because top level containers in Swing aren't double buffered. Now, you could implement your own buffering strategy, but Swing components are double buffered by default...
To fix this, we can create a simple
DrawPanel
that extends from aJPanel
and override it'spaintComponent
methodSo you could end up with something more like...
Also, be careful when overriding methods, the
getX
andgetY
methods have very special meanings, you could cripple your application by overrding them...I'd also question the need to use
JApplet
, it would be better to simply start with using aJFrame
which is significantly easier to get working properly.Take a look at Concurrency in Swing and How to use Swing Timers for more details