1

When I modify a component in a component tree of any depth, the modifications usually show automatically, immediately, without need for me to take any action to that end.

Not so when the modification is an addition of a new child.
Furthermore, if I want to force the repaint using any of the methods appropriate (as far as I understand the API), this has no tangible effect as well.

Only when a new modification to the existing tree - including the added, but still invisible component - is made, does the added child appear.

Here is an example, that will render a black window with an "Add" button at the bottom. Clicking the button will have no effect. Resizing or minimising the window will cause as many white "XX" strings to appear, as the button has been pressed beforehand.

I would, of course, very much like to have the additions appear immediately one by one, whenever the button is pressed.

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Applikation
{
  public static void main(String[] argumente)
  {
    Box dummy     = new Box(BoxLayout.Y_AXIS);
    JFrame window = new JFrame();
    JPanel panel  = new JPanel();

    panel.setBackground(Color.black);
    window.add(dummy);
    dummy.add(panel);

    JButton button = new JButton("Add");
    button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e)
    {
      JLabel white = new JLabel("XX");
      white.setBackground(Color.white);
      white.setForeground(Color.white);
      panel.add(white);   // only visible after resizing window or switching focus to another program and back
      panel.invalidate(); // does nothing
      panel.repaint();    // does nothing
      panel.repaint(200); // does nothing
    } });

    dummy.add(button);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setVisible(true);
  }
}

What am I missing?

Note that this is essentially a duplicate of this question, but as can bee seen in my example code, none of its answers do apply: They empirically do not work.

Community
  • 1
  • 1
Zsar
  • 443
  • 3
  • 14
  • 1. (after all JComponent are added) revalidate + repaint (all JComponents fills current Rectangle from ContentPane) or pack (JFrames bound are calculated from, based on JComponents PrefferedSize), 2. by default works from Java6 – mKorbel Jan 20 '16 at 13:25
  • @mKorbel : "pack" requires the top level container to be known in that leaf of the component tree. Not good. "revalidate + repaint" surprisingly works in my life code, but does *not* work in the example code I posted. Looks like the answer is a bit more complicated than that. – Zsar Jan 20 '16 at 13:34
  • That code won't compile as shown, so it is obviously ***not*** the code you are saying does not work. It would compile if `JPanel panel = new JPanel();` was instead `final JPanel panel = new JPanel();` but that is not the point.. – Andrew Thompson Jan 20 '16 at 15:21
  • @AndrewThompson : Something seems to be wrong with your Java installation then. I just copy-pasted the code from this page into a new text file and compiled that without any parameters using javac from jdk1.8.0_66. Not only does it compile, it behaves exactly as I described. – Zsar Jan 20 '16 at 15:44
  • 1
    `revalidate` + `repaint` *does* work with this example. However, since you are invalidating the entire tree (`add` does that implicitly, your manual invocation of `invalidate` is obsolete), the correct way is to invoke either `validate()` or `revalidate()` on the topmost component. Mind [`SwingUtilities.getRoot(…)`](https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingUtilities.html#getRoot-java.awt.Component-)… – Holger Jan 20 '16 at 18:59
  • @Andrew Thompson: the question is tagged with Java 8. Maybe it would be more obvious, if the code uses a lambda expression for the `ActionListener`… – Holger Jan 20 '16 at 19:01
  • @Holger : It does not seem as if *any* combination of revalidate and/or repaint works with this example. Mayhap I should check *my* Java installation? `SwingUtilities.getRoot(panel).[re]validate()` however *does* work and is elegant enough to be used. Care to turn this into an answer? Ideally with some hint at whether re- or just validate might be preferrable over the other why in what situation. – Zsar Jan 21 '16 at 09:49

0 Answers0