2015-03-31 2 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) –

+3

Для примера [http://stackoverflow.com/a/2234020/230513). – trashgod

ответ

2

Использование javax.swing.TImer. Пример смотреть на:

EDIT: использовали различные переменные, как ранее переменная 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); 
    } 
} 

EDIT 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

+0

@remi: Ничего, фактически 'SwingUtilities' сам внутренне вызывает' EventQueue'. –

2

Каждый раз, когда вы используете Thread или Timer, его время отклика будет зависеть от загрузки системы. То есть вы не можете гарантировать, что событие будет отправлено на миллисекунду, поэтому я бы не стал беспокоиться об этом.

Единственное, что вы могли бы сделать, это использовать:

label.paintImmediately(...); 

Это заставит ярлык перерисовать себя без использования RepaintManager.

// кстати, опубликовать ((Пустота []) нуль) Выдает исключение

Ну, а затем передать строку или какой-либо другой объект, который можно игнорировать.

Смежные вопросы