6

I cannot seem to force a layout in Swing. I have a JComponent added to a JLayeredPane and I set a border on the JComponent. Then, I want to immediately re-draw everything - not in the sense of "please do this asap" like invalidate(), but synchronously and immediately. Any help? I cannot seem to find the right method of doing this, and all my reading about invalidate(), validate(), repaint(), doLayout(), etc is just confusing me more!

nwalke
  • 3,170
  • 6
  • 35
  • 60
Hamy
  • 20,662
  • 15
  • 74
  • 102

3 Answers3

2

According to this (see the section titled "Synchronous Painting") the paintImmediately() method should work.

bobndrew
  • 395
  • 10
  • 32
Jonathan
  • 3,203
  • 2
  • 23
  • 25
  • 1
    I have tried this - myComponent.paintImmediately(myComponent.getBounds). No luck :( I think this may be because changing the border requires a new layout pass due to the border using some extra pixels on each side of the object – Hamy Jan 21 '11 at 17:27
  • paintImmediately may be the way to go, but you still need to post it as an event using invokeLater or invokeAndWait, I think. – phooji Jan 21 '11 at 17:36
  • @Hamy Have you tried calling it on the parent component, that might allow for the layout change. – Jonathan Jan 21 '11 at 19:11
1

The most reliable way to get Swing to update a display is to use SwingUtilities.invokeLater. In your case, it would look something like

SwingUtilities.invokeLater(new Runnable {
                             public void run() { 
                                somecomponent.repaint();
                             }
                           });

I realize the 'invokelater' does not exactly sound like it does anything immediate, but in practice, events posted in this way tend execute pretty quickly compared to just calling e.g. somecomponent.repaint() directly. If you absolutely must make your control code wait for the GUI to update, then there is also invokeAndWait, but my experience is that this is rarely necessary.

See also: document on event dispatch in Swing.

phooji
  • 10,086
  • 2
  • 38
  • 45
  • Unfortunately neither of those will work for my impl :/ I need the GUI update to happen immediately, not after the pending events have been processed. It's due to a flaw in my design that I need it this way, but unfortunately changing it would set me back almost two weeks and I have a deliverable tomorrow :/ – Hamy Jan 21 '11 at 17:28
  • Ok try this: use invokeAndWait, then inside the runnable call paintImmediately on the outer container. I think this is as close as you can get using Swing -- it will override previous calls to 'repaint,' if I'm not mistaken. – phooji Jan 21 '11 at 17:35
  • Unfortunately that didn't work either. To call invokeAndWait you have to spawn a new Thread. I have a *very* slow event happening immediately after this painting, and it begins execution before the runnable is started, resulting in the GUI freezing without this paint call having been performed yet – Hamy Jan 21 '11 at 20:58
  • 1
    The invokeAndWait call does not spawn a new thread -- it just adds your Runnable to the event queue, and then *blocks your current thread* until the event is called. If you're still not seeing the 'change' when using invokeAndWait, then you're most likely repainting the wrong object. One way to check is to add debug output to your component's (g)paint method. – phooji Jan 21 '11 at 21:24
0

This is super old, but I found a simple solution, which I'll show with a JPasswordField:

var pw = new JPasswordField();
...
pw.paint(pw.getGraphics()); // paints immediately
looncraz
  • 1
  • 1
  • 2