Изменить фоновый цвет JPanel несколько раз - PullRequest
1 голос
/ 02 ноября 2019

Я пытаюсь сделать небольшую программу, которая включает в себя изменение цвета панели на основе времени. Прямо сейчас я просто пытаюсь сделать эту часть без всего остального. Поэтому я написал небольшой интерфейс только с одной панелью и хочу несколько раз изменить цвет внутри цикла. Проблема заключается в том, что даже если поток приостанавливается на правильное время, цвет панели изменяется неправильно. Это иногда меняется в цикле не каждый раз.

мой класс интерфейса:

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

}

мой класс Blink

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

1 Ответ

1 голос
/ 02 ноября 2019

Согласно Параллелизм с Swing вы не можете просто Thread.sleep Thread, где работает GUI, потому что он его замораживает, следовательно, события не могут происходить. Вместо этого, для любого вида анимации или долгого тяжелого задания (рассмотрим Thread.sleep как одно), следует использовать Swing Timers и 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 читайте Что делает SwingUtilities.invokeLater .

...