2015-03-31 74 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)拋出一個異常

好,那麼傳遞一個字符串或其他對象,你可以忽略。