Java guis - 在无限循环中监听事件

Java guis - listening for events in infinite loop

我正在尝试编写一个简单的 GUI,它可以循环连续显示一些颜色。当用户按下 enter 时,循环将停止在一种颜色,并在再次按下 enter 时恢复。

我好像遇到了一些问题。当我按一次 enter 时,它会继续显示数组中的最后一种颜色,即黑色 - 当它应该停止在我按 enter 的颜色时。当我再次按下回车键时,程序似乎只是挂起并且没有响应然后抛出如下错误:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.

我使用的TimerTimerTask错了吗?

这是我的class:

import java.awt.Color;
import java.awt.Container;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;

public class Rainbow extends JFrame {
    public static final int PAUSED = 0;
    public static final int PLAYING = 1;
    private Timer timer;
    private TimerTask task;
    private int state;
    private Color[] spectrum;
    private Container c;

    public static void main(String[] args) {
        Rainbow r = new Rainbow();
    }

    public Rainbow() {
        super("TASTE THE RAINBOW!");
        createFrame();
        setVisible(true);
        timer = new Timer();
        state = PLAYING;
        task = new TimerTask() {
            public void run() {
                colorChange();
            }
        };
        timer.schedule(task, Calendar.getInstance().getTime(), 1);
    }

    private void createFrame() {
        c = getContentPane();
        spectrum = new Color[] {Color.RED, Color.YELLOW, Color.GREEN,  Color.BLUE, Color.BLACK};
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);

        c.setFocusable(true);
        c.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER) {

                    if(state ==  PLAYING)  {
                        System.out.println(1);
                        state  =  PAUSED;
                        timer.cancel();
                    } else {
                        System.out.println(2);
                        state =  PLAYING;
                        timer.schedule(task, Calendar.getInstance().getTime(), 1);
                    }
                }
            }
        });
    }

    private void colorChange() {
        try {
            while(state == PLAYING) {
                for(int i = 0; i < spectrum.length; i++) {
                    c.setBackground(spectrum[i]);
                    Thread.sleep(1000);
                }
            }
        } catch(Exception e) {

        }
    }
}

更新 2: 使用计时器 class。 添加字段 private Timer timer;

在构造函数中初始化

timer = new Timer(5000, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                colorChange();
            }
        });

        timer.start();

并且 colorChange() 删除了 while 循环。 问题:当您 运行 程序时,它会在灰色屏幕停留 5 秒,然后跳到黑色(最后一种颜色)并停留在那里。在执行 actionPerformed 期间,GUI 似乎没有更新?

不要使用 TimerTask。 Swing 组件应该在事件调度线程上更新。所以你应该使用 Swing Timer.

不要使用 KeyListener。 Swing 旨在与 Key Bindings.

一起使用

在定时器调用的ActionListener中,不需要循环。您只需增加索引并获得下一个颜色。

下面是一个在您每次切换到组件时淡化背景的示例:

import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
import java.util.ArrayList;
import javax.swing.*;

public class Fader
{
    //  background color when component has focus
    private Color fadeColor;

    //  steps to fade from original background to fade background
    private int steps;

    //  apply transition colors at this time interval
    private int interval;

    //  store transition colors from orginal background to fade background
    private Hashtable backgroundColors = new Hashtable();

    /*
     *  Fade from a background color to the specified color using
     *  the default of 10 steps at a 50 millisecond interval.
     *
     *  @param fadeColor the temporary background color
     */
    public Fader(Color fadeColor)
    {
        this(fadeColor, 10, 50);
    }

    /*
     *  Fade from a background color to the specified color in the
     *  specified number of steps at the default 5 millisecond interval.
     *
     *  @param fadeColor the temporary background color
     *  @param steps     the number of steps to fade in the color
     */
    public Fader(Color fadeColor, int steps)
    {
        this(fadeColor, steps, 50);
    }

    /*
     *  Fade from a background color to the specified color in the
     *  specified number of steps at the specified time interval.
     *
     *  @param fadeColor the temporary background color
     *  @param steps     the number of steps to fade in the color
     *  @param intevral  the interval to apply color fading
     */
    public Fader(Color fadeColor, int steps, int interval)
    {
        this.fadeColor = fadeColor;
        this.steps = steps;
        this.interval = interval;
    }

    /*
     *  Add a component to this fader.
     *
     *  The fade color will be applied when the component gains focus.
     *  The background color will be restored when the component loses focus.
     *
     *  @param component apply fading to this component
    */
    public Fader add(JComponent component)
    {
        //  Get colors to be used for fading

        ArrayList colors = getColors( component.getBackground() );

        //  FaderTimer will apply colors to the component

        new FaderTimer( colors, component, interval );

        return this;
    }

    /*
    **  Get the colors used to fade this background
    */
    private ArrayList getColors(Color background)
    {
        //  Check if the color ArrayList already exists

        Object o = backgroundColors.get( background );

        if (o != null)
        {
            return (ArrayList)o;
        }

        //  Doesn't exist, create fader colors for this background

        ArrayList colors = new ArrayList( steps + 1 );
        colors.add( background );

        int rDelta = ( background.getRed() - fadeColor.getRed() ) / steps;
        int gDelta = ( background.getGreen() - fadeColor.getGreen() ) / steps;
        int bDelta = ( background.getBlue() - fadeColor.getBlue() ) / steps;

        for (int i = 1; i < steps; i++)
        {
            int rValue = background.getRed() - (i * rDelta);
            int gValue = background.getGreen() - (i * gDelta);
            int bValue = background.getBlue() - (i * bDelta);

            colors.add( new Color(rValue, gValue, bValue) );
        }

        colors.add( fadeColor );
        backgroundColors.put(background, colors);

        return colors;
    }

    class FaderTimer implements FocusListener, ActionListener
    {
        private ArrayList colors;
        private JComponent component;
        private Timer timer;
        private int alpha;
        private int increment;

        FaderTimer(ArrayList colors, JComponent component, int interval)
        {
            this.colors = colors;
            this.component = component;
            component.addFocusListener( this );
            timer = new Timer(interval, this);
        }

        public void focusGained(FocusEvent e)
        {
            alpha = 0;
            increment = 1;
            timer.start();
        }

        public void focusLost(FocusEvent e)
        {
            alpha = steps;
            increment = -1;
            timer.start();
        }

        public void actionPerformed(ActionEvent e)
        {
            alpha += increment;

            component.setBackground( (Color)colors.get(alpha) );

            if (alpha == steps || alpha == 0)
                timer.stop();
        }
    }

    public static void main(String[] args)
    {
        // Create test components

        JComponent textField1 = new JTextField(10);
        textField1.setBackground( Color.YELLOW );
        JComponent textField3 = new JTextField(10);
        JComponent textField4 = new JTextField(10);
        JComponent button = new JButton("Start");
        JComponent checkBox = new JCheckBox("Check Box");

        JFrame frame = new JFrame("Fading Background");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.getContentPane().add(textField1, BorderLayout.NORTH );
        frame.getContentPane().add(button, BorderLayout.SOUTH );
        frame.getContentPane().add(textField3, BorderLayout.WEST );
        frame.getContentPane().add(textField4, BorderLayout.EAST );
        frame.getContentPane().add(checkBox);

        //  Gradual Fading (using defaults)

//      Fader fader = new Fader( new Color(155, 255, 155) );
        Fader fader = new Fader( new Color(155, 255, 155), 10, 50 );
        fader.add( textField1 );
        fader.add( textField3 );
        fader.add( checkBox );

        //  Instant Fading

        fader = new Fader( new Color(255, 155, 155), 1, 1 );
        fader.add( textField4 );
        fader.add( button );

        frame.pack();
        frame.setVisible( true );
    }
}