My goal is to draw a rectangle and move it smoothly from left to right, using Observer pattern.
I have a Model class, which is the Observable where I put the coordinates of the rectangle, and a Display class which is the Observer and perform repaint each time the coordinates change in the Model.
The coordinates changes in the Model are made in a while loop inside a SwingWorker : at each iteration I increment the x coordinate by one, then sleep for 100 ms, then notify the Observer (the Display) which only task is to perform a repaint. As you see the repaint() method is called on the EDT like it is adviced to do.
The problem is that the move isn't smooth after about one second, the repaint frequency change and it seems that the rectangle is less and less repainted.
Here is the Model class :
import java.util.Observable;
import java.awt.EventQueue;
import javax.swing.SwingWorker;
public class Model extends Observable{
int xCoordinate;
Model(Display d){
SwingWorker<Void,Void> sw = new SwingWorker<Void,Void>(){
@Override
protected Void doInBackground() {
while(xCoordinate<600){
xCoordinate ++;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {}
setChanged();
notifyObservers(xCoordinate);
}
return null;
}
};
addObserver(d);
sw.execute();
}
public static void main(String[] a){
EventQueue.invokeLater(new Runnable(){
@Override
public void run(){
Display d = new Display();
Model m = new Model(d);
d.model = m;
}
});
}
}
And here is the Display class :
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display extends JFrame implements Observer{
Model model;
int xCoordinate;
Display(){
getContentPane().add(new JPanel(){
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(xCoordinate, 1, 50, 50);
}
});
setSize(600, 600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
/* arg is the updated xCoordinate*/
public void update(Observable o, Object arg) {
xCoordinate = (Integer)arg;
EventQueue.invokeLater(new Runnable(){
@Override
public void run() {
repaint();
}
});
}
}
I tried other methods, for instance using Timer in the Display, but that didn't work either. The SwingWorker maybe isn't useful here because calculations made on the SwingWorker thread are easy (increment by one) but I will need it for the heavy calculations I intend to do on my project (a pool game).
I also tried debugging by looking at time between two repaints (in Display) and time between two incrementations (in Model) and it was as expected about 100 ms each.
Thanks in advance