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

Java Discussion :

Problème de KeyListener et de Thread


Sujet :

Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Cimentage
    Inscrit en
    Septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Septembre 2014
    Messages : 44
    Par défaut Problème de KeyListener et de Thread
    Bonjour à tous,

    J'essaie de créer une petite application dotée d'un serveur ( certes réduit à son minimum usage, mais fonctionnel ) qui reçoit la variable "send" incrémentée à chaque fois que le Client appui sur la touche du haut du clavier ( VK_UP ).

    Le serveur est en mode console.

    Le Client quant à lui, est une fenêtre JFrame qui intègre une JPanel ( la classe Connexion ) qui lui-même fait appel à une classe nommée " Test " qui fait office de Thread dans la classe Connexion.

    Le problème, c'est que le serveur détecte bien la connexion du Client, mais lorsque j'appuie sur la touche du haut du clavier ( VK_UP ) depuis le Client, il ne se passe strictement rien.. Aucune incrémentation de la variable "send", rien ne s'envoi sur le serveur..

    La classe Connexion :

    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
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
     
    import javax.swing.JPanel;
     
    public class Connexion extends JPanel {
     
        int send = 0;
        boolean envoi = false;
     
        public Connexion(){
            this.setFocusable(true);
            this.addKeyListener(new Test());
            Thread Execute = new Thread(new Test());
            Execute.start();
        }
    }
    La classe Test :

    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
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
     
    public class Test extends Thread implements KeyListener {
     
        int send = 0;
        boolean envoi = false;
     
     
        public void run() {
     
            try{
     
                Socket s = new Socket("localhost",1234);
     
                while (true){
     
                Thread.sleep(3);
     
                OutputStream os = s.getOutputStream();
                InputStream is = s.getInputStream();
     
                    if (envoi){
                    	send++;
                        os.write(send);
                    }
     
                    int rep = is.read();
                    System.out.println(rep);
                }
     
            }catch(Exception E) {}
     
        }
     
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_UP){
                    System.out.println("Compteur interne : "+send);
                envoi = true;
            }
        }
     
        public void keyReleased(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_UP){
                envoi = false;
            }
        }
     
        public void keyTyped(KeyEvent e) {}
     
     
        }
    Dans cette classe Test, on dirait que ce code qui est compris dans un While(true){ n'est pas pris en compte lorsque j'appuie sur la touche VK_UP, la variable send ne s'incrémente pas et ne s'envoie pas sur le serveur, voici le bout de code en question sensé incrémenter et envoyer la variable send au serveur..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
                    if (envoi){
                    	send++;
                        os.write(send);
                    }

    Je n'arrive pas à comprendre pourquoi, merci de bien vouloir m'éclairer cher(s) passionné(s) ! :-)

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    1. Tu as 2 instances de Test : dans l'une envoi est modifié lorsqu'on appuie sur une touche. Dans l'autre, envoi ne change jamais.
    2. Ton thread fait :
      1. se connecter à un serveur
      2. ouvrir le stream d'écriture
      3. tester envoi qui est faux, donc pas d'écriture dans l'ouputstream
      4. lecture du inputstream donc attente jusqu'à ce que le serveur écrive dedans = ton thread est à priori bloqué, puisque je doute que ton serveur écrive dans la socket du client s'il ne reçoit rien du client.
    3. il faudrait au moins afficher les erreurs dans le catch, sinon, s'il y a des erreurs tu ne le sauras pas
    4. comment est fait ton serveur ? Qu'est-ce qu'il lui permet de savoir que le client a envoyer l'ensemble de son message, et qu'il doit répondre ?
    5. attention, par ailleurs, lorsque 2 threads manipulent (modifie d'un côté, lit de l'autre) la même variable, il faut soit synchroniser, soit la rendre volatile, sinon la modification faite par un thread peut ne pas être "vue" par l'autre.
    6. je te laisse pour l'instant voir pour faire fonctionner ça déjà, répondre sur le fonctionnement du serveur, et te laisse observer ce qu'il se passe
    7. pour la suite, indice : au lieu de faire un thread qui tourne continuellement (une pause de 3 ms, c'est rien), fais plutôt un système du type observeur/observé. Le thread client doit pouvoir envoyer à son rythme, et le KeyListener stocker les datas à envoyer au sien.
    8. pense également à bien fermer les flux que tu ouvres, libérer les ressources en général (fermer les sockets),
    9. Accessoirement, tu peux regarder cet exemple de client/serveur.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre averti
    Homme Profil pro
    Cimentage
    Inscrit en
    Septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Septembre 2014
    Messages : 44
    Par défaut
    Salut Joel.Drigo ! :-)

    Adorable ta grande réponse rapide !

    Alors, j'ai bien passé en revue tout ce que tu m'as dit, j'ai rendu visible dans un premier temps l'erreur potentiel liée à mon Try-Catch dans le run() de ma classe Connexion avec printStackTrace(), rien à signaler lors de l'exécution.. J'ai tenté de retirer mon is.read(); de manière à voir si c'est cela qui bloquait mon programme.. Que nenni! Rebelote..

    J'ai tenté de rendre la variable boolean envoi volatile, cela n'a rien changé non plus.. je crois que c'est surtout une mauvaise gestion de la modification de mes variables avec KeyListener, modification qui ne semble pas prise en compte dans ma boucle infinie ..La boucle doit être surement , en effet comme tu l'as dit, bloquée.. Depuis hier après-midi je me déglingue les neurones pour trouver une solution, j'ai essayé une multitdes de techniques diverses & variées mais qui se sont toutes révélées, au final, assez foireuses

    Voici le code du serveur au fait :

    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
     
    import java.net.*;
    import java.io.*;
     
    public class Server {
     
    	public static void main(String[] args) {
     
    		int msg;
     
    		try{
     
    		ServerSocket ss = new ServerSocket(1234);
     
    		System.out.println("Attente d'un client...");
    		Socket s = ss.accept();
    		System.out.println("Client connecté.");
     
    		while(true){
     
    		OutputStream os = s.getOutputStream();
    		InputStream is = s.getInputStream();
     
    		msg = is.read();
    		System.out.println(msg);
    		os.write(msg);
     
    		if ( s.isClosed() ){
    			System.out.println("Terminé..");
    		}
     
    		}
     
    		}catch(IOException IOE){}
    	}
     
    }
    Le problème viendrait-il de mon JPanel côté Client et de la manière dont j'exécute mon Thread et dont j'ajoute une écoute clavier avec la même classe ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        public Connexion(){
            this.setFocusable(true);
            this.addKeyListener(new Test());
            Thread Execute = new Thread(new Test());
            Execute.start();
        }
    Thanks again !

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    1. Si j'ai parlé en premier du problème de la double instance de Test, c'était parce que c''était un problème important de ton programme, le principale en fait avec le problème de blocage de boucle du thread client, le reste étant que ce n'est juste pas la meilleure façon de faire pour que ça fonctionne bien, efficacement, dans toutes les conditions, et sans bouffer un max de cpu.

      La solution pour n'avoir qu'une seule instance :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
       
      Test test=new Test();
      this.addKeyListener(test);
      Thread Execute = new Thread(test);
      Pour que tu comprennes bien le souci, simplifions tes classes en enlevant la problématique de transmission réseau, de thread, de keylistener. Ce qui fait qu'on a plus que l'attribut envoi.

      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
      67
      68
      69
      70
      71
      public class Test {
       
      	private boolean envoi;
       
      	public Test() {
      	}
       
      	public void setEnvoi(boolean envoi) {
      		this.envoi = envoi;
      	}
       
      	@Override
      	public String toString() {
      		return String.valueOf(envoi); // quand on affiche l'instance de Test, on
      										// voit la valeur de envoi, ce qui
      										// suffit pour la dmonstration
      	}
       
      	public static void main(String[] args) {
       
      		demo2InstancesDifferentes();
      		demo1SeuleUniqueInstance();
       
      	}
       
      	private static void demo2InstancesDifferentes() {
      		// je créé 2 instances différentes de Test
      		Test demo1 = new Test();
      		Test demo2 = new Test();
       
      		demo(demo1, demo2);
       
      	}
       
      	private static void demo1SeuleUniqueInstance() {
      		// je créé 1 instance de Test
      		Test demo = new Test();
       
      		// j'ai toujours mes deux variables mais je leur donne pour valeur "la même instance"
      		Test demo1 = demo;
      		Test demo2 = demo;
       
      		demo(demo1, demo2);
       
      	}
       
      	private static void demo(Test demo1, Test demo2) {
       
      		if (demo1 == demo2) {
      			System.out.println("demo1 et demo2 sont la même instance d'objet de classe Test");
      		} else {
      			System.out.println("demo1 et demo2 sont 2 instances différentes d'objet de classe Test");
      		}
       
      		// je modifie envoi dans demo1
      		demo1.setEnvoi(true);
      		// j'affiche les 2 instances
      		System.out.println("j'affiche ");
      		System.out.println("- demo1: " + demo1);
      		System.out.println("- demo2: " + demo2);
      		if (demo1.envoi == demo2.envoi) {
      			// s'il sont égaux, c'est bien que demo2.envoi a aussi changé
      			System.out.println("demo2.envoi a bien changé");
      		} else {
      			// s'il sont différents, c'est que demo2.envoi n'a pas changé
      			System.out.println("demo2.envoi n'a pas changé");
      		}
       
      	}
       
      }
      Une instance d'objet, c'est un individu dans une population de même type d'élément, un des représentant. Il peut être reconnu de plusieurs façons, les variables (en général, attribut/variable de classes, variable locale, argument de méthode... éventuellement (mais pas bien) variable statique(partagée donc)). Et par ces variables, être connu à plusieurs endroits. La modifier à un endroit modifie qu'une seul attribut envoi (le même pour la même instance, connue de différentes variables). Si, on a plusieurs instances, les attributs envoi sont différents, modifier l'un ne modifie pas l'autre.

      C'est comme toi et moi : on est 2 instances d'être humain, reconnu sous différents identiants, notre vrai nom, notre pseudo Developpez, nos différentes adresses email, tweeter, ou autre, etc. Si on m'envoie un mail, ce n'est pas toi qui le reçois. Mais quelque soit l'adresse email qu'on emploie pour t'envoyer un mail, tant que c'est l'une des tiennes, tu le reçois.
    2. Ton serveur a pratiqueement les mêmes soucis que ton client.
      • le catch vide (sans affichage des erreurs)
      • une boucle infinie où on récupère sans arrêt les mêmes streams. ça va fonctionner globalement parce que tu n'utilises pas de buffer, et que le read() sur l'ouputstream attend que le client écrive dans son outputstream (ce qui fera que le read() du client ne sera plus bloquant mais seulement si le client envoie quelque chose : ça c'est pour dire qu'il ne fallait pas retirer le read() dans Test, mais le déplacer dans le if(envoi)).
      • pas de fermetures de socket (et la gestion de celle du client (qui n'est pas faite côté client) ne fait pas grand chose, et les conditions pour qu'elle le fasse sont tellement peu probable que ça ne sert à rien (il faudrait que le client soit déconnecté juste après avoir échangé))
      • c'est peut-être voulu mais ton serveur ne gère qu'un seul et unique client.

    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre averti
    Homme Profil pro
    Cimentage
    Inscrit en
    Septembre 2014
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Cimentage
    Secteur : Associations - ONG

    Informations forums :
    Inscription : Septembre 2014
    Messages : 44
    Par défaut
    Merci INFINIMENT Joel ! :-D

    En déclarant directement une classe test en utilisant cette dernière pour l'écoute clavier et pour le thread, ça marche PARFAITEMENT bien !!!

    Je suis le plus heureux des hommes, merci encore à toi en tout cas, tu m'as expliqué ça d'une manière réellement pro et efficace :-)

    Pour tous ceux et celles qui seraient éventuellement confronté au même type de problème dans le futur, je vous donne le code source complet et fonctionnel ( cette fois-ci avec la flèche haut on incrémente et avec la flèche basse on décrémente, avec un thread.sleep histoire de ne pas incrémenter 80 unité d'un coup à chaque appui de touche ! )
    Cela vous servira peut-être de "base de chez base" pour éventuellement commencer à prog un Pong en réseau ( mon but actuellement ).

    Code du serveur : inchangé ( donc le même code que celui posté plus haut ).

    Code de ma classe " Test.java " légèrement amélioré :

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
     
    public class Test extends Thread implements KeyListener {
     
        int y = 0;
        boolean sendUp = false;
        boolean sendDown = false;
        int rep;
     
        public void run() {
     
            try{
     
                Socket s = new Socket("localhost",1234);
     
                while (true){
     
                OutputStream os = s.getOutputStream();
                InputStream is = s.getInputStream();
     
                    if (sendUp){
                    	y++;
                    	Wait(100);
                    		os.write(y);
                    		rep = is.read();
                        System.out.println(rep);
                    }
     
                    if (sendDown){
                    	y--;
                    	Wait(100);
                    		os.write(y);
                    		rep = is.read();
                    	System.out.println(rep);
                    }
     
                }
     
            }catch(IOException IOE) { IOE.printStackTrace(); }
     
        }
     
        public void Wait(int value){
        	try{
        		Thread.sleep(value);
        	}catch (Exception e) { System.out.println("Erreur de Thread.Sleep"); }
        }
     
        public int getY(){ return y; }
     
    	public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_UP){
                sendUp = true;
            }
            if (e.getKeyCode() == KeyEvent.VK_DOWN){
                sendDown = true;
            }
        }
     
        public void keyReleased(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_UP){
                sendUp = false;
            }
            if (e.getKeyCode() == KeyEvent.VK_DOWN){
                sendDown = false;
            }
        }
     
        public void keyTyped(KeyEvent e) {}
     
     
        }
    Code de ma classe "Connexion.java" sans la grossière erreur d'avant :

    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
    import java.awt.Graphics;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
     
    import javax.swing.JPanel;
     
    public class Connexion extends JPanel {
     
    	Test test = new Test();
     
        public Connexion(){
            this.setFocusable(true);
            this.addKeyListener(test);
            Thread Execute = new Thread(test);
            Execute.start();
        }
     
        public void run(){
        	while(true){
        		this.repaint();
        	}
        }
     
        public void paint(Graphics G){
        	G.drawString(String.valueOf(test.getY()), 20, 20);
        }
    }
    Et enfin, le code Main :

    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
     
    import java.net.*;
    import java.util.Scanner;
     
    import javax.swing.JFrame;
     
    import java.io.*;
     
    public class Main {
     
    	public static void main(String[] args) {
     
    		Connexion co = new Connexion();
     
    		JFrame fen = new JFrame("Client");
     
    		fen.setSize(600,400);
    		fen.setResizable(false);
    		fen.setDefaultCloseOperation(fen.EXIT_ON_CLOSE);
     
    		fen.setContentPane(co);
    		fen.setVisible(true);
     
    	}
     
    }
    En espérant en avoir, du coup, aidé d'autres à mon tour :-)

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

Discussions similaires

  1. Problème de KeyListener
    Par Link3 dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 02/05/2006, 18h21
  2. Aide Probléme Connxion ADSL
    Par amazircool dans le forum Dépannage et Assistance
    Réponses: 4
    Dernier message: 19/03/2006, 23h09
  3. Aide: Problème avec la taille de mon fichier
    Par ATTIA dans le forum Langage
    Réponses: 6
    Dernier message: 15/03/2006, 10h19
  4. de l'aide, problème avec lecteur CD/graveur
    Par princetn dans le forum Périphériques
    Réponses: 2
    Dernier message: 18/02/2006, 06h37
  5. [JFrame] Problème de KeyListener
    Par lanfeustdetroll dans le forum Agents de placement/Fenêtres
    Réponses: 9
    Dernier message: 04/07/2005, 18h32

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