首页 > 解决方案 > 多次更改JPanel的背景颜色

问题描述

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

我的接口类:

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;
    }

}

我的暂停课:

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();
        }
    }

}

我的眨眼班

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();
    }
}

标签: javaswingjpanel

解决方案


根据Concurrency to Swing,您不能简单地Thread.sleep确定ThreadGUI 的运行位置,因为它会冻结它,因此无法发生事件。相反,对于任何类型的动画或长时间繁重的任务(视为Thread.sleep一个),都应该使用Swing TimersSwing Workers 。在您的情况下, ajavax.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(),但它实际上是 aJPanel而不是 a JFrame。所以,一个更好的名字可能是getPanel()。另外,关于这SwingUtilities.invokeLater部分,请阅读SwingUtilities.invokeLater 的作用


推荐阅读