开发者

Can I batch some Swing component updates so that repaints are all done at once?

开发者 https://www.devze.com 2022-12-15 09:37 出处:网络
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

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开发者_如何学C 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());
                    }
                }
            });
        }
    }
}


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.


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 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.)

0

精彩评论

暂无评论...
验证码 换一张
取 消