IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AWT/Swing Java Discussion :

nouvelle question JFrame


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé

    Homme Profil pro
    Enseignant
    Inscrit en
    Février 2020
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Février 2020
    Messages : 178
    Par défaut nouvelle question JFrame
    J'ai une JFrame principale statique, nommée "fenetre1", appartenant à la classe" RunTest".
    Cette fenetre affiche un Quizz, posant différentes questions dans des domaines techniques.

    A la sélection du Quizz, on affiche des labels qui ont le rôle suivant :
    - en gris, le nombre total de question disponibles dans le domaine.
    - en orange avec un numéro, le nombre de question choisi pour ce quizz.
    En gros ca ressemble à ca (oui je sais, il y aura encore du travail de présentation, mais pas le sujet du jour...)
    Nom : labelsQuizz.png
Affichages : 100
Taille : 19,1 Ko

    Quand je clique sur le bouton "démarrer" (au bas de la JFrame, non visible sur la photo ci-dessus), je démarre le quizz. (pour le moment, uniquement la question "q0")
    Je fais alors appel à un Thread, qui permet de faire clignoter le label de la question en cours. Le code sur le bouton "démarrer" est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // Action sur BP DEMARRER
    										private static void appuiDémarrer() {
    												System.out.println("on a démarré le quizz.");		
    												démarrer.setEnabled(false);
    												anim = true;
     
    											//	for (int q=0; q<qtne.getNbQuestions(); q++) {
    													int q = 0;
    													Question question = qtne.getListeQuestions()[q];
    													énoncé.setText(question.getEnoncé());
    													MesThreads  thread = new MesThreads(q);
    													thread.start();
     
    											//	}
    										}
    Le Thread est crée et le label clignote bien!
    Le code du Thread est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // --- Méthode Run() ---
    	public void run() {
     
    		boolean clignotant = false;
     
    						while ((RunTest.anim) && (RunTest.fenetre1.isDisplayable())) {			// tant que la question est posée...
    							System.out.println("on est dans la question d'index " + q);
    							System.out.println("la fenetre principale  vaut : " + RunTest.fenetre1.isDisplayable());
     
    							if (clignotant) {
    								RunTest.jlabels[q].setBackground(Color.red);
    							}
    							else {
    								RunTest.jlabels[q].setBackground(Color.WHITE);
    							}
    							RunTest.jlabels[q].repaint();
     
    							  try { Thread.sleep(500); }
    							  		catch (InterruptedException e) {e.printStackTrace();}
     
    							clignotant = !clignotant;
    						}	// fin du while	
    	}  // fin de run
    Le clignotement se vérifie dans la console par les affichages successifs :
    Nom : consoleThreadOK.png
Affichages : 93
Taille : 5,8 Ko

    Je souhaite cependant avoir la main sur la fermeture du Thread.
    Pour cela, j'ai utilisé un "while", pour m'assurer que :
    - la variable "anim" est "true", c'est à dire qu'on est bien en train de réfléchir à une question posée.
    - la fenêtre principale est toujours ouverte. En effet, si on ferme la fenetre principale, je n'ai pas envie que des threads continuent à tourner en arrière plan..

    C'est là que la question se pose..

    1/ dans la condition du "while", j'ai testé "RunTest.fenetre1 != null" et "RunTest.fenetre1.isDisplayable()", et aucune de ces deux conditions ne semble passer à "false", pour interrompre mon thread, quand je ferme "RunTest.fenetre1", qui est pourtant positonnée sur "DisposeOnClose"...
    Pourquoi la JFrame libérée reste sur les valeurs "true", pour "!=null" et "isDisplayable()"?

    2/ Puis-je personnaliser le code effectué à la fermeture de la fenetre, pou y ajouter un variable de classe, qui passerait alors à false, et que je surveillerai pour mon thread?
    Dois-je utiliser "overide"? Comment trouver la bonne syntaxe?

    Merci à ceux qui auront tenu jusqu'au bout....

  2. #2
    Membre confirmé

    Homme Profil pro
    Enseignant
    Inscrit en
    Février 2020
    Messages
    178
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Février 2020
    Messages : 178
    Par défaut disposeOnClose vs exitOnClose
    Apparement, le constante "DISPOSE_ON_CLOSE", supprime le cadre de la jFrame, mais ne met pas fin à l'application.
    La JFrame est toujours un objet défini. Seul le "isDisplayable()" semble passer à false. (du fait de la suppression du cadre certainement?...)

    Dans mon cas en effet, à la fermeture de la fenêtre :

    - si je teste
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (RunTest.anim && RunTest.fenetre1 != null){
    le thread continue, en affichant "true", à la question "la fenetre est-elle définie?"

    - si je teste
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (RunTest.anim && RunTest.fenetre1.isDisplayable()){
    le thread s'arrete, donc la condition n'est plus vraie, la JFrame n'est plus affichable..


    Avec "EXIT_ON_ClOSE", on sort vraiment de l'application. De fait, avec ce choix, la fermeture de ma fenêtre principale, entraîne une fermeture des threads enfants de cette fenêtre. Ce choix semble le plus pertinent pour que tout se ferme si la fenêtre principale et fermée.

  3. #3
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 908
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 908
    Billets dans le blog
    54
    Par défaut
    Suggestion : utiliser un Timer Swing plutôt qu'un Thread. Cependant, si tu tiens vraiment a utiliser un Thread, ca marche aussi mais il faut faire un peu plus attention a ce que tu fais.

    Je rappelle que AWT et Swing utilisent un thread évènementiel nomme EDT (Event Dispatch Thread - fil de propagation d’événements) pour a la fois propager les évenements utilisateur dans l'UI mais aussi gérer tout ce qui est affichage. Ce thread oscille constament entre ces 2 fonctions :
    • Propagation des events ;
    • Gestion de l'affichage.

    Il est donc recommandé, quand on fait des choses pour bidouiller la presentation, de les faire sur l'EDT. Il est possible de faire certaines interactions avec des composant Swing depuis un autre thread, mais c'est pas vraiment recommandé.
    Donc déjà, il faudrait en fait remplacer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (clignotant) {
       RunTest.jlabels[q].setBackground(Color.red);
    }
    else {
       RunTest.jlabels[q].setBackground(Color.WHITE);
    }

    Par :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SwingUtilities.invokeLater(() -> {
        RunTest.jlabels[q].setBackground(clignotant ? Color.RED : Color.WHITE);
        RunTest.jlabels[q].repaint();
    });
    Mais bon a la rigueur vu ce que fait ce thread, autant ne pas se casser la tête et utiliser un Timer Swing. Avec cette classe tu es tout le temps sur que l'action se déroule dans l'EDT.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import javax.swing.Timer;
     
    final var blinkTimer = new Timer(500, event -> {
        RunTest.jlabels[q].setBackground(clignotant ? Color.RED : Color.WHITE));
        RunTest.jlabels[q].repaint();
        clignotant = !clignotant;
    });
    blinkTimer.setRepeats(true);
    blinkTimer.start();
    Note que, a l'inverse, Les taches non-graphiques de longue durée doivent être faites sur un thread externe pour ne pas bloquer l'EDT (syndrome de "mon UI est figée et répond plus aux clics utilisateurs"). Cependant la classe SwingWorker existe pour faire ce genre de choses sans devoir coder un thread a mano.

    Mais ceci ne règle pas pour autant ton soucis. En effet meme avec Timer, le programme continue de tourner a la fermeture de la fenêtre. Dans ton cas c'est car ton thread tourne toujours et dans mon cas c'est car le Timer tourne toujours. Il faut donc prendre soin de bien terminer ces operations avant de tenter de sortir.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    mport javax.swing.*;
    import java.awt.*;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.util.Objects;
    import java.util.Optional;
     
    public final class Main {
        private Timer blinkTimer;
        private boolean blink = false;
     
        public static void main(final String... args) {
            SwingUtilities.invokeLater(Main::launchAtEDT);
        }
     
        private static void launchAtEDT() {
            new Main().createUI();
        }
     
        private void createUI() {
            final var content = new JPanel();
            content.setMinimumSize(new Dimension(500, 500));
            content.setPreferredSize(new Dimension(800, 600));
            final var startButton = new JButton("Start");
            startButton.addActionListener(event1 -> {
                // Le timer existe et tourne donc il faut l'arreter et revenir aux reglages d'origine.
                if (!Objects.isNull(blinkTimer) && blinkTimer.isRunning()) {
                    startButton.setText("Start");
                    blinkTimer.stop();
                    content.setBackground(null);
                    content.repaint();
                    blink = false;
                } else {
                    startButton.setText("Pause");
                    // Le timer n'existe pas encore, on va le creer.
                    if (Objects.isNull(blinkTimer)) {
                        blinkTimer = new Timer(500, event2 -> {
                            content.setBackground(blink ? Color.RED : null);
                            content.repaint();
                            blink = !blink;
                        });
                        blinkTimer.setRepeats(true);
                    }
                    // Demarrage de l'animation.
                    blinkTimer.start();
                }
            });
            final var toolBar = new JToolBar();
            toolBar.add(startButton);
            final var frame = new JFrame("Test");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            // On s'assure de bien terminer le timer.
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent event) {
                    Optional.ofNullable(blinkTimer)
                            .ifPresent(Timer::stop);
                }
            });
            frame.setLayout(new BorderLayout());
            frame.add(toolBar, BorderLayout.NORTH);
            frame.add(content, BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
        }
    }
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [EXCEL] Validation des données saisies - nouvelle Question :-)
    Par Paloma dans le forum Macros et VBA Excel
    Réponses: 39
    Dernier message: 29/11/2006, 13h28
  2. Quelle(s) technique(s) ... Nouvelle question ...
    Par miniil dans le forum Général Conception Web
    Réponses: 4
    Dernier message: 27/01/2006, 15h03
  3. [Debutant] Nouvelle question sur les pointeurs
    Par etiennegaloup dans le forum Débuter
    Réponses: 3
    Dernier message: 11/01/2006, 09h55
  4. [Static] nouvelle question sur les blocs static
    Par Alec6 dans le forum Langage
    Réponses: 2
    Dernier message: 25/11/2004, 18h09
  5. Nouvelle question Excel OLE
    Par sbeu dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 04/10/2004, 19h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo