tags:

views:

140

answers:

3

I have a bunch of buttons in my JToolBar, and I set some of them to be disabled or enabled depending on the state of my application. I find when I am updating a number of buttons at once that they are not all repainted at the same time. I want to ensure that when I set a number of buttons to be disabled/enabled, that they all change state at the same time.

Below is a small test that demonstrates the problem. (It needs a file a.png in the current directory to use as a button icon.) When you run it, a toolbar with 10 buttons is shown. Pressing Enter at the terminal will toggle the disabled state of all of the buttons. On my machine at least, each time I do this the buttons are repainted in a seemingly random order, and not all at once.

It seems like double buffering might solve the problem, although the first thing I tried (setting double buffering on the JToolBar) didn't seem to affect anything.

Thanks,

Cameron

import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.util.*;

public class Test {
    public static void main(String[] args) throws IOException {
        final JButton[] bs = new JButton[10];
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                JFrame f = new JFrame("test");
                JToolBar t = new JToolBar();
                f.getContentPane().add(t);
                for (int i = 0; i < bs.length; i++) {
                    bs[i] = new JButton(new ImageIcon("a.png"));
                    t.add(bs[i]);
                }
                f.pack();
                f.setVisible(true);
            }
        });
        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
        for (;;) {
            r.readLine();
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    for (JButton b : bs) {
                        b.setEnabled(!b.isEnabled());
                    }
                }
            });
        }
    }
}
+1  A: 

Works fine for me using JDK6 on XP.

I don't see any problem with your code. I've enabled/disable more components than that at one time without a problem.

Is the problem because you are accepting input from the terminal? Try adding a separate button to your frame such that clicking on it will cause the state of the buttons to change.

camickr
+2  A: 

As long as the enable state changes happen in one event thread run, they happen so that nothing can't go there between in invalid state. So I guess this is just a painting problem? It just looks bad?

One possible way to change the behavior is to add a repaint call for the container (the toolbar for example) so that bigger area is repainted at once instead of repainting each button separately.

iny
A: 

@camickr I'm on JDK6 on Windows 7. I kicked off the changes with EventQueue.invokeLater() because in my application, what causes the toolbar buttons to need to update state happens in another thread, so I use EventQueue.invokeLater() there. I tried doing everything from the EDT (i.e., doing the setEnabled() calls from an ActionListener on one of the buttons) but I still had the same strange repainting.

@iny Right, it just looks bad. I did actually think that because all the state changes happen within one EventQueue Runnable that all the painting would happen at once after it ended, but I guess not. Your suggestion of calling repaint() on the JToolBar did coalesce all the painting for the buttons, thanks! (Once my unregistered account (which I can't seem to get back to) and my recently registered account are merged, I'll accept your answer.)

heycam