2015-05-01 3 views
0

Я пытаюсь написать простой графический интерфейс, который отображает некоторые цвета непрерывно в цикле. Цикл будет останавливаться при цвете, когда пользователь нажимает кнопку ввода, и возобновляет повторное нажатие.Java guis - прослушивание событий в бесконечном цикле

У меня, похоже, возникают проблемы. Когда я нажимаю один раз, он продолжает последний цвет в массиве, который является черным - когда он должен остановиться на цвет, который я нажал, введите. И когда я нажимаю войти еще раз, программа, кажется, просто повесить и пойти отвечать на запросы затем бросить ошибки как:

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

Могу ли я с помощью Timer и TimerTask неправильно?

Вот мой класс для этого:

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) { 

     } 
    } 
} 

Update 2: Использование класса Timer. Добавлено поле private Timer timer;

Он initializied в конструкторе

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

     timer.start(); 

И colorChange() имеет время цикла удалены. Проблема: при запуске программы она остается на сером экране в течение 5 секунд, после чего она переходит на черный (последний цвет) и остается там. Графический интерфейс, похоже, не обновляется во время выполнения ActionPerformed?

ответ

2

Не используйте 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); 
    } 
} 
+0

Привет, спасибо за ваше предложение. Я читаю о классе Swing Timer. Я изменил свой код, чтобы использовать его, но, похоже, проблема. Когда я запускаю программу. он серый, а затем через 5 секунд он перескакивает до последнего цвета и остается черным – tenkii

+1

@tenkii. The Thread.sleep() не позволяет графическому интерфейсу пересортировать себя, избавиться от него. Кроме того, таймер должен срабатывать каждую секунду. Затем вы меняете цвет фона. Когда индекс достигает 5, вы останавливаете таймер. См. Редактирование. – camickr

+0

Я снял сон(), но он ничего не делает. Почему Таймеру нужно стрелять каждую секунду? Могу ли я не продолжать его стрелять каждые 5 секунд, поскольку это достаточно долго, чтобы каждый цвет отображался на экране один раз в секунду? – tenkii