簡體   English   中英

如何在多次 repaint() 后重繪 JComponent 一次?

[英]How to repaint JComponent once after several repaint()?

我的程序在 JButton 列表上循環。 對於每個 JButton,它每秒重新繪制它:

public class a {
    static JFrame frame = new JFrame();
    static Set<MyButton> components = new HashSet<MyButton>();

    public static void main(String[] args) {
        JPanel lPanel = new JPanel(new GridLayout(0,18));

        for (int i = 0; i < 500; i++) {
            MyButton lButton = new MyButton("Hello" + i);
            lPanel.add(lButton);
            components.add(lButton);
        }
        frame.add(lPanel);
        frame.pack();
        frame.setVisible(true);
        blinking();
    }

    public static void blinking() {
        Timer blinkTimer = new Timer(500, new ActionListener() {
            boolean on = false;

            public void actionPerformed(ActionEvent e) {
                for (MyButton lButton : components) {
                    lButton.blink(on);
                }
                on = !on;
            }
        });
        blinkTimer.start();
    }
}

public class MyButton extends JButton {

    public MyButton(String text) {
        super(text);
    }

    public void blink(boolean on) {
        setBackground(on ? Color.DARK_GRAY : Color.LIGHT_GRAY);
        setForeground(on ? Color.WHITE : Color.BLACK);
    }
}

結果: 在此處輸入圖片說明

我想確保所有按鈕同時更新它們的背景和前景色。

JButton extends JComponentJComponent.setBackground調用repaint() ,以及JComponent.setForeground

因此,我的程序每秒為每個按鈕調用兩次repaint() ,並且顏色並不總是同時更新。

如何確保所有按鈕的顏色同時更新? 我認為解決方案是只調用一個repaint() ,也許在按鈕容器上,但我該怎么做?

按鈕是否都在面板的同一層? 那么為什么不使用該圖層的背景而不是按鈕的背景呢?

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main {
    private static JButton newButton() {
        final JButton b = new JButton("x");
        b.setContentAreaFilled(false);
        //b.setOpaque(false); //Do not make this call, because setContentAreaFilled documentation says so.
        return b;
    }

    public static void main(final String[] args) {
        final JButton tester = newButton();
        final Dimension testerDim = tester.getPreferredSize();
        final Dimension maxDim = new Dimension(1200, 700);

        final int rows = maxDim.width / testerDim.width,
                  cols = maxDim.height / testerDim.height;

        final JPanel buttonPanel = new JPanel(new GridLayout(0, cols));
        final int n = rows * cols;
        buttonPanel.add(tester);
        for (int i = 1; i < n; ++i)
            buttonPanel.add(newButton());

        final JFrame frame = new JFrame("Button grid");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(buttonPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        final Color bg = buttonPanel.getBackground();
        final Timer timer = new Timer(500, new ActionListener() {
            private boolean on = false;

            @Override
            public void actionPerformed(final ActionEvent e) {
                buttonPanel.setBackground(on? bg: bg.darker());
                on = !on;
            }
        });
        timer.setRepeats(true);
        timer.start();
    }
}

我認為這是單核/線程所能做的最好的事情。

此外,如果您想要按鈕之間的其他組件,它們的背景與圖層的背景不同,那么只需使它們不透明( setOpaque(true) ),如果它們還沒有。

解決方案:使用setIgnoreRepaint()並僅重繪框架:

frame.setIgnoreRepaint(true);
for (JButton lButton : components) {
                    // blink the buttons background on and off
    lButton.blink(on);
}
frame.setIgnoreRepaint(false);
frame.repaint();
on = !on;

setIgnoreRepaint 文檔有點誤導,因為它說要暫停系統事件的重繪。 所以我們正在考慮操作系統可以發送的事件。 但實際上它忽略了重繪(隱式或顯式),並且不會直接忽略組件上的方法調用(paint /paintImmediately ...所有這些)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM