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.
我使用的Timer
和TimerTask
错了吗?
这是我的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 );
}
}
我正在尝试编写一个简单的 GUI,它可以循环连续显示一些颜色。当用户按下 enter 时,循环将停止在一种颜色,并在再次按下 enter 时恢复。
我好像遇到了一些问题。当我按一次 enter 时,它会继续显示数组中的最后一种颜色,即黑色 - 当它应该停止在我按 enter 的颜色时。当我再次按下回车键时,程序似乎只是挂起并且没有响应然后抛出如下错误:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
我使用的Timer
和TimerTask
错了吗?
这是我的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 );
}
}