2015-03-31 104 views
3

在我的应用程序的某个时候,我想让JLabel“闪烁”,即重复颠倒前景和背景颜色几次迭代。 我使用SwingWorker发布/过程来做到这一点,但由于此过程的异步特性,根据系统负载等因素,闪烁可能不会很准确。我该如何做得更好?改善我的JLabel闪烁

 SwingWorker<Void, Void> flash = new SwingWorker<Void, Void>() 
    { 

     final int NUM_FLASH = 5; 
     final long DELAY_MS = 500; 
     @Override 
     protected Void doInBackground() throws Exception 
     { 
      try { 
       for (int i = 0; i < 2*NUM_FLASH; ++i) { 
        TimeUnit.MILLISECONDS.sleep(DELAY_MS); 
        // by the way, publish((Void[])null) throws an exception 
        publish(new Void[]{}); 
       } 
      } catch (InterruptedException e) { 
       logger.warn("Exception raised in swingworker flash ", e); 
      } 
      return null; 
     } 

     @Override 
     protected void process(List<Void> chunks) 
     { 
      logger.debug("Swapping colors for flash"); 
      Color fg = label.getForeground(); 
      Color bg = label.getBackground(); 
      label.setForeground(bg); 
      label.setBackground(fg); 
     } 

    }; 
    flash.execute(); 
+2

使用[javax.swing.Timer中(https://docs.oracle.com/javase/8/docs/api/ javax/swing/Timer.html) – 2015-03-31 15:02:39

+3

[示例](http://stackoverflow.com/a/2234020/230513)。 – trashgod 2015-03-31 15:08:24

回答

2

使用javax.swing.TImer。一个例子来查看:

编辑: 使用不同的变量,如前面所述counter变量表示相同的值。

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class LabelExample { 

    private Timer timer; 
    private JButton button; 
    private JLabel label; 
    private Color[] labelColors = { 
     Color.red, 
     Color.blue 
    }; 

    private ActionListener timerAction = new ActionListener() { 
     private int counter1 = 0; 
     private int counter2 = 1; 
     @Override 
     public void actionPerformed (ActionEvent ae) { 
      ++counter1; 
      counter1 %= labelColors.length; 
      label.setBackground (labelColors [ counter1 ]); 
      System.out.println ("Background Counter: " + counter1 + " Length: " + labelColors.length); 
      ++counter2; 
      counter2 %= labelColors.length; 
      label.setForeground (labelColors [ counter2 ]); 
      System.out.println ("Foreground Counter: " + counter2 + " Length: " + labelColors.length); 
     } 
    }; 

    public LabelExample() { 
    } 

    private void displayGUI() { 
     JFrame frame = new JFrame ("Label Example"); 
     frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE); 

     JPanel contentPane = new JPanel(); 

     label = new JLabel ("Hello World!"); 
     label.setOpaque (true); 
     label.setBackground (labelColors [ 0 ]); 
     label.setForeground (labelColors [ 1 ]); 

     button = new JButton ("Stop Timer"); 
     button.addActionListener (new ActionListener() { 
      @Override 
      public void actionPerformed (ActionEvent ae) { 
       timer.stop(); 
      } 
     }); 

     contentPane.add (label); 
     contentPane.add (button); 

     frame.setContentPane (contentPane); 
     frame.pack(); 
     frame.setLocationByPlatform (true); 
     frame.setVisible (true); 

     timer = new Timer (1000, timerAction); 
     timer.start(); 
    } 

    public static void main (String[] args) { 
     Runnable runnable = new Runnable() { 
      @Override 
      public void run() { 
       new LabelExample().displayGUI(); 
      } 
     }; 
     EventQueue.invokeLater (runnable); 
    } 
} 

编辑2:

至于评论,了解更多信息,可以很容易地通过打开SwingUtilities.java文件自己的本地机器上,通过移动到Java的安装位置,并找到了被发现src.zip文件夹,观看任何课程的内容。下面是内容(不要读评论的倒数第二行)SwingUtilities.invokeLater (...)

/** 
* Causes <i>doRun.run()</i> to be executed asynchronously on the 
* AWT event dispatching thread. This will happen after all 
* pending AWT events have been processed. This method should 
* be used when an application thread needs to update the GUI. 
* In the following example the <code>invokeLater</code> call queues 
* the <code>Runnable</code> object <code>doHelloWorld</code> 
* on the event dispatching thread and 
* then prints a message. 
* <pre> 
* Runnable doHelloWorld = new Runnable() { 
*  public void run() { 
*   System.out.println("Hello World on " + Thread.currentThread()); 
*  } 
* }; 
* 
* SwingUtilities.invokeLater(doHelloWorld); 
* System.out.println("This might well be displayed before the other message."); 
* </pre> 
* If invokeLater is called from the event dispatching thread -- 
* for example, from a JButton's ActionListener -- the <i>doRun.run()</i> will 
* still be deferred until all pending events have been processed. 
* Note that if the <i>doRun.run()</i> throws an uncaught exception 
* the event dispatching thread will unwind (not the current thread). 
* <p> 
* Additional documentation and examples for this method can be 
* found in 
* <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How to Use Threads</a>, 
* in <em>The Java Tutorial</em>. 
* <p> 
* As of 1.3 this method is just a cover for <code>java.awt.EventQueue.invokeLater()</code>. 
* <p> 
* Unlike the rest of Swing, this method can be invoked from any thread. 
* 
* @see #invokeAndWait 
*/ 
public static void invokeLater(Runnable doRun) { 
    EventQueue.invokeLater(doRun); 
} 
+0

甚至可以在您的第一条评论后自己写!顺便说一下,'EventQueue.invokeLater'和'SwingUtilities.invokeLater'有什么区别? – remi 2015-03-31 15:23:09

+0

@remi:没有,实际上'SwingUtilities'本身在内部调用'EventQueue'。 – 2015-03-31 15:24:41

2

任何时候您使用线程或计时器时,其响应时间将取决于系统负载。这是你不能保证事件将被派往毫秒,所以我不会担心它。

你也许能够做的唯一的事情就是使用:

label.paintImmediately(...); 

这将迫使标签重绘自己不使用的RepaintManager。

//顺便说一下,发布((无效[])为null)抛出一个异常

好,那么传递一个字符串或其他对象,你可以忽略。