Synchronous painting - Issue

Hello there!

I'm confused...

Its about a kind of real-time view, were first the current values are calculated and then shown. It is necessary, that the current values are painted synchronously, because otherwise it is possible, that partially old and partially new values are shown (that's why a simple repaint()

is not useable).

I'm using a Observer/Observable Pattern, were the Observable is a thread, which generates the impulses when to calculate the new values and to paint them. The first observer is the "calculator" and the second is the JFrame, where these values are shown.

Here the code of the JFrame(Observer) update method, which is called regulary:

publicvoid update(Observable o, Object arg){

this.getJMenuBar().paintImmediately(0,0, this.getJMenuBar().getWidth(), this.getJMenuBar().getHeight());

panel1.paintImmediately(0,0,panel1.getWidth(),panel1.getHeight());

panel2.paintImmediately(0,0,panel2.getWidth(),panel2.getHeight());

panel3.paintImmediately(0,0,panel3.getWidth(),panel3.getHeight());

}

I'm pretty sure that this is not the right way to synchonously update my JFrame, but honestly I don't know the right one.

A side-effect of this approach is, that the view is flickering and not displayed correct.

What would you suggest? Would you approach this issue in a different way?

Please help!

Many thanks in advance!

PS:

I also read about this invokeAndWait

but I didn't understand...

[1657 byte] By [schorschi6a] at [2007-11-27 10:00:25]
# 1

> I'm confused...

Me to, I don't understand why repaint() won't work.

You get updated data, perform calculations and then invoke repaint() and the entire panel gets repainted. Using the newly calculated values.

If your calculations take a long time then they should be executed in a separate thread so you don't prevent the GUI from repainting itself.

camickra at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 2

It doesn't work. I tried it. When i use repaint in the update method and the time-diff between the last call is too small, paint isn't called immediately. It then happens, that paint is called DURING the calculation of the new values. So i have partially new and partially old values shown. Perhaps you should know, that the calculated values are some kind of "global variables".

I'm now thinking of using a synchronized

statement, but I don't know exactly how...

But I'm open for new ideas!

How would you approach this?

Message was edited by:

schorschi6

schorschi6a at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 3

I have no idea what your update routine is doing. Maybe you create a buffered image and draw the updates on the buffered image. Then your panel simply paints the last buffered image available.

If you need further help then you need to create a "Short, Self Contained, Compilable and Executable, Example Program (SSCCE)",

see http://homepage1.nifty.com/algafield/sscce.html,

that demonstrates the incorrect behaviour, because I can't guess exactly what you are doing based on the information provided.

Don't forget to use the "Code Formatting Tags",

see http://forum.java.sun.com/help.jspa?sec=formatting,

so the posted code retains its original formatting.

camickra at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 4

I tried to write some abstract code, to clarify the problem. It's NOT runnable.

StartUp.java:

public class StartUp extends Thread{

Simulator sim;

SimulatorFrame simFrame;

public StartUp(Simulator sim, SimulatorFrame simFrame){

this.sim = sim;

this.simFrame = simFrame;

}

public void run(){

while(true){

sim.calcluate_A_Lot_Of_Stuff_And_Update_Data();

// this repaint takes longer than 100 ms

// especially the paintComponent() of the VeryBulkyPanel takes LONG

simFrame.repaint();

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public static void main(String[] args){

BulkyDatastructure data = new BulkyDatastructure();

Simulator sim = new Simulator(data);

SimulatorFrame simFrame = new SimulatorFrame(data);

StartUp startUp = new StartUp(sim, simFrame);

startUp.start();

}

}

Simulator.java:

public class Simulator {

private BulkyDatastructure data;

public Simulator(BulkyDatastructure data){

this.data = data;

}

public void calcluate_A_Lot_Of_Stuff_And_Update_Data(){

// here is "this.data" updated

}

}

SimulatorFrame.java

public class SimulatorFrame extends JFrame{

private BulkyDatastructure data;

private JPanel veryBulkyPanel;

private JPanel notSoImportantPanel;

public SimulatorFrame(BulkyDatastructure data){

this.data = data;

veryBulkyPanel = new VeryBulkyPanel(data);

notSoImportantPanel= new NotSoImportantPanel(data);

this.getContentPane().add(veryBulkyPanel);

this.getContentPane().add(notSoImportantPanel);

}

}

VeryBulkyPanel.java

public class VeryBulkyPanel extends JPanel{

private BulkyDatastructure data;

public VeryBulkyPanel(BulkyDatastructure data){

this.data = data;

}

protected void paintComponent(Graphics g){

// here "this.data" is painted

// it's very much data with images and stuff

// so it takes some time

}

}

In principle this is all I'm tryiing to do. I hope you unterstand now. I think the problem is the non-blocking/asynchronous behavior of repaint().

When the (re-)paint() lasts longer than the 100ms of sleep we have the problem, that we paint values that are partially new and partially old ( sim.calcluate_A_Lot_Of_Stuff_And_Update_Data()

is executed again, although repaint isn't finished yet!)

schorschi6a at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 5

You can solve your problem with a technique called double buffering. Try googling for some tutorials or examples.

Essentially you keep two BufferedImage's around (called A and B). First paintComponent(Graphics) is overridden to only copy A onto the screen. So basically if you want something to appear on the screen it has to be drawn into BufferedImage A.

When your data changes, then you draw the new image onto B. When that is done, copy B- > A, then call repaint(). That way you never get some old + some new data showing, its always only new data. Also, double buffering is fast!

jvaudrya at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 6

Do you think this would solve the problem?

I think the inconsistent data would be painted in the buffered image as well as on screen. By the way: isn't the JPanel by default double buffered?

I know how a un-double-buffered animation looks like. That is not the case.

I think the problem is, that the repaint() takes too long and is overrun by the next sim.calcluate_A_Lot_Of_Stuff_And_Update_Data()

. If I set the sleep-time of the thread higher, e.g. on 500 ms, I have no inconsistent data (but a chopped animation instead).

The best way I can imagine is still a "synchronous repaint()" of the JFrame (SimulatorFrame). But I don't know how to do this correctly...

Furthermore I think, that the general problem is the concurrent access on the data

that's why I also thought of using "synchronized", but I also don't know how exactly.

Please help!

schorschi6a at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 7

Hello again!

Still have the problem...

I read, that the repaint() of an AWT-Frame is synchronous. Can I use my JPanels in the AWT-Frame without side-effects? How is then the repaint() of the JPanels called? Synchronously, too? I would convert my JPanels to AWT-Panels, but I'm using transparency and stuff which isn't possible in Panels.

Suggestions? Opinions?

PLZ help!

schorschi6a at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 8

If you have a problem that it takes 200ms to paint the panel but you want to repaint it every 100ms, then that obviously can't be done.

So the problem is in your painting. If you can't post a simple SSCCE showing what you are attempting to do then we can't really help. There are all kinds of animation examples and refreshing examples in the forum that don't have a problem.

camickra at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...
# 9

Ok, thanks. I'll try to do a SSCCE. But I don't do any "strange" things in my code (at least in my opinion :-) ).

I don't necessarily want to repaint every 200ms. I want to repaint as fast as I can.

But when the repaint doesn't block the execution of the residual code, I get the inconsistencies.

Maybe I make some error in reasoning.

I'll take a look at the tutorials. It is a kind of "game loop" that I'm trying to do, right?

schorschi6a at 2007-7-13 0:31:44 > top of Java-index,Desktop,Core GUI APIs...