多次更改 JPanel 的背景颜色

Change backround color of JPanel multiple times

我正在尝试制作一个小程序,其中包括基于时间更改面板的颜色。 现在我只是想在没有其他的情况下完成那部分。所以我只写了一个只有一个面板的小界面,我想在一个循环中多次更改颜色。 问题是,即使线程暂停了正确的时间,面板的颜色也没有正确改变。它只是有时在循环中改变,而不是每次都改变。

我的界面Class:

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

//creates the Interface
public class Interface extends JFrame {
    private JPanel frame1;

    public Interface (String titel) {
        super(titel);
        setSize(600, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.frame1 = new JPanel();
        this.frame1.setPreferredSize(new Dimension (200, 200));
        setLayout(new FlowLayout());
        add(frame1);
        this.setVisible(true);
    }

    public JPanel getFrame1() {
        return frame1;
    }

}

我的暂停 Class:

import java.util.TimerTask;


//supposed to pause the thread by @pause amount of milliseconds
public class Pause extends TimerTask {
    private int pause;

    public Pause(int pause){
        this.pause = pause;
    }

    @Override
    public void run() {
        System.out.println("Timer"+ pause+" task started at:"+System.currentTimeMillis());
        pause();
        System.out.println("Timer task"+ pause+" ended at:"+System.currentTimeMillis());
    }

    public void pause() {
        try {
            Thread.sleep(this.pause);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

我的眨眼Class

import javax.swing.*;
import java.awt.*;
public class Blink {
    private JPanel frame1;
    public Blink(Interface anInterface){
        this.frame1 = anInterface.getFrame1();
    }

    // blink should change the color of the JPanel inside my Frame. 
    // Its supposed to change to red for 200 ms
    // and then to white again for 1000 ms.
    // this should be repeated 10 times.
    public void blink() {
        Pause pause1 = new Pause(200);
        Pause pause2 = new Pause(1000);
        pause2.run();
        int i = 1;
        while(i <= 10){
            i++;
            frame1.setBackground(Color.red);
            frame1.repaint();
            pause1.run();
            frame1.setBackground(Color.white);
            frame1.repaint();
            pause2.run();
        }
    }

    public static void main ( String[] args ) {
        Interface anInterface = new Interface("Title");
        anInterface.setVisible(true);
        Blink blink = new Blink(anInterface);
        blink.blink();
    }
}

根据Concurrency to Swing you cannot simply Thread.sleep the Thread where the GUI runs because it will freeze it, hence events cannot take place. Instead, for any kind of animation or long-heavy task (consider Thread.sleep as one), Swing Timers and Swing Workers应该使用。在您的情况下,javax.swing.Timer 更合适。

其用法示例:

public class Blink {
    private JPanel frame1;
    private int pause1TimesRan;
    private int pause2TimesRan;

    private Timer pauser1, pauser2;

    public Blink(Interface anInterface) {
        this.frame1 = anInterface.getFrame1();
        //Create pauser 1 with delay 200ms
        pauser1 = new Timer(200, e -> {
            if (pause1TimesRan == 10) {
                pauser1.stop();
                return;
            }
            Color color = randomColor();
            frame1.setBackground(color);
            System.out.println("Pauser #1 changed background to: " + color);
            pause1TimesRan++;
        });
        //Create pauser 2 with delay 1000ms
        pauser2 = new Timer(1000, e -> {
            if (pause2TimesRan == 10) {
                pauser2.stop();
                return;
            }
            Color color = randomColor();
            frame1.setBackground(color);
            System.out.println("Pauser #2 changed background to: " + color);
            pause2TimesRan++;
        });
    }

    private static Color randomColor() {
        return new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
    }

    public void blink() {
        pauser1.start();
        pauser2.start();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Interface anInterface = new Interface("Title");
            anInterface.setVisible(true);
            Blink blink = new Blink(anInterface);
            blink.blink();
        });
    }

    static class Interface extends JFrame {
        private JPanel frame1;

        public Interface(String titel) {
            super(titel);
            setSize(600, 400);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.frame1 = new JPanel();
            this.frame1.setPreferredSize(new Dimension(200, 200));
            setLayout(new FlowLayout());
            add(frame1);
            this.setVisible(true);
        }

        public JPanel getFrame1() {
            return frame1;
        }

    }
}

一个偏离主题的建议是正确命名您的方法(和变量)。您调用了方法 getFrame1(),但它实际上是 JPanel 而不是 JFrame。因此,更好的名称可能是 getPanel()。另外,关于 SwingUtilities.invokeLater 部分,阅读 What does SwingUtilities.invokeLater does.