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
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 ...
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
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
Vous seriez surpris – MadProgrammer