Comment créer des “veuillez patienter” Swing dialogue tout en composant des peintures
Encore relativement nouveau pour Swing, mais après quelques heures de recherche, je ne pouvais pas trouver la réponse en ligne, d'où ce post (désolé si déjà répondu et j'ai oublié).
Je suis en utilisant JFreeChart dans une application Swing. Certains graphiques sont relativement lourds (180k points de données) et la JFreeChart est ChartPanel besoins ~6 secondes pour faire sa première paintComponent().
Donc je voudrais afficher un message "please wait" message dans une boîte de dialogue, tandis que la composante des peintures (pas besoin de montrer les progrès réalisés avec un SwingWorker). J'ai essayé de remplacer la méthode paintComponent, mais malheureusement, le message n'apparaît jamais à l'écran (je suppose que le thread va directement dans la peinture, le graphique, sans prendre le temps de peindre la boîte de dialogue).
Mon code ressemble à ceci:
public class CustomizedChartPanel extends ChartPanel{
private static final long serialVersionUID = 1L;
private JDialog dialog = null;
boolean isPainted = false;
public CustomizedChartPanel(JFreeChart chart) { super(chart); }
@Override
public void paintComponent(Graphics g) {
//At first paint (which can be lengthy for large charts), show "please wait" message
if (! isPainted){
dialog = new JDialog();
dialog.setUndecorated(true);
JPanel panel = new JPanel();
panel.add(new JLabel("Please wait"));
dialog.add(panel);
dialog.pack();
GuiHelper.centerDialog(dialog); //Custom code to center the dialog on the screen
dialog.setVisible(true);
dialog.repaint();
}
super.paintComponent(g);
if (! isPainted){
isPainted = true;
dialog.dispose();
super.repaint();
}
}
}
Un pointeur sur la façon de résoudre ce /meilleures pratiques serait très apprécié!
Grâce,
Thomas
Mise à JOUR:
Merci pour les conseils & débat: très utile.
J'ai commencé la mise en œuvre de la solution proposée avec le invokeLater() que je suis, de peur que l'JLayer solution ne fonctionne pas puisqu'il est également en cours d'exécution sur l'EDT.
Malheureusement, je fais une exception de pointeur null lorsque le paintComponent() est appelée par le invokeLater().
Mon code ressemble à ceci:
@Override
public void paintComponent(Graphics graph) {
//At first paint (which can be lengthy for large charts), show "please wait" message
if (! isPainted){
isPainted = true;
dialog = new JDialog();
dialog.setUndecorated(true);
JPanel panel = new JPanel();
panel.add(new JLabel("Please wait"));
panel.add(new JLabel("Please wait !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"));
dialog.add(panel);
dialog.pack();
GuiHelper.centerDialog(dialog); //Custom code to center the dialog on the screen
dialog.setVisible(true);
dialog.repaint();
RunnableRepaintCaller r = new RunnableRepaintCaller(this, graph, dialog);
SwingUtilities.invokeLater(r);
}
else super.paintComponent(graph); //NULL POINTER EXCEPTION HERE (invoked by runnable class)
}
Et la classe runnable est:
public class RunnableRepaintCaller implements Runnable{
private ChartPanel target;
private Graphics g;
private JDialog dialog;
public RunnableRepaintCaller(ChartPanel target, Graphics g, JDialog dialog){
this.target = target;
this.g = g;
this.dialog = dialog;
}
@Override
public void run() {
System.out.println(g);
target.paintComponent(g);
dialog.dispose();
}
}
Encore une fois, tout pointeur serait bien apprécié !
Thomas
Jetez un oeil à ma réponse ci-dessous. Il utilise SwingWorker mais c'est votre seul moyen de sortir. Je ne peut pas avoir une meilleure suggestion. Aussi, dans paintComponent vous devriez effectuer seulement la "peinture" des opérations et de ne pas modifier l'INTERFACE utilisateur, ni appel invokeLater.
OriginalL'auteur Tom | 2012-07-31
Vous devez vous connecter pour publier un commentaire.
Ici est un exemple et/mais il utilise SwingWorker. Vous devriez sérieusement envisager d'utiliser cela, car si d'une certaine façon le système d'exploitation invalide votre cadre et le chargement de votre JFreeChart est fait sur l'EDT (Événement Expédition Fil), puis votre GUI semblent gelés.
Il vous permet également de donner un meilleur feedback de l'utilisateur pendant que vous êtes au traitement des données. (désolé si le code est un peu long mais le plus intéressant est le code dans l'initUI et le SwingWorker).
Remarque: au lieu de la boîte de dialogue, vous pouvez utiliser le JLayer (si vous utilisez Java 7), mais c'était inutile dans mon exemple.
Le code est très inspiré de http://www.vogella.com/articles/JFreeChart/article.html
Justement repéré. Il suffit de déplacer le setVisible(true) après l'appel à
worker.execute()
.Polet" Maintenant, vous avez introduit une condition de course. Vous n'avez aucune garantie que le thread ne sera pas exécuté jusqu'à la fin avant de la boîte de dialogue.setVisible(true) est même appelé. Si cela arrive toutes sortes de choses étranges peuvent se produire tels que la boîte de dialogue modale s'affiche après que le travail a déjà fait et maintenant, le programme est bloqué.
tout est possible, il est très peu probable de se produire depuis par essence vous envoi long de la tâche en cours d'exécution dans un Swing Travailleur, et non pas quelque chose qui se passe à l'intérieur d'un court laps de temps. Pour être totalement complet et assurez-vous qu'aucune condition de concurrence se produit, nous pouvons déplacer le
execute()
appel à un invokeLater bloc de veiller à ce que la boîte de dialogue est présentée pour la première fois avant que le travailleur exécute.Polet" je ne pense pas que votre correction est bon. Je pense que vous avez besoin de déplacer la boîte de dialogue.setVisible(true) pour un invokeLater dans la méthode doInBackground à établir le bon passe-avant la relation. Oh, et qu'il est peu probable de se produire n'inspire pas confiance dans un programme. Je préférerais qu'il ne se produira jamais.
OriginalL'auteur Guillaume Polet
Vous pouvez utiliser
JLayer
comme expliqué ici.C'est spécifiquement pour un voyant d'activité comme vous le souhaitez.
En plus, vous pouvez garder le
JPanel
avecsetEnabled(false)
jusqu'à vos données complètement chargée. Cela évite les clics indésirables sur leJPanel
.Cela peut être possible, pas sûr jusqu'à essayé. Mais au lieu de figé, il sera de se déplacer plus lentement que d'habitude. Et ce comportement est vu dans la plupart des applications. Si le
LayerUI
est faite d'un cours privé d'un indicateur peut être utilisé pour indiquer à tuer le fil, et leCustomizedChartPanel
peut être utilisé pour l'affichage de toutes les cartes. Cela renforce aussi la GUI.Non, si l'JFreeChart est chargé sur l'EDT, cela ne fonctionnera pas, comme tout repeindre les événements (même s'il est déclenché à partir d'un javax.swing.Minuterie puisqu'ils comptent également sur InvocationEvent) ne se produisent pas jusqu'à ce que le JFreechart a fini de charger.
OriginalL'auteur Nitin Chhajer
Il a été un long temps depuis que j'ai rien fait en Java, mais autant que je sache, le
repaint()
méthode ne permet pas réellement de causer un dessin à se produire. Simplement indicateurs de contrôle en tant que besoin d'être redessiné dans les plus brefs délais. Vous devez appeler lapaint()
méthode directement si vous souhaitez un composant à tirer immédiatement.OriginalL'auteur Taedrin
Vous avez besoin pour commencer l'attente de Dialogue dans un nouveau Thread. Je ne sais pas comment vous créer votre graphique, mais voici un exemple de
Je suppose que c'est facile à dire, c'est une très mauvaise idée sans en donner les références...Pour moi ce n'est pas logique, c'est essayer de jouer deux séparés opérations en même temps : l'affichage du panneau de chargement et le chargement de la réelle graphique dans le même thread.
docs.oracle.com/javase/tutorial/uiswing/concurrency/... Balancer le code de gestion des événements s'exécute sur un fil spécial connu comme le event dispatch thread. Cela est nécessaire parce que la plupart Swing méthodes de l'objet ne sont pas "thread-safe": l'invocation à partir de plusieurs threads risques fil des interférences ou de consistance de la mémoire des erreurs. Certains composant Swing méthodes sont étiquetés "thread-safe" dans la spécification de l'API; il peut être appelée en toute sécurité à partir de n'importe quel thread. Les programmes qui ignorent cette règle peut fonctionner correctement la plupart du temps, mais sont sujettes à des erreurs imprévisibles qui sont difficiles à reproduire.
OriginalL'auteur outellou