更改 JButtons 背景的最佳方法

发布于 2024-11-09 09:29:54 字数 1010 浏览 0 评论 0原文

现在我以

button.setBackground(Color.WHITE);

That 为例来更改按钮的背景颜色。

但是当我有一个巨大的 jbuttons 网格(1000+)时,仅仅运行一个 for 循环来改变每个按钮的背景是非常非常慢的。您可以看到网格逐个框慢慢变白。我真的不想这样

有没有更好的方法可以同时将网格上的每个 JButton 更改为相同的颜色?

这就是我制作网格的方式,使用的数字只是举例...

grid = new JPanel(new GridLayout(64, 64, 0, 0));

那是 4096 个按钮,需要大约 30 秒以上才能将每个按钮更改为相同的颜色。

编辑1:我需要按钮是可点击的,例如当我点击按钮时它会变成蓝色。单击所有按钮后,将每个按钮的颜色更改为白色。现在我的工作正常,但改变每个按钮的颜色很慢。

编辑2:这就是我更改按钮的方式:

    new javax.swing.Timer(300, new ActionListener() {
        int counter = 0;
        public void actionPerformed(ActionEvent e) {
            if (counter >= counterMax) {
                ((Timer) e.getSource()).stop();
            }
            Color bckgrndColor = (counter % 2 == 0) ? flashColor : Color.white;
            for (JButton button : gridButton) {
                button.setBackground(bckgrndColor);
            }
            counter++;
        }
    }).start();

Right now i change the background color of a button by using

button.setBackground(Color.WHITE);

That being an example.

But when i have a massive grid out of jbuttons (1000+), just running a for loop to change every buttons background is very, very slow. You can see the grid slowly turning white, box by box. I really don't want this

Is there a better way of changing every JButton on the grid to the same color at the same time?

This is how i am making the grid, the numbers used are only for example...

grid = new JPanel(new GridLayout(64, 64, 0, 0));

That's 4096 buttons, takes about 30+ seconds to change every button to the same color.

Edit 1: I need the buttons to be clickable, like when i click a button it turns blue for example. when all of the buttons are clicked, change the color of every button to white. Right now i have that working fine, but it is just slow to change the color of every button.

Edit 2: this is how i am changing the buttons:

    new javax.swing.Timer(300, new ActionListener() {
        int counter = 0;
        public void actionPerformed(ActionEvent e) {
            if (counter >= counterMax) {
                ((Timer) e.getSource()).stop();
            }
            Color bckgrndColor = (counter % 2 == 0) ? flashColor : Color.white;
            for (JButton button : gridButton) {
                button.setBackground(bckgrndColor);
            }
            counter++;
        }
    }).start();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

生来就爱笑 2024-11-16 09:29:54

事实上,您看到各个框单独重新绘制,这表明双缓冲已关闭,或者按钮 UI 中的绘制代码使用了 paintImmediately()

我使用 64x64 JButtons 测试了您的设置,并确保所有 UI 操作都在 EDT(事件调度线程)中执行。我可以确认您看到的效果,更改所有按钮的背景大约需要 1200 毫秒,每个框都会立即重新绘制。
您可以通过将网格设置为之前不可见,并在更改背景后设置为可见来绕过立即重新绘制:

grid.setVisible(false);
for (Component comp : grid.getComponents()) {
   comp.setBackground(color);
}
grid.setVisible(true);

这导致网格仅执行一次重新绘制,并将时间减少到约 300 毫秒(因子 4)。

对于频繁的更新来说,这仍然太慢,所以如果你想允许,你最好使用绘制网格的自定义组件,或者flyweight容器(trashgod在你的问题的评论中建议的)网格单元是任意组件。

The fact that you see the boxes being repainted individually indicates that either double buffering is turned off, or that the paint code in the button UI makes use of paintImmediately().

I tested your setup with 64x64 JButtons, an made sure that all UI operations were executed in the EDT (Event Dispatch Thread). I can confirm the effect you saw, changing the background of all buttons took about 1200 ms, with every box repainted immediately.
You can bypass the immediate repaints by setting the grid to non-visible before, and to visible after you changed the backgrounds:

grid.setVisible(false);
for (Component comp : grid.getComponents()) {
   comp.setBackground(color);
}
grid.setVisible(true);

This caused the grid to do only one repaint, and reduced the time to ~300ms (factor 4).

This is still too slow for frequent updates, so you're better off with a custom component which draws the grid, or a flyweight container (what trashgod suggested in the comment to your question) if you want allow the grid cells to be arbitrary components.

