Come aspettare fino JComponent è completamente dipinta?
Domanda
Ho bisogno di un modo di aspettare fino a quando un (Swing) JComponent è completamente dipinta. Questo problema reale deriva da un'applicazione openmap:. Il compito è quello di disegnare una mappa (mapBean) con un paio di strati e di creare un'immagine da quella mappa
Purtroppo, ed è chiaramente documentato, il formattatore immagine assume lo stato attuale dalla mappa per creare l'immagine, e c'è una possibilità, soprattutto quando le mappe diventano complesse, che l'IST formattatore chiamato prima della mapBean, un JComponent, è dipinto .
Anche se spiegato con questa applicazione openmap, il problema è del tutto generale e presumibilmente swing correlate. In questo momento, ho solo aspettare un tempo fisso (un secondo), ma che non elimina il rischio di creare mappe incomplete ...
Modifica
Alcuni dettagli - devo iniziare con la costruzione di un (OpenMap) MapPanel, che crea un internallz MapBean (JComponent sottoclasse) e una MapHandler. Poi mi nutro la MapHandler con i livelli geografici e il quadro inizia a dipingere i dati geografici 'on' il tipo JComponent MapBean.
Dopo aver aggiunto tutti i livelli alla mappa, io uso un'altra classe framework per creare un'immagine JPG (o: il byte [] che contiene i dati di immagine). E questo può causare problemi, se non mi aspetto: questo 'immagine creatore' crea l'immagine dallo stato attuale della mappa di fagioli, e se io chiamo questo 'immagine creatore' ai primi, un po ' i livelli della mappa non sono dipinte e dispersi. Piuttosto fastidioso ...
Soluzione
java.awt.EventQueue.invokeLater
vi permetterà di eseguire un compito dopo l'operazione di disegno è terminato. Se si sta facendo qualche tipo di carico asincrono, allora sarà specifico API (come MediaTracker
fa per Image
).
Altri suggerimenti
Si potrebbe anche provare a utilizzare un buffer schermo spento per rendere la vostra immagine in:
MapBean map = new MapBean();
map.setData(...);
BufferedImage bi = new BufferedImage(...);
map.paintComponent(bi.getGraphics());
writeToFile(bi);
Sembra che tu abbia bisogno di sincronizzare l'aggiornamento dei dati sottostanti del JComponent con ciclo di verniciatura di Swing. È possibile creare una sottoclasse tua JComponent e decorare il metodo paintComponent()
, si potrebbe anche guardare ImageObserver.imageUpdate()
, anche se non sono sicuro se che sta per dirti quello che vuoi.
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);
}
}
}
}