I am working on a concurrent canvas written in Java which will make the users think that they are drawing on the canvas in parallel.
In order to achieve the user perceived parallelism, I get them to create these Runnable objects that I go ahead and put on the EventQueue using SwingUtilities.invokeLater().
In order to test it, I simulated the users using a couple of Threads and added a bit of delay(around 50ms) between each call to invokeLater(), in order to see if it actually looks like the drawing is happening in parallel.
The problem is that while it worked fine with that added delay between the invokeLater() calls, taking out that delay results in the drawings being drawn properly sometimes, partially being drawn and vanishing sometimes and just not being drawn at other times.
I am pretty stumped about what could be going wrong so any if anyone has any ideas, please let me know.
Following is the code with the delay commented out:
public void run(){
//add tasks on to the event queue of the EDT
for(int i = 0; i<numLines; i++){
DrawLineTask task = new DrawLineTask(g, x1, y1+i, x2, y2+i, lineColor);
SwingUtilities.invokeLater(task);
// try {
// Thread.sleep(new Double(Math.random()*50).longValue());//random sleeping times to make it appear more realistic
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
Cheers
EDIT: Here is the code for the DrawLineTask as requested. Its pretty simple as its just an extension of the Runnable class that draws a line using the standard Java function at the given parameters.
public class DrawLineTask implements Runnable {
Graphics g;
int x1 = 0;
int y1 = 0;
int x2 = 0;
int y2 = 0;
Color color = Color.BLACK;
public DrawLineTask(Graphics g, int x1, int y1, int x2, int y2){
this.g = g;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public DrawLineTask(Graphics g, int x1, int y1, int x2, int y2, Color color){
this.g = g;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.color = color;
}
@Override
public void run() {
g.setColor(color);
g.drawLine(x1, y1, x2, y2);
}
}
AFAIK, you're not supposed to keep a reference to a Graphics object and draw on it when you want to. Instead, you're supposed to wait for the
paintComponent()
method to be called by Swing, and do your drawings in this method.So, your task should just change the state of your component, and ask for an asynchronous or synchronous repaint (using
repaint()
orpaintImmediately()
). Swing will then invoke thepaintComponent()
method with a Graphics object that you can use to paint the appropriate lines, based on the state of your component.See http://java.sun.com/products/jfc/tsc/articles/painting/ for more details and explanations.