Hi!
I'm sitting with a gui bug that I have been stuck with for a while. When a "view" is changed from one "view" to another, the new "view" doesn't get painted properly. The previous view is visibile randomly in the background.

I can't reproduce this in the dev environment so its hard to debug, but It can easily be reproduced in a remote testlab which I don't have access to and can't remote debug from.

So I was going through the code and noticed this:

proteted void updatebuttonsToModel() {
   // some code...
   SwingUtilities.invokeLater(new Runnable() {
      // some gui changes...     
      validate()
      repaint()
   }
}

I am thinking about if changing validate to revalidate() might do me any good? What are the differences beteween these two? It sound like they should do the samt thing. The javadocs doesn't say much. Could this possibly be the problem?

1) validate & invalidate is Look and Feel sensitive, and for some JComponents doesn't works correctly

2) validate is for add new JComponents to already Visible Container

3) revalidate is for remove JComponent (and then maybe add new JComponent) from / to already Visible Container

4) part of JComponents required add repaint() method too,

5) revalidate covered validate too

6) result is always use only (and covered all possible combinations implemented in Swing APIs)

revalidate();
repaint();

7) here you can test whats happens,

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;

public class AddComponentsAtRuntime {

    private JFrame f;
    private JPanel panel;
    private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;

    public AddComponentsAtRuntime() {
        JButton b = new JButton();
        b.setBackground(Color.red);
        b.setBorder(new LineBorder(Color.black, 2));
        b.setPreferredSize(new Dimension(600, 10));
        panel = new JPanel(new GridLayout(0, 1));
        panel.add(b);
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel, "Center");
        f.add(getCheckBoxPanel(), "South");
        f.setLocation(200, 200);
        f.pack();
        f.setVisible(true);
    }

    private JPanel getCheckBoxPanel() {
        checkValidate = new JCheckBox("validate");
        checkValidate.setSelected(false);
        checkReValidate = new JCheckBox("revalidate");
        checkReValidate.setSelected(false);
        checkRepaint = new JCheckBox("repaint");
        checkRepaint.setSelected(false);
        checkPack = new JCheckBox("pack");
        checkPack.setSelected(false);
        JButton addComp = new JButton("Add New One");
        addComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JButton b = new JButton();
                b.setBackground(Color.red);
                b.setBorder(new LineBorder(Color.black, 2));
                b.setPreferredSize(new Dimension(600, 10));
                panel.add(b);
                makeChange();
                System.out.println(" Components Count after Adds :" + panel.getComponentCount());
            }
        });
        JButton removeComp = new JButton("Remove One");
        removeComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int count = panel.getComponentCount();
                if (count > 0) {
                    panel.remove(0);
                }
                makeChange();
                System.out.println(" Components Count after Removes :" + panel.getComponentCount());
            }
        });
        JPanel panel2 = new JPanel();
        panel2.add(checkValidate);
        panel2.add(checkReValidate);
        panel2.add(checkRepaint);
        panel2.add(checkPack);
        panel2.add(addComp);
        panel2.add(removeComp);
        return panel2;
    }

    private void makeChange() {
        if (checkValidate.isSelected()) {
            panel.validate();
        }
        if (checkReValidate.isSelected()) {
            panel.revalidate();
        }
        if (checkRepaint.isSelected()) {
            panel.repaint();
        }
        if (checkPack.isSelected()) {
            f.pack();
        }
    }

    public static void main(String[] args) {
        AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
    }
}

8) never use invalidate that's notifiers for UIManager

Edited 4 Years Ago by mKorbel: n/a

Just a FYI

http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/SwingUtilities.html#invokeLater%28java.lang.Runnable%29

Sometimes when I work with SwingUtilities.invokeLater(Runnable) it doesn't quite work like I want. Sometimes all of the GUI is updated, sometimes only part of it, sometimes everything but 1% of the last piece of GUI is updated super fast and the rest percentage takes what seem like forever. This is especially noticeable when working with large collections of data (as a ResultSet from your database for instance).

I usually work around this by NOT using SwingUtilities (or SwingWorker for that matter) and creating an anonymous thread in my actionPerformed and invoking the .start(), like so:

new Thread(new Runnable() {

            @Override
            public void run() {
                //code omitted
        }).start();

Here is a brilliantly clear explanation of the difference between validate and revalidate:
http://www.jguru.com/faq/view.jsp?EID=88716

@Traps: I don't know why you posted that in this thread, but SwingUtilities.invokeLater runs things on the Swing EDT, and is therefore absolutely NOT intended for "working with large collections of data" - that's a complete mis-use of that method.
SwingWorker, on the other hand, is intended for long-running tasks, and provides mechanisms for displaying intermediate results, and dispatching the final results back to an EDT method for display. You can, if you want, write your own code to run a task on your own thread and handle the synch with the EDT and transfer back to the EDT to display the results. But unless you have some very special requirement, you should use the standard methods provided for that purpose.

The work done in the Runnable passed to SwingUtilities.invokeLater is just setting of some text in labels and some other minor stuff. I guess that they used invoke later because that piece of code doesn't run on the EDT. Don't think SwingWorker will be neccesary.

Have changed to revalidate and submitted for testing. Lets see if that was the problem.

Yes, because Swing isn't thread-safe any code that updates anything related to the GUI should be run on the EDT, so you use invokeLater or invokeAndWait to run them if you are on another thread. (Except, as it happens, updating the text of a JLabel is one of the very few things that can be done safely from another thread.)

This question has already been answered. Start a new discussion instead.