Question

I need a way to wait until a (Swing) JComponent is fully painted. This actual problem arises from an openmap application: The task is to draw a map (mapBean) with a couple of layers and create an image from that map.

Unfortunatly, and it's clearly documented, the image formatter takes the current state from the map to create the picture, and there's a chance, especially when maps become complex, that the formatter ist called before the mapBean, a JComponent, is painted.

Although explained with this openmap application, the problem is quite general and supposedly Swing related. Right now, I just wait a fixed time (one second) but that does not eliminate the risk of creating incomplete maps...

Edit

Some more details - I have to start with constructing a (OpenMap) MapPanel, which internallz creates a MapBean (JComponent subclass) and a MapHandler. Then I feed the MapHandler with geographical Layers and the Framework starts painting the geographical data 'on' the JComponent type MapBean.

After adding all layers to the Map, I use another framework class to create a JPG image (or: the byte[] that holds the image data). And this can cause problem, if I don't wait: this 'image creator' creates the image from the current state of the map bean, and if I call this 'image creator' to early, some map layers are not painted and missing. Pretty annoying...

Was it helpful?

Solution

java.awt.EventQueue.invokeLater will allow you to run a task after the paint operation has finished. If it is doing some kind of asynchronous load, then it will be API specific (as MediaTracker does for Image).

OTHER TIPS

You might also try using an off screen buffer to render your image in:

 MapBean map = new MapBean();
 map.setData(...);

 BufferedImage bi = new BufferedImage(...);
 map.paintComponent(bi.getGraphics());

 writeToFile(bi);

It sounds like you need to synchronize updating your JComponent's underlying data with Swing's paint cycle. You can subclass your JComponent and decorate the paintComponent() method, you might also look at ImageObserver.imageUpdate(), though I'm not sure if that is going to tell you what you want.

public class DrawingCycleAwareComponent extends MyOtherJComponent {

    private final Object m_synchLock = new Object();

    protected void paintComponent(Graphics g) {
        synchronized (m_synchLock) {
            super.paintComponent(g);
        }
    }

    protected void updateData(Object data) {
        if (SwingUtilities.isEventDispatchThread()) {
            reallySetMyData(data);  // don't deadlock yourself if running in swing
        }
        else {
            synchronized (m_synchLock) {
                reallySetMyData(data);
            }
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top