2014-05-23 5 views
0

J'essaie de rendre rouge mon JButton scintillant pour ce jeu que je crée. Toutes les solutions sur ce site suggèrent d'utiliser un fil et de le mettre en veille ou en utilisant une minuterie, cependant, la pause allays semble venir après le changement de couleurJava Swing JButton Délais (Flicker)

Voici mon code:

Color cb = board[Y1][X1].getBackground(); 
board[Y1][X1].setBackground(Color.RED); 
//Pause 
board[Y1][X1].setBackground(cb); 

Si je mettre un fil et le mettre en veille sur la ligne 3 et commenter la ligne 4 la pause viendra avant que le JButton ne devienne rouge. (Le tableau de notes n'est qu'un tableau 2D de JButtons)

+2

Bienvenue dans Stack Overflow! Un réel [exécutable exemple qui démontre votre problème] (https://stackoverflow.com/help/mcve) impliquerait moins de deviner le travail et de meilleures réponses – MadProgrammer

+0

Je pensais que quelqu'un devait avoir rencontré un problème similaire avant, le code réel est inutile, c'est plus un problème Java. JButton -> Rouge Pause JButton -> Noir – user3667398

+0

Vous seriez surpris – MadProgrammer

Répondre

4

Il existe plusieurs raisons pour lesquelles cela peut se produire et, de plusieurs façons, il peut être résolu. En fonction de votre description, il semble que vous essayez de mettre à jour l'interface utilisateur à l'extérieur du thread d'envoi d'événement.

Swing est un environnement à un seul thread, il n'est pas non plus thread-safe. Fondamentalement, ce que cela signifie, il y a une attente que toutes les interactions/modifications à l'interface utilisateur sont effectuées dans le contexte de l'EDT. Ne pas suivre cette règle peut conduire à toutes sortes de comportements étranges et merveilleux.

La solution la plus simple est d'utiliser un javax.swing.Timer, ce qui vous permet de programmer des événements chronométrés réguliers qui sont garantis à exécuter dans le EDT, par exemple

Flashy

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class FlashyButton { 

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

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

       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 button; 
     private Color[] colors = new Color[]{Color.RED, Color.YELLOW}; 

     public TestPane() { 
      button = new JButton("Flash Gorden"); 
      button.setContentAreaFilled(false); 
      button.setBorderPainted(false); 
      button.setFocusPainted(false); 
      button.setOpaque(true); 
      button.setBackground(Color.YELLOW); 
      setLayout(new GridBagLayout()); 
      add(button); 

      Timer timer = new Timer(500, new ActionListener() { 
       private int counter = 0; 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        counter++; 
        if (counter % 2 == 0) { 
         button.setBackground(colors[0]); 
        } else { 
         button.setBackground(colors[1]); 
        } 
       } 
      }); 
      timer.start(); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      g2d.dispose(); 
     } 
    } 

} 

Jetez un oeil à Concurrency in Swing et How to Use Swing Timers pour plus de détails.

Une solution plus complexe vous permettra d'utiliser un Thread, mais il faudrait mettre à jour l'interface utilisateur en utilisant SwingUtilities.invokeLater, qui placerait un événement sur le EDT qui exécute une interface Runnable, que vous utilisez pour mettre à jour l'interface utilisateur . Cela pourrait avoir des problèmes de synchronisation puisque le Thread que vous appelez aura été déplacé avant que l'événement réel ne soit déclenché et pourrait causer des mises à jour sales, sauf si vous contrôlez soigneusement le processus de mise à jour ...

+0

Cette solution ne fonctionne pas pour mon problème particulier, je l'ai besoin pour clignoter une fois pas clignoter en continu. En tant que tel, j'ai essayé de changer de compteur à un booléen et d'utiliser un if/else, mais comme je l'utilise sur un tableau, les choses descendent très rapidement – user3667398

+1

Alors? Arrêtez le 'Timer' après le nombre de clignotements requis. Vous pouvez également utiliser un seul 'Timer' et un' List' ou 'Queue' d'éléments qui doivent être flashés – MadProgrammer

+0

Voir, exemple exécutable, aide vraiment ... – MadProgrammer