2016-01-06 3 views
1

Моя проблема: Эффективный способ для программы задержать в моем сценарии.Jbutton flash между двумя цветами фона

Мой сценарий: Я делаю викторину для короткого проекта, длинный рассказ. На вопрос отвечает, когда пользователь нажимает на одну из четырех кнопок, на которых есть ответ. Тогда мой класс quizengine вызывает метод рисования, показанный здесь. После этого он начинает ссылаться на другие методы, ответственные за появление следующего вопроса. Теперь я хочу, чтобы кнопка переключалась между двумя цветами с уменьшением временных интервалов.

Что есть я пытался до сих пор: Сначала я поставил JOptionPane между методом paintbutton и метод, который изменяет интерфейс на следующий вопрос только, чтобы увидеть, если кнопка изменит цвет. Это было успешно. Конечно, это было не мое намерение, я хотел всего лишь промежуток времени. Затем я попытался использовать Thread.Sleep. Хотя программа будет ждать, прежде чем перейти к следующему вопросу, изменение цвета не было видно. Наконец, я попробовал реализовать таймер (возможно, не правильно), хотя, хотя он изменил цвет, программа пошла дальше и перешла к следующему вопросу.

Мои хочет быть код

/* Paints the button pressed red or green 
    * Green if the anwser is correct red if 
    * its false 
    * 
    * @param int bnr the number of the button 
    * @param boolean corr true if correct false if false :D 
    */ 
    public static void paintbutton(int bnr,boolean corr) { 
     for (int i=10;i>1;i--){ 
     b[bnr-1].setBackground(null);  
     //wait for i*100 milliseconds 
     b[bnr-1].setBackground(corr?Color.green:Color.red);   
     } 
    } 
+1

Используйте Swing 'Timer', см. [Как использовать таймеры Swing] (http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) для получения более подробной информации. – MadProgrammer

+0

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

+0

А на самом деле это может дать мне проблемы, потому что остальная часть кода будет продолжена, и это приведет к изменению текста вопроса. По крайней мере, это, по-видимому, проблема =/ –

ответ

3

Давайте начнем с некоторыми основами. Swing является однопоточным, что означает, что вы никогда не должны блокировать или исполнять длинный код в контексте потока событий Dispatching, это заставит пользовательский интерфейс зависеть и пользователь нарушит

Swing не является потокобезопасным, это означает, что вы никогда не должны создавать или обновлять пользовательский интерфейс вне контекста EDT.

Это приводит к возникновению проблемы. Вы хотите, после небольшой задержки, обновить интерфейс.

К счастью для вас существует как минимум две возможности: Swing Timer или SwingWorker.

A Swing Timer относительно прост, но на самом деле не обеспечивает средства для создания переменной задержки между обновлениями. A SwingWorker является более сложным, но дает вам контроль в основном делать то, что вы хотите.

Оба эти (могут) «ждут» вне EDT, но оба обеспечивают средства, с помощью которых вы можете безопасно доставлять обновления EDT.

Например ...

Blinky

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.util.List; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingWorker; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class BlinkyTheButton { 

    public static void main(String[] args) { 
     new BlinkyTheButton(); 
    } 

    public BlinkyTheButton() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private JButton blinky; 

     public TestPane() { 
      blinky = new JButton("Blinky"); 
      blinky.setOpaque(true); 
      blinky.addActionListener(new ActionListener() { 
       private BlinkWorker worker; 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (worker == null || worker.getState() == SwingWorker.StateValue.DONE) { 
         worker = new BlinkWorker(blinky, Color.RED); 
         worker.addPropertyChangeListener(new PropertyChangeListener() { 
          @Override 
          public void propertyChange(PropertyChangeEvent evt) { 
           SwingWorker worker = (SwingWorker) evt.getSource(); 
           if ("state".equals(evt.getPropertyName())) { 
            if (worker.getState() == SwingWorker.StateValue.DONE) { 
             // this is where you would then call the method to 
             // update the state for a new question 
            } 
           } 
          } 
         }); 
         worker.execute(); 
        } 
       } 
      }); 
      setLayout(new GridBagLayout()); 
      add(blinky); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

     public class BlinkWorker extends SwingWorker<Void, Color> { 

      private JButton btn; 
      private Color color; 
      private Color normal; 

      public BlinkWorker(JButton btn, Color color) { 
       this.btn = btn; 
       normal = btn.getBackground(); 
       this.color = color; 
      } 

      @Override 
      protected Void doInBackground() throws Exception { 
       for (int index = 10; index > 1; index--) { 
        publish(color); 
        Thread.sleep(index * 100); 
        publish(normal); 
        Thread.sleep(index * 100); 
       } 
       return null; 
      } 

      @Override 
      protected void process(List<Color> chunks) { 
       Color color = chunks.get(chunks.size() - 1); 
       btn.setBackground(color); 
      } 

     } 

    } 

} 

Посмотрите Concurrency in Swing, How to use Swing Timers и Worker Threads and SwingWorker для получения более подробной информации

+0

Ничего себе! С моих первых попыток я почувствовал, что было бы сложно сделать это. Я очень ценю то время, которое вы вложили в это. Вступление в реализацию пользовательского интерфейса - это совершенно новый уровень сложности. Спасибо, что открыли мне глаза на это, я тщательно изучу ваш ответ. –

0

нашел обходной путь! Хорошо, я не знаю, сколько уровней мое решение ошибочно, но, похоже, это трюк. Я заметил, что если используется JOptionPane.showMessageDialog, кнопка окрашивается нормально. Теперь следующая проблема заключалась в том, что пользователю не нужно было нажимать кнопку ОК в диалоговом окне ... Поэтому я использовал робота!Вот код:

public static void paintbutton(int bnr,boolean corr) { 
     long time; 
      try {   
      Robot robot = new Robot(); 
       for (int i=5;i>1;i--){    
        b[bnr-1].setBackground(null); 
        // Simulate a key press 
        robot.keyPress(KeyEvent.VK_SPACE); 
        robot.keyRelease(KeyEvent.VK_SPACE); 
        JOptionPane.showMessageDialog(null,"hi");           
        time = System.currentTimeMillis(); 

        do {       
        }while(time+i*100>System.currentTimeMillis()); 
        b[bnr-1].setBackground(i==1?(corr?Color.green:Color.red):Color.yellow); 
        // Simulate a key press 
        robot.keyPress(KeyEvent.VK_SPACE); 
        robot.keyRelease(KeyEvent.VK_SPACE); 
        JOptionPane.showMessageDialog(null,"hi");           
        time = System.currentTimeMillis();      
        do {       
        }while(time+i*100>System.currentTimeMillis());      
       } 
     } catch (AWTException e) { 
      System.err.println("error"); 
       }   
    } 

Ok его неаккуратно, диалоговое сообщение появляется на короткое время, но из-за расположения игры обрамляют его скрытым. Если вы переместите основной фрейм, он появится кратко и т. Д. И т. Д. Но, похоже, я здесь что-то здесь. Что-то, что происходит при создании JOptionPane, заставляет кнопки перерисовываться. Если у кого-то появилась идея о том, как воссоздать то, что происходит, когда JOptionPane создается без необходимости его создания, было бы здорово!

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