叹梦 2024-11-16 09:29:54

如果仅需要重新绘制可见按钮,您可以获得相当大的好处。在如下所示的 MVC 方法中,每个按钮监听定义其当前状态的模型。与重新绘制相比,更新模型相当快。尽管启动需要几秒钟,但我看到更新时间<< 10 毫秒在稳态下。它的可扩展性不如 使用的 flyweight 模式 JTable,如图所示此处,但它可以使用。

import java.awt.*;
import java.awt.event.*;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import javax.swing.*;

/** @see https://stackoverflow.com/questions/6117908 */
public class UpdateTest {

    private static final int ROW = 64;
    private static final int COL = 64;
    private static final int MAX = COL * ROW;
    private final DataModel model = new DataModel(MAX);

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new UpdateTest().create();
            }
        });
    }

    void create() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(ROW, COL));
        for (int i = 0; i < MAX; i++) {
            panel.add(new ViewPanel(model, i));
        }
        Timer timer = new Timer(1000, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                long start = System.nanoTime();
                model.update();
                System.out.println(
                    (System.nanoTime() - start) / (1000 * 1000));
            }
        });
        JFrame f = new JFrame("JTextTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new JScrollPane(panel), BorderLayout.CENTER);
        f.setPreferredSize(new Dimension(800, 600));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        timer.start();
    }

    private static class ViewPanel extends JPanel implements Observer {

        private final JButton item = new JButton();
        private DataModel model;
        private int index;

        public ViewPanel(DataModel model, int i) {
            this.model = model;
            this.index = i;
            this.add(item);
            item.setText(String.valueOf(i));
            item.setOpaque(true);
            item.setBackground(new Color(model.get(index)));
            model.addObserver(this);
        }

        @Override
        public void update(Observable o, Object arg) {
            int value = model.get(index);
            item.setBackground(new Color(value));
        }
    }

    private static class DataModel extends Observable {

        private final Random rnd = new Random();
        private final int[] data;

        public DataModel(int n) {
            data = new int[n];
            fillData();
        }

        public void update() {
            fillData();
            this.setChanged();
            this.notifyObservers();
        }

        public int get(int i) {
            return data[i];
        }

        private void fillData() {
            for (int i = 0; i < data.length; i++) {
                data[i] = rnd.nextInt();
            }
        }
    }
}

You can get a considerable benefit if only visible buttons need to be repainted. In the MVC approach shown below, each button listens to a model that defines it's current state. Updating the model is quite fast compared to repainting. Although startup takes a few seconds, I see updates taking < 10 ms. in the steady-state. It's not as scalable as the flyweight pattern used by JTable, illustrated here, but it may serve.

import java.awt.*;
import java.awt.event.*;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import javax.swing.*;

/** @see https://stackoverflow.com/questions/6117908 */
public class UpdateTest {

    private static final int ROW = 64;
    private static final int COL = 64;
    private static final int MAX = COL * ROW;
    private final DataModel model = new DataModel(MAX);

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new UpdateTest().create();
            }
        });
    }

    void create() {
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(ROW, COL));
        for (int i = 0; i < MAX; i++) {
            panel.add(new ViewPanel(model, i));
        }
        Timer timer = new Timer(1000, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                long start = System.nanoTime();
                model.update();
                System.out.println(
                    (System.nanoTime() - start) / (1000 * 1000));
            }
        });
        JFrame f = new JFrame("JTextTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new JScrollPane(panel), BorderLayout.CENTER);
        f.setPreferredSize(new Dimension(800, 600));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        timer.start();
    }

    private static class ViewPanel extends JPanel implements Observer {

        private final JButton item = new JButton();
        private DataModel model;
        private int index;

        public ViewPanel(DataModel model, int i) {
            this.model = model;
            this.index = i;
            this.add(item);
            item.setText(String.valueOf(i));
            item.setOpaque(true);
            item.setBackground(new Color(model.get(index)));
            model.addObserver(this);
        }

        @Override
        public void update(Observable o, Object arg) {
            int value = model.get(index);
            item.setBackground(new Color(value));
        }
    }

    private static class DataModel extends Observable {

        private final Random rnd = new Random();
        private final int[] data;

        public DataModel(int n) {
            data = new int[n];
            fillData();
        }

        public void update() {
            fillData();
            this.setChanged();
            this.notifyObservers();
        }

        public int get(int i) {
            return data[i];
        }

        private void fillData() {
            for (int i = 0; i < data.length; i++) {
                data[i] = rnd.nextInt();
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文