【问题标题】:Java guis - listening for events in infinite loopJava guis - 在无限循环中监听事件
【发布时间】:2015-05-01 00:58:37
【问题描述】:

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

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

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

我使用TimerTimerTask 有错吗?

这是我的课程:

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: 使用定时器类。 添加字段private Timer timer;

在构造函数中初始化

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

        timer.start();

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

【问题讨论】:

    标签: java user-interface loops timer timertask


    【解决方案1】:

    不要使用 TimerTask。 Swing 组件应该在 Event Dispatch Thread 上更新。所以你应该使用Swing Timer

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

    在 Timer 调用的 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 );
        }
    }
    

    【讨论】:

    • 您好,感谢您的建议。我正在阅读有关 Swing Timer 课程的信息。我已经修改了我的代码以使用它,但似乎有问题。当我运行程序时。它是灰色的,然后在 5 秒后跳到最后一种颜色并保持黑色
    • @tenkii,Thread.sleep() 正在阻止 GUI 重新打印,摆脱它。此外,定时器需要每秒触发一次。然后你改变背景颜色。当索引达到 5 时,您停止 Timer。查看编辑。
    • 我已经删除了 sleep() 但它仍然没有做任何事情。为什么 Timer 需要每秒触发一次?我能不能让它每 5 秒触发一次,因为这足以让每种颜色每秒在屏幕上出现一次?
    • @tenkii,每次定时器触发你做一些事情。在您的情况下,您希望颜色每秒更改一次。如果您在 5 秒内只触发一次 Timer,那么只会生成一个事件,因此您只能更改一次颜色。我给了你工作代码。使用代码将 Timer 的时间间隔更改为 1 秒以查看差异。
    • 啊哈,我搞定了。我需要阅读更多关于 Timer 的内容,但非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    相关资源
    最近更新 更多