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

Interfaces Graphiques en Java Discussion :

Listener pour un point


Sujet :

Interfaces Graphiques en Java

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut Listener pour un point
    Bonsoir,

    Je travaille actuellement sur une interface graphique pour un gros projet.
    L'utilisateur pourra interagir avec l'interface grâce à ses mouvements (il y a une kinect dans le projet)

    Un sous programme permet de donner la position de la main de l'utilisateur.

    J'aimerais faire un listener pour la main qui permettrait de détecter si la main reste 3 seconde dans une certaine zone.
    Les tutos que je vois sur internet pour creer des listener reposent tous sur des listeners deja existant. Là je n'ai pas vraiment d'idée.

    Une idée ?

    Merci beaucoup

  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 : 56
    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,

    Ta question concerne la mise en œuvre d'un "listener" en général, en en particulier pour kinect ?

    Pour le cas général, on procède simplement comme suit :

    • On fait une interface qui constitue le listener
      • le mieux est de faire une interface (personnellement, je préfère toujours faire une interface fonctionnelle, à une méthode donc, ce qui permet d'utiliser les lambdas pour l'implémentation de l'écouteur), qui permettra de réagir aux évenements
      • On peut soit
        • avoir en argument les informations qui permettent de savoir qui à produit le changement d'état, la valeur de l'état, l'ancienne valeur de l'état éventuellement, etc.
        • Mieux, faire une classe qui réprésente l'évenement, et y mettre les informations nécessaires (ce qui permet de faire évoluer plus facilement le code sans impact, et qui plus simple à écrire/lire
    • Dans la classe qui produit les changements d'états
      • On fait une méthode pour enregistrer un écouteur
        • Dans le cas général, on stocke les listeners dans une List<interface de listener>
      • On fait une méthode qui permet de retirer un écouteur d'évenement
      • Une méthode qui permet de lancer l'évenement
        • On parcourt les listeners et on invoque la méthode
        • Eventuellement, on prévoit une exécution thread-safe (qui permet d'ajouter ou supprimer un listener, et de lancer l'évenement, dans différents threads concurrents, mais ce n'est pas forcément indispensable
        • Il peut être avantageux de prévoir une gestion d'exception par handler externe (UncaughtExceptionHandler) afin d'éviter une rupture de l'envoi des évenements à plusieurs listeners, si l'un d'eux produisait des exceptions.


    Voici un exemple, avec une classe qui contient un état, dont on veut écouter les changements de valeurs :

    La classe qui représente l'évenement :
    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
    public class MonEvenement {
     
    	private final Object source;
    	private final int ancienEtat;
    	private final int nouvelEtat;
     
    	public MonEvenement(Object source, int ancienEtat, int nouvelEtat) {
    		this.source=source;
    		this.ancienEtat=ancienEtat;
    		this.nouvelEtat=nouvelEtat;
    	}
     
    	public final Object getSource() {
    		return source;
    	}
     
    	public final int getAncienEtat() {
    		return ancienEtat;
    	}
     
    	public final int getNouvelEtat() {
    		return nouvelEtat;
    	}
     
    }
    L'interface pour l'écouteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    @FunctionalInterface
    public interface IMonListener {
     
    	void changementEtat(MonEvenement evenement);
     
    }
    La classe qui produit le changement d'état (en mode synchrone, pour de l'asynchrone, on peut utiliser un Executor pour traiter le fireEvent):
    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
    public class MonProducteurDEvenements {
     
    	private final List<IMonListener> monEvenementlisteners;
     
    	private int etat;
     
    	public MonProducteurDEvenements() {
    		monEvenementlisteners = new ArrayList<>();
    	}
     
    	public void setEtat(int nouvelEtat) {
    		int ancientEtat = this.etat;
    		this.etat=nouvelEtat;
    		fireEvent(ancientEtat, nouvelEtat); // on lance l'événement qui indique que l'état a changé
    	}
     
    	public int getEtat() {
    		return etat;
    	}
     
            // enregistrement écouteur
    	public void ajouterMonListener(IMonListener listener) {
    		Objects.requireNonNull(listener, "un listener ne doit pas être null");
    		synchronized (monEvenementlisteners) {
    		    if ( monEvenementlisteners.contains(listener) ) {
    		    	monEvenementlisteners.add(listener);
    		    }
    		}
    	}
     
            // arrêt de l'écoute
    	public void retirerMonListener(IMonListener listener) {
    		synchronized (monEvenementlisteners) {
    		    monEvenementlisteners.remove(listener);
    		}
    	}
     
            // envoi de l'événement aux écouteurs
    	private void fireEvent(int ancienEtat, int nouvelEtat) {
    		MonEvenement evenement = new MonEvenement(this, ancienEtat, nouvelEtat);
    		synchronized (monEvenementlisteners) {
    			for( IMonListener listener : monEvenementlisteners ) {
    				listener.changementEtat(evenement);
    			}
    		}
    	}
     
    }
    Dans ton cas, je suppose que la kinect produit elle-même des événements : tu peux sur écoute de ces évenements, générer d'autres évenements qui spécialisent l'action résultant. Pour la durée de 3 secondes, je ne sais pas comment ces évenements sont écoutables dans l'API de la kinect : si ce n'est pas prévu nativement, il te faudra chronométrer toi-même. Tu peux éventuellement utiliser un Timer pour ça : à la réception l'évenement kinect qui correspond à la détection de la main, tu lances une TimerTask avec un délai de 3 secondes, qui lance le fireEvent. Quand tu reçois l'évenement qui dit que la détection de la main n'est plus active, tu annules la timertask.
    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
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Merci beaucoup
    Ca m'a quand même l'air pas mal compliqué.
    Je regarde tout ça et je vous tient au courant
    Encore merci !

  4. #4
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    J'ai bien regardé votre code. Je l'ai compris.

    Ce qui genere l'évênement en gros c'est la méthode setEtat.

    Le problème que je me pose c'est comment utiliser ce code. Il existera une méthode getPosition qui renvoie la position de la main.

    Faut il alors faire quelque chose du type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while(true){
    if(mainDansLaZone(getPosition()))
       setEtat(...)
    }
     
    // la méthode mainDansLaZone renvoie un bouléan qui est vrai si la position de la main est dans la zone voulue.
    Cette boucle infinie ne m'inspire pas grand chose. C'est bien ce qu'il faut faire ?

  5. #5
    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 : 56
    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
    C'était juste un exemple général : le problème c'est que je ne sais pas comment est faite ton API Kinect, donc je peux difficilement de donner des indications plus spécifiques. C'est quoi déjà comme API ? J4K ?
    C'est quoi mainDansLaZone() ? C'est une méthode à toi ? Quel est son code ? Ne repose-t-elle pas sur un système évènementiel ? Ce serait préférable à une boucle while(true) qui va consommer du cpu à rien faire qu'attendre...

    Moi, je vois un système avec 2 évènements :
    • main dans la zone
    • main hors de la zone


    Et faire :
    • Quand "main dans la zone", lancer timer, delai 3 secondes
    • Quand "main hors de la zone", annuler timer
    • quand timer se déclenche, lancer évenement "main dans la zone pendant 3 secondes)
    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.

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Merci pour la réponse

    pour la méthode mainDansLaZone() c'est codé comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public boolean mainDansLaZone(Point p){
         return(p.getX()<maxX && p.getX()>minX && p.getY()<maxY && p.getY()> minY)
    }
    sachant que la zone dont on parle est un rectangle compris entre minX et maxX pour x et minY et maxY pour y

    dans le programme j'utilise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    mainDansLaZone(getPosition()) // sachant que getPosition donne un Point (les coo de la main)
    Pour la kinect je ne sais pas quelle API est utilisée (ce n'est pas ma partie). Le problème étant que le sous programme Kinect est codé en C++ (on utilise des Pipes pour communiquer entre le java et la C++)

  7. #7
    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 : 56
    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
    Il te faut observer l'appartenance de la position dans la zone à intervalle régulier (java.util.Timer) et faire ce que je te t'ai dit plus haut (lancer une autre TimerTask lorsque la main est dans la zone et qui envoie l'évenement avec un délai de 3 sec, avec annulation de la TimerTask lorsque la main sort de la zone.

    Ça pourrait donner ça :

    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    public class MainDansLaZoneEventProducer {
     
    	private final Rectangle zone; // la zone à observer
    	private final long time; // la durée d'observation avant d'envoyer l'évenement en ms
    	private final long period; // la période d'observation (on teste la position toutes les period ms)
    	private final TrucKinect trucKinect; // la classe avec la méthode getPosition()
    	private AtomicBoolean started; // indique que l'observation est démarrée
    	private ExecutorService executor; // pour déléguer l'exécution de l'envoi de l'évenement aux écouteurs (pour éviter de bloquer timer)
     
    	private Timer timerObserver; // le timer qui sert à observer la position de la main
    	private Timer timerEvent; // le timer qui permet d'envoyer l'évenement au bout du temps time
     
    	private final List<IMainDansLaZoneListener> listeners; // la liste des écouteurs
     
    	private final Runnable fireEventTask; // la tâche qui envoie l'évenement
     
     
    	/**
             * 
             * @param zone la zone à tester
             * @param time 
             * @param period
             */
    	public MainDansLaZoneEventProducer(TrucKinect trucKinect, Rectangle zone, long time, long period) {
    		this.zone=zone;
    		this.time=time;
    		this.period=period;
    		this.trucKinect=trucKinect;
    		this.started=new AtomicBoolean(false);
    		this.listeners=new ArrayList<>();
    		this.fireEventTask=()-> fireEvent();
    	}
     
    	/**
             * Démarrer l'observation
             */
    	public void start() {
    		if ( started.compareAndSet(false, true) ) {
    			executor = Executors.newSingleThreadExecutor();
    			timerObserver=new Timer();
    			timerEvent=new Timer();
    			timerObserver.schedule(new TimerTask(){
     
    				private boolean mainDansLaZone;
    				private TimerTask timerTask;
     
    				@Override
    				public void run() {
    					final Point position = trucKinect.getPosition();
    					if ( position!=null && zone.contains( position ) ) { // test si la main est dans la zone
    						if ( !mainDansLaZone ) { // si on a déjà détecté, on ne fait rien
    							mainDansLaZone=true; // sinon on relève qu'on a détecter la main dans la zone
    							// on lance la tâche qui attend avant d'envoyer l'évenement
    							timerTask = new TimerTask() { // on lance la tâche qui attend que la main est restée suffisemment longtemps
     
    								@Override
    								public void run() {
    									fireEvent();
    								}
     
    								private void fireEvent() {
    									executor.execute(fireEventTask);
    								}
     
    							};
    							timerEvent.schedule(timerTask, time);
    						}
    					}
    					else {
    						if ( mainDansLaZone ) { // si on n'est pas dans la zone et qu'on avait été dans la zone
    							mainDansLaZone=false; // on relève qu'on est plus dans la zone
    							timerTask.cancel(); // on annule la tâche qui attend
    						}
    					}
    				}
     
    			}, period, period);
    		}
    	}
     
    	/**
             * Arrêter l'observation
             */
    	public void stop() {
    		if ( started.compareAndSet(true, false) ) {
    			executor.shutdownNow();
    			timerEvent.cancel();
    			timerObserver.cancel();
    		}
    	}
     
    	/**
             * Pour ajouter un écouteur
             * @param listener
             */
    	public void addListener(IMainDansLaZoneListener listener) {
    		Objects.requireNonNull(listener,"Listener can't be null");
    		synchronized( listeners ) {
    			if ( !listeners.contains(listener) ) {
    				listeners.add(listener);
    			}
    		}
    	}
     
    	/**
             * Pour enlever un écouteur
             * @param listener
             */
    	public void removeListener(IMainDansLaZoneListener listener) {
    		synchronized( listeners ) {
    			listeners.remove(listener);
    		}
    	}
     
    	private void fireEvent() {
    		synchronized( listeners ) { // on parcourt tous les listeners et on leur envoie l'événement
    			for(IMainDansLaZoneListener listener : listeners) {
    				listener.mainDansLaZone();
    			}
    		}
    	}
     
    	public interface IMainDansLaZoneListener {
     
    		void mainDansLaZone();
     
    	}
     
    }
    Dans cette classe, j'ai découplé la classe avec la méthode getPosition() que j'ai applée KinectTruc parce que je ne connaissais pas le nom de ta classe. Dans cette version, il faut sortir de la zone et y entrer à nouveau pour que l'évenement soit soulevé à nouveau. Il est important d'appeler la méthode start() pour démarrer l'écoute.

    Pour te montrer comment l'utiliser, j'ai fait un petit POC, où la main est simulée par la souris et la kinect par un JPanel :

    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    public class MainDansLaZoneTest extends JPanel {
     
    	private static final long TIME = 3000; // le temps d'attente = 3 secondes
    	private static final long PERIOD = 100; // la période d'observation (toutes les 100 ms)
     
    	private final Rectangle rectangle; // stocke la zone (pour la dessiner)
    	private volatile Point mousePoint; // stocke la position de la souris = la position de la main
    	private AtomicBoolean mainDansLaZone=new AtomicBoolean(); // un état pour savoir qu'on a valider "main dans la zone pendant 3 secondes"
     
    	// sert à afficher un compte à rebours (pour la démo)
    	private volatile int counter;
    	private Timer counterTimer;
    	private TimerTask counterTask;
    	private AtomicBoolean counterStarted=new AtomicBoolean();
    	private boolean started;
     
     
    	public MainDansLaZoneTest(Rectangle rectangle) {
    		this.counterTimer = new Timer();
    		this.rectangle=rectangle;
    		// simulation de la détection de la main dans la zone = tes classes C++ de gestion de la kinect
    		addMouseMotionListener(new MouseAdapter() {
     
    			@Override
    			public void mouseMoved(MouseEvent e) {
    				if ( !e.getPoint().equals(mousePoint) ) {
    					mousePoint = e.getPoint();
    					repaint();
    				}
    			}
     
    			@Override
    			public void mouseExited(MouseEvent e) {
    				if ( mousePoint!=null ) {
    					mousePoint=null;
    					stopCounter();
    					repaint();
    				}
    			}
    		});
    	}
     
    	@Override
    	public Point getMousePosition() throws HeadlessException {
    		Point point = super.getMousePosition();
    		if ( point!=null && rectangle.contains(point) ) {
    			startCounter();
    		}
    		else {
    			stopCounter();
    		}
    		return point;
    	}
     
    	public Point getMousePoint() {
    		Point point = super.getMousePosition();
    		if ( point!=null && rectangle.contains(point) ) {
    			startCounter();
    		}
    		else {
    			stopCounter();
    		}
    		return point;
    	}
     
    	private void startCounter() {
    		if ( counterStarted.compareAndSet(false, true) ) {
    			counter=(int)TIME/1000;
    			counterTask = new TimerTask() {
     
    				@Override
    				public void run() {
    					counter--;
    					if ( counter==0 ) cancel();
    					repaint();
    				}
    			};
    			counterTimer.schedule(counterTask, 1000, 1000);
    			repaint();
    		}
    	}
     
    	private void stopCounter() {
    		if ( counterStarted.compareAndSet(true, false) ) {
    			if ( counterTask!=null) counterTask.cancel();
    			counter=0;
    			repaint();
    		}
    	}
     
    	public void setStarted(boolean started) {
    		if ( this.started!=started) {
    			this.started=started;
    			if ( !started ) {
    				stopCounter();
    			}
    			repaint();
    		}
    	}
     
    	@Override
    	protected void paintComponent(Graphics g) {
    		super.paintComponent(g);
    		if ( started ) {
    			if ( mousePoint!=null && rectangle.contains(mousePoint) ) {
    				if ( mainDansLaZone.get() ) {
    					g.setColor(Color.GREEN); // on affiche la zone en vert quand la souris est dans la zone et qu'on reçu l'événement
    				}
    				else {
    					g.setColor(Color.YELLOW); // on affiche la zone en jaunne quand la souris est dans la zone
    				}
    			}
    			else {
    				g.setColor(Color.CYAN);
    			}
    			g.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
    			if ( mousePoint!=null ) {
    				g.setColor(Color.BLACK);
    				g.drawLine(mousePoint.x-1, mousePoint.y, mousePoint.x+1, mousePoint.y);
    				g.drawLine(mousePoint.x, mousePoint.y-1, mousePoint.x, mousePoint.y+1);
    			}
    			if ( counter>0 ) {
    				g.setColor(Color.BLACK);
    				String counterString = String.valueOf(counter);
    				int size = g.getFont().getSize();
    				FontMetrics fm = g.getFontMetrics();
    				Rectangle2D stringBounds = fm.getStringBounds(counterString, g);
    				double scale = rectangle.getHeight()/size;
    				AffineTransform scaleTransform = AffineTransform.getScaleInstance(scale, scale);
    				stringBounds = scaleTransform.createTransformedShape(stringBounds).getBounds2D();
    				Rectangle2D bounds = new Rectangle2D.Double(0, 0, rectangle.width, rectangle.height);
    				AffineTransform transform = AffineTransform.getTranslateInstance(rectangle.x + (int)((bounds.getWidth()-stringBounds.getWidth())/2), rectangle.y /*+ (int)((bounds.getHeight()-stringBounds.getHeight())/2)*/);
    				transform.concatenate(scaleTransform);
    				((Graphics2D)g).setTransform(transform);
    				g.drawString(counterString, 0, fm.getAscent()-fm.getDescent());
    			}
    		}
    		else {
    			g.setColor(Color.DARK_GRAY);
    			g.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
    		}
    	}
     
    	public void setMainDansLaZone(boolean mainDansLaZone) {
    		if ( this.mainDansLaZone.compareAndSet(!mainDansLaZone, mainDansLaZone) ) {
    			repaint();
    		}
    	}
     
    	public static void main(String[] args) {
     
    		SwingUtilities.invokeLater(()-> run());
     
    	}
     
    	private static void run() {
     
    		// création de l'UI
    		JFrame frame = new JFrame("Démo");
    		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
     
    		frame.setSize(600, 400);
    		frame.setLocationRelativeTo(null);
     
    		Rectangle zone = new Rectangle( 300, 100, 150, 100); // zone d'observation
     
    		MainDansLaZoneTest panel = new MainDansLaZoneTest(zone); // simulation de kinect
     
    		MainDansLaZoneEventProducer eventProducer = new MainDansLaZoneEventProducer(
    				new TrucKinect() {
    					@Override
    					public Point getPosition() {
    						return panel.getMousePoint();
    					}
    		}, zone, TIME, PERIOD);
     
    		// enregistrement de l'écouteur
    		eventProducer.addListener(()-> {
     
    			// ici on fait le code qu'on veut faire quand la main entre dans la zone
    			System.out.printf("Main dans la zone pendant %d seconde(s)%n", TIME/1000);
     
    			panel.setMainDansLaZone(true);
    			new Thread(){
    				public void run() {
    					try {
    						Thread.sleep(1000);
    						panel.setMainDansLaZone(false);
    					} catch (InterruptedException e) {
    					}
    				}
    			}.start();
    		});
     
    		JPanel mainPanel = new JPanel();
    		mainPanel.setLayout(new BorderLayout());
    		mainPanel.add(panel, BorderLayout.CENTER);
     
    		JCheckBox checkBox = new JCheckBox("Ecoute active");
    		checkBox.addChangeListener(e-> {
    			if ( checkBox.isSelected() ) {
    				eventProducer.start();
    				panel.setStarted(true);
    			}
    			else {
    				eventProducer.stop();
    				panel.setStarted(false);
    			}
    		});
    		mainPanel.add(checkBox, BorderLayout.SOUTH);
     
    		frame.getContentPane().add(mainPanel);
     
    		// important : il faut démarrer le composant et l'arrêter
    		// ici on démarre quand la fenêtre est ouverte, et on arrête quand elle est fermée
    		frame.addWindowListener(new WindowAdapter() {
     
    			@Override
    			public void windowOpened(WindowEvent e) {
    				eventProducer.start();
    				panel.setStarted(true);
    				checkBox.setSelected(true);
    			}
     
    			@Override
    			public void windowClosed(WindowEvent e) {
    				eventProducer.stop();
    				System.exit(0);
    			}
     
    		});
     
    		frame.setVisible(true);
     
    	}
     
    }
    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.

  8. #8
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Merci enormément
    Ca marche très bien !

    Je vais essayer maintenant de comprendre le code
    Encore merci

  9. #9
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    J'ai bien lu le code. J'ai pas tout compris mais je pense avoir saisi l'essentiel.

    J'essaye actuellement de l'adapter pour notre projet. Le petit soucis est que les zones qui nous interessent sont des boutons (JButton)

    La classe MainDansLaZoneTest étant une sous classe de JPanel, lorsque j'essaye d'integrer vos classes aux miennes, le JPanel de MainDansLaZoneTest "cache"
    le bouton.

    Pensez vous que l'on puisse adapter votre code pour qu'il puisse au seins d'une JFrame existante (possedant des boutons) afficher un du texte à l'écran dès que l'utilisateur à la main au niveau du bouton ? (Chaque JFrame possède une ArrayList qui contient tous les boutons qu'elle contient).

    L'idéal mais pas du tout nécessaire serait que durant ces 3 secondes le boutons ait l'air enfoncé

    Si vous avez quelques pistes pour m'aider à integrer votre code au miens je vous en serait très reconnaissant

  10. #10
    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 : 56
    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
    MainDansLaZoneTest c'est juste pour tester et pour avoir un exemple de comment on crée une MainDansLaZoneEventProducer et comment on s'enregistre comme écouteur de celui-ci, et vérifier que ça fonctionne, mais avec une souris à la place de la kinect... On peut complètement s'en passer. Il vaut mieux d'ailleurs.

    Le principe d'avoir fait un générateur d'évènements, c'est justement de faire ce qu'on veut sur réception de l'évènement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // enregistrement de l'écouteur
    		eventProducer.addListener(()-> {
     
                         bouton.doClick();
     
    		});
    Va faire que ça clique sur le bouton (une instance de JButton) quand la main est restée 3 secondes dans la zone.

    Donc, dans ta JFrame, avec tes JButton, crée un MainDansLaZoneEventProducer et enregistre un écouteur !

    Tu peux lui changer son texte, avec bouton.setText("Truc"), ou n'importe quoi d'autre, mais uniquement lorsque le main est restée trois secondes dans la zone. C'était ta question à l'origine, donc j'ai répondu à celle-là.

    Maintenant, si tu veux faire correspondre les boutons avec des zones, et afficher quelque chose dans le bouton (ou à côté, peu importe), ou lui changer sa couleur ou que sais-je, quand la main entre dans la zone, tu peux le faire aussi, mais pas en l'état. Il faut ajouter un évènement qui dit on entre dans la zone, et probablement un autre pour dire la main sort de la zone, sinon le changement fait sur le bouton va rester (sauf si tu as un timer qui le remet en place, mais ça va compliquer inutilement).

    Dans MainDansLaZoneTest, ce n'est pas le producteur ou l'écouteur d'évenements qui gère le passage en jaune, ou le compteur, c'est MainDansLaZoneTest, qui est un simulateur pour tester que MainDansLaZoneEventProducer fonctionne. MainDansLaZoneTest simule la kinect avec la souris, et simule une UI. Impossible de l'utiliser en l'état pour faire ce que tu veux faire. Et, en plus, c'est bien plus simple de ne pas le faire.

    Il suffit uniquement de modifier MainDansLaZoneEventProduceur pour qu'elle produise trois type d'évènements. Il faut que l'écouteur puisse reconnaître le type d'évènement. J'ai fait ça avec un enum. Ce qui permet d'écrire maintenant :


    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
     
     
         button = new JButton("Machin truc");
     
         ...
     
         Rectangle zone = button.getBounds(); // alors là ça pose un (petit) problème (voir après le code)
     
         MainDansLaZoneEventProducer buttonEventProducer= new MainDansLaZoneEventProducer(
    				kinect
    		, zone, TIME, PERIOD);
     
    		buttonEventProducer.addListener((type)-> {
     
                        switch( type ) {
                             case ENTER: // on entre la zone
                                  button.setBackground(Color.GREEN); // je passe le bouton en vert lorsque je rentre dans la zone
                                  break;
                              case HIT; // si la main est restée 3 secondes
                                  button.setBackground(null); // je remets la valeur par défaut de LAF (sinon il va rester en vert)
                                  button.doClick(); // je clique le bouton
                                  break;
                               case EXIT; // si la main sort (attention avec ce que j'ai fait, elle sort toujours, même si elle est restée 3 secondes...
                                  button.setBackground(null); // je remets la valeur par défaut de LAF
                                  break;
                        }
     
     
    		});
    Le problème dont je parle au sujet des bounds de JButton, est relatif à la façon de faire le layout des boutons. Le layout des boutons est fait

    • soit automatiquement par LayoutManager, et donc fait après l'affichage de la fenêtre (donc on ne peut pas connaitre les bounds ici, ce qui est problématique pour MainDansLaZoneEventProducer qui a besoin de la zone pour être construit), et chaque fois qu'on change la taille de la fenêtre, donc la position et la taille du bouton peuvent changer, ce qui n'est pas possible avec la classe que j'ai faite. Il faut la modifier pour que la zone puisse varier et détecter avec un ComponentListener les déplacements et changement de taille du bouton. mais en plus, il faut gérer l'interaction avec le timer qui observer la zone : que se passe t il si on a commencér à détecter la main dans la zone et la zone bouge avant les 3 secondes : est-ce qu'on recommence à zéro le chrono, ou on annule seulement si la zone va si loin que la main en sort ? Il y a des petites adaptations à faire. La gestion du enter et du exit en dépend d'ailleurs.
    • Soit vous faite le layout à la main : si les positions des boutons sont fixées, c'est facile il suffit de les récupérer comme j'ai indiqué pour faire la zone, sinon ii faut faire tout ce que j'ai dit pour le cas de layout par layoutmanager


    Ensuite, pour que le bouton ai l'air enfoncé, le problème est que c'est un rendu qui est de la responsabilité du LaF (Look and Feel) : on y a pas accès à priori (j'ai jamais cherché à le faire, mais je ne pense pas). Il est peut être possible de faire ça avec la classe java.awt.Robot, mais je n'ai jamais essayé, et je ne sais pas si le rendu du JButton suit. Essayez donc avec la classe Robot.



    Voici le code modifié du producteur d'évenement :

    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    public class MainDansLaZoneEventProducer {
     
    	public enum Type {
    		ENTER,
    		HIT,
    		EXIT
    	}
     
    	private final Rectangle zone; // la zone à observer
    	private final long time; // la durée d'observation avant d'envoyer l'évenement en ms
    	private final long period; // la période d'observation (on teste la position toutes les period ms)
    	private final TrucKinect trucKinect; // la classe avec la méthode getPosition()
    	private AtomicBoolean started; // indique que l'observation est démarrée
    	private ExecutorService executor; // pour déléguer l'exécution de l'envoi de l'évenement aux écouteurs (pour éviter de bloquer timer)
     
    	private Timer timerObserver; // le timer qui sert à observer la position de la main
    	private Timer timerEvent; // le timer qui permet d'envoyer l'évenement au bout du temps time
     
    	private final List<IMainDansLaZoneListener> listeners; // la liste des écouteurs
     
    	private final Runnable fireHitEventTask; // la tâche qui envoie l'évenement
    	private final Runnable fireEnterEventTask; // la tâche qui envoie l'évenement
    	private final Runnable fireExitEventTask; // la tâche qui envoie l'évenement
     
     
    	/**
             * 
             * @param zone la zone à tester
             * @param time 
             * @param period
             */
    	public MainDansLaZoneEventProducer(TrucKinect trucKinect, Rectangle zone, long time, long period) {
    		this.zone=zone;
    		this.time=time;
    		this.period=period;
    		this.trucKinect=trucKinect;
    		this.started=new AtomicBoolean(false);
    		this.listeners=new ArrayList<>();
    		this.fireHitEventTask=()-> fireEvent(Type.HIT);
    		this.fireExitEventTask=()-> fireEvent(Type.EXIT);
    		this.fireEnterEventTask=()-> fireEvent(Type.ENTER);
    	}
     
    	/**
             * Démarrer l'observation
             */
    	public void start() {
    		if ( started.compareAndSet(false, true) ) {
    			executor = Executors.newSingleThreadExecutor();
    			timerObserver=new Timer();
    			timerEvent=new Timer();
    			timerObserver.schedule(new TimerTask(){
     
    				private boolean mainDansLaZone;
    				private TimerTask timerTask;
     
    				@Override
    				public void run() {
    					final Point position = trucKinect.getPosition();
    					if ( position!=null && zone.contains( position ) ) { // test si la main est dans la zone
    						if ( !mainDansLaZone ) { // si on a déjà détecté, on ne fait rien
    							mainDansLaZone=true; // sinon on relève qu'on a détecter la main dans la zone
    							executor.execute(fireEnterEventTask);
    							// on lance la tâche qui attend avant d'envoyer l'évenement
    							timerTask = new TimerTask() { // on lance la tâche qui attend que la main est restée suffisemment longtemps
     
    								@Override
    								public void run() {
    									fireEvent();
    								}
     
    								private void fireEvent() {
    									if ( mainDansLaZone ) {
    										executor.execute(fireHitEventTask);
    									}
    								}
     
    							};
    							timerEvent.schedule(timerTask, time);
    						}
    					}
    					else {
    						if ( mainDansLaZone ) { // si on n'est pas dans la zone et qu'on avait été dans la zone
    							mainDansLaZone=false; // on relève qu'on est plus dans la zone
    							timerTask.cancel(); // on annule la tâche qui attend
    							executor.execute(fireExitEventTask);
    						}
    					}
    				}
     
    			}, period, period);
    		}
    	}
     
    	/**
             * Arrêter l'observation
             */
    	public void stop() {
    		if ( started.compareAndSet(true, false) ) {
    			executor.shutdownNow();
    			timerEvent.cancel();
    			timerObserver.cancel();
    		}
    	}
     
    	/**
             * Pour ajouter un écouteur
             * @param listener
             */
    	public void addListener(IMainDansLaZoneListener listener) {
    		Objects.requireNonNull(listener,"Listener can't be null");
    		synchronized( listeners ) {
    			if ( !listeners.contains(listener) ) {
    				listeners.add(listener);
    			}
    		}
    	}
     
    	/**
             * Pour enlever un écouteur
             * @param listener
             */
    	public void removeListener(IMainDansLaZoneListener listener) {
    		synchronized( listeners ) {
    			listeners.remove(listener);
    		}
    	}
     
    	private void fireEvent(Type type) {
    		synchronized( listeners ) { // on parcourt tous les listeners et on leur envoie l'événement
    			for(IMainDansLaZoneListener listener : listeners) {
    				listener.mainDansLaZone(type);
    			}
    		}
    	}
     
    	public interface IMainDansLaZoneListener {
     
    		void mainDansLaZone(Type type);
     
    	}
     
    }
    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.

  11. #11
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Merci pour cette réponse très rapide !!

    Je vais dechiffrer le code de ce pas

  12. #12
    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 : 56
    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,

    J'ai regardé pour simuler le bouton enfoncé et c'est beaucoup plus simple que je pensais en SWING : il faut appeler setArmed() et setPressed() sur le modèle du bouton :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    button.getModel().setArmed(true);
    button.getModel().setPressed(true)
    Il faudra juste bien penser à éviter les conflits d'UI : on peut le faire facilement avec un glasspane, ou un JLayer, pour intercepter les évenements de la souris.
    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.

  13. #13
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Je pense avoir réussi à l'integrer au projet.
    Je vous tiens au courant des résultats des tests d'integrations.

    Pour l'integrer finalement j'ai fais une modification dans votre code : votre classe MainDansLaZoneTest est une sous classe de JPanel . J'en ai fait une sous classe de JButton directement.

  14. #14
    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 : 56
    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
    Citation Envoyé par pythagor Voir le message
    J'en ai fait une sous classe de JButton directement.
    Je ne vois pas l'intérêt. La seule chose qui te soit utile dans cette classe, c'est le code qui suit, pour chaque JButton:

    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
    MainDansLaZoneEventProducer eventProducer = new MainDansLaZoneEventProducer(
    				trucKinect // c'est l'instance de votre classe avec la méthode getPosition()
    		}, new Rectangle(button.getLocationOnScreen(), button.getSize()), TIME, PERIOD); // buttonBounds ce sont les bounds du bouton (à priori dans l'écran)
     
    		// enregistrement de l'écouteur
    		eventProducer.addListener( (type)-> {
     
                        switch( type ) {
                             case ENTER: // on entre la zone
                                  button.getModel().setArmed(true);
                                  button.getModel().setPressed(true)
                                  break;
                              case HIT; // si la main est restée 3 secondes
                                  button.getModel().setArmed(false);
                                  button.getModel().setPressed(false);      
                                  button.doClick(); // je clique le bouton
                                  break;
                               case EXIT; // si la main sort (attention avec ce que j'ai fait, elle sort toujours, même si elle est restée 3 secondes...
                                  button.getModel().setArmed(false);
                                  button.getModel().setPressed(false);      
                                  break;
                        }
     
                    })
    Tout le reste, c'est exactement comme n'importe quelle autre JFrame, avec un JPanel et des JButton dedans. Pas besoin de se trimballer tout ce que j'ai fait pour simuler la kinect, le compte à rebours, le hightlight de la zone, etc...
    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.

  15. #15
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Effectivement c'est plus simple
    Je vais essayer
    Merci beaucoup je vous tiens au courant

  16. #16
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Bonsoir,

    J'ai voulu faire un test avec une fenêtre et un seul bouton.
    Tout mon code compile mais cela ne marche pas.
    En restant 3 secondes sur le bouton, rien ne se passe (alors que dans le code en plus de faire un doClik je demande d'afficher "ok" à la console).
    J'ai relu plusieurs fois le code mais je ne vois pas d'ou pourrait provenir le problème.

    Voici mon code ( je ne peux pas utiliser de lambda expressions j'ai du faire quelques modifications pour les remplacer)

    Pour la classe MainDansLaZoneEventProducer
    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    package event;
     
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.atomic.AtomicBoolean;
     
     
    public class MainDansLaZoneEventProducer {
     
    	private final Rectangle zone; 
    	private final long time, period;
    	private final TrucKinect trucKinect; 
    	private AtomicBoolean started; 
    	private ExecutorService executor; 
    	private Timer timerObserver; 
    	private Timer timerEvent; 
    	private final List<Listener> listeners; 
    	//private final Runnable fireEventTask;
    	public enum Type {ENTER,HIT,EXIT}
    	private Runnable fireHitEventTask = new Runnable() {
    		public void run() {
    			fireEvent(Type.HIT);			
    		}
    	};
    	private Runnable fireEnterEventTask= new Runnable() {
     
    		public void run() {
    			fireEvent(Type.ENTER);			
     
    		}
    	};
     
    	private Runnable fireExitEventTask = new Runnable() {
     
    		public void run() {
    			fireEvent(Type.EXIT);			
     
    		}
    	};
     
    	public MainDansLaZoneEventProducer(TrucKinect trucKinect, Rectangle zone, long time, long period) {
    		this.zone = zone;
    		this.time = time;
    		this.period = period;
    		this.trucKinect = trucKinect;
    		this.started = new AtomicBoolean(false);
    		this.listeners = new ArrayList<Listener>();
    		//this.fireEventTask = new Runnable() {public void run() {fireEvent();}};
    	}
     
    	public void start() {
    		if (started.compareAndSet(false, true)) {
    			executor = Executors.newSingleThreadExecutor();
    			timerObserver = new Timer();
    			timerEvent = new Timer();
    			timerObserver.schedule(new TimerTask() {
     
    				private boolean mainDansLaZone;
    				private TimerTask timerTask;
     
    				@Override
    				public void run() {
    					final Point position = trucKinect.getPosition();
    					if (position != null && zone.contains(position)) { 
    						if (!mainDansLaZone) { // si on a déjà détecté, on ne
    												// fait rien
    							mainDansLaZone = true; // sinon on relève qu'on a
    													// détecter la main dans la
    													// zone
    							// on lance la tâche qui attend avant d'envoyer
    							// l'évenement
    							executor.execute(fireEnterEventTask);
    							timerTask = new TimerTask() { // on lance la tâche
    															// qui attend que la
    															// main est restée
    															// suffisemment
    															// longtemps
     
    								@Override
    								public void run() {
    									fireEvent();
    								}
     
    								private void fireEvent() {
    									if(mainDansLaZone)
    									executor.execute(fireHitEventTask);
    								}
     
    							};
    							timerEvent.schedule(timerTask, time);
    						}
    					} else {
    						if (mainDansLaZone) { // si on n'est pas dans la zone et
    												// qu'on avait été dans la zone
    							mainDansLaZone = false; // on relève qu'on est plus
    													// dans la zone
    							timerTask.cancel(); // on annule la tâche qui attend
    							executor.execute(fireExitEventTask);
    						}
    					}
    				}
     
    			}, period, period);
    		}
    	}
     
    	/**
             * Arrêter l'observation
             */
    	public void stop() {
    		if (started.compareAndSet(true, false)) {
    			executor.shutdownNow();
    			timerEvent.cancel();
    			timerObserver.cancel();}}
     
    	public void addListener(IMainDansLaZoneListener listener) {
    		Objects.requireNonNull(listener, "Listener can't be null");
    		synchronized (listeners) {
    			if (!listeners.contains(listener)) {
    				listeners.add((Listener) listener);}}}
     
     
    	public void removeListener(IMainDansLaZoneListener listener) {
    		synchronized (listeners) {
    			listeners.remove(listener);}}
     
    	private void fireEvent(Type type) {
    		synchronized (listeners) { // on parcourt tous les listeners et on leur
    									// envoie l'événement
    			for (IMainDansLaZoneListener listener : listeners) {
    				listener.mainDansLaZone(type);}}}
     
    	public interface IMainDansLaZoneListener {void mainDansLaZone(Type type);}}
    Ma classe TrucKinect

    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
    package event;
     
    import java.awt.Point;
    import javax.swing.JButton;
     
     
    public class TrucKinect {
    	protected JButton bouton;
     
    	public TrucKinect(JButton bouton){this.bouton=bouton;}
     
    	public Point getPosition() {
    		return bouton.getMousePosition();
     
    	}
     
    }
    Ma classe Listener (que j'ai du creer pour ne pas utiliser de Lambda expression mais dont l'interieur est inutil)
    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
    package event;
     
    import event.MainDansLaZoneEventProducer.IMainDansLaZoneListener;
    import event.MainDansLaZoneEventProducer.Type;
     
    public class Listener implements IMainDansLaZoneListener{
     
    	public void mainDansLaZone() {
     
    		// ici on fait le code qu'on veut faire quand la main entre dans la zone
    		System.out.println("Main dans la zone pendant pdt 1 sec");
     
    		MainDansLaZoneTest.button.setMainDansLaZone(true);
    		new Thread(){
    			public void run() {
    				try {
    					Thread.sleep(1000);
    					MainDansLaZoneTest.button.setMainDansLaZone(false);
    				} catch (InterruptedException e) {}
    			}
    		}.start();
    	}
     
    	public void mainDansLaZone(Type type) {}
     
     
     
    }
    Et enfin ma classe pour tester

    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
    package event;
     
    import java.awt.Point;
    import java.awt.Rectangle;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import event.MainDansLaZoneEventProducer.Type;
     
    public class Test {
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame();
    		frame.setVisible(true);
    		final JButton bouton = new JButton("ok");
    		frame.getContentPane().add(bouton);
    		frame.pack();
     
    		MainDansLaZoneEventProducer eventProducer = new MainDansLaZoneEventProducer(
    				new TrucKinect(bouton) {
    					@Override
    					public Point getPosition() {
    						return bouton.getMousePosition();
    					} // c'est l'instance de votre classe avec la méthode getPosition()
    		}, new Rectangle(bouton.getLocationOnScreen(), bouton.getSize()), 1000, 100); // buttonBounds ce sont les bounds du bouton (à priori dans l'écran)
     
     
    		eventProducer.addListener(new Listener(){
    			public void mainDansLaZone(Type type) {
    				switch( type ) {
    			    case ENTER: // on entre la zone
    			        bouton.getModel().setArmed(true);
    			        bouton.getModel().setPressed(true);
    			        break;
    			    case HIT: // si la main est restée 3 secondes
    			        bouton.getModel().setArmed(false);
    			        bouton.getModel().setPressed(false);
    			        bouton.doClick(); // je clique le bouton
    			        break;
    			     case EXIT: // si la main sort (attention avec ce que j'ai fait, elle sort toujours, même si elle est restée 3 secondes...
    			        bouton.getModel().setArmed(false);
    			        bouton.getModel().setPressed(false);      
    			        break;		
    			}
    		}});
     
    	}	
    }
    Avez vous une idée d'où pourrait provenir l'erreur ?

  17. #17
    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 : 56
    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. Problèmes avec Listener et IMainDansLaZoneListener
      1. Tu as fait une classe concrète pour implémenter le listener (la classe Listener qui implémente IMainDansLaZoneListener).
        Pourquoi pas. Mais il ne fallait surtout pas modifier la MainDansLaZoneEventProducer en remplaçant (en partie en plus), la référence à l'interface par la référence à la classe concrète : le composant devient incohérent. Le but de l'interface est de décoréler l'implémentation concréte de l'écouteur : ceci permet d'en faire autant qu'on en veut, sans pour autant que MainDansLaZoneEventProducer soit dépendant de ces implémentations concrètes (ici dépendant parce que faisant directement référence au nom de la classe concrète.
      2. Second problème sur l'implémentation concrète, c'est que tout le code est dans une méthode qui n'existe pas dans l'interface, donc qui ne sera pas appelée de toute manière par la méthode fireEvent() de MainDansLaZoneEventProducer.
        Mais, soit, ce n'est pas pour ça que ça ne fonctionne pas : dans Test, quand tu ajoutes Listener, tu fais une classe anonyme qui étend Listener, où tu implémentes la bonne méthode de IMainDansLaZoneListener, ce qui fait que ça devrait fonctionner, mais...
    2. Il n'y a pas d'ActionListener sur ton bouton. JButton.doClick() simule le clic sur le bouton, mais le code à faire dans le bouton doit être mis dans l'ActionListener, comme d'habitude. L'intérêt de l'implémentation, justement, c'est qu'elle fonctionne avec une JFrame et des JButton normale, qui fonctionne normalement avec la souris. Il n'y a pas d'implémentation spéciale de la JFrame, si ce n'est le lien avec MainDansLaZoneEventProducer, par l'intermédiaire du listener.
    3. Le dernier exemple que je t'ai donné était dans l'hypothèse de fonctionner avec une kinect, en supposant que la classe que tu as pour récupérer la position de la main donne cette position relativement à l'écran (comment pourrait-elle faire autrement, puisqu'elle ne connait ni ta JFrame ni ton JButton). Ceci permet d'être indépendant des 2 côtés (côté kinect et côté GUI Java).
      Pour la simulation de test, utilisant la souris, par contre, il faut convertir la position de la souris sur le bouton dans les coordonnées de l'écran, car JButton.getMousePosition() est relatif au bouton.
    4. Ensuite, il est nécessaire de démarrer MainDansLaZoneEventProducer, qui utilise un Timer pour observer la position de la kinect (celle-ci ne produisant malheureusement pas d'évenement d'après ce que tu m'as dit), un Executor, pour enfiler les différents évenements et garantir leur ordre d'exécution (Les deux doivent être démarré pour fonctionner : l'avantage de l'avoir fait dans une méthode à part et pas dans le constructeur et qu'on peut l'arrêter et le redémarrer à loisir, mais il faut le faire pour que ça fonctionne). Pour la souris, ça ne serait pas nécessaire, puis qu'on pourrait utiliser un MouseMotionListener. Mais ça fonctionne quand même sans MouseMotionListener pour la souris, grace au timer. D'ailleurs le dernier paramètre du constructeur de MainDansLaZoneEventProducer est la période d'observation : tu as mis 100, ce qui veut dire qu'on va demander toutes les 100 millisecondes qu'elle est la position actuelle à TrucKinect. C'est un peu une sorte de temps de réaction minimum du système.


    Attention cette classe c'est juste pour tester sans la kinect, avec la souris : elle ne doit pas figurer dans ton programme à la fin. Tu dois utiliser la classe qu'on a fourni, utilisant du code natif c++. Et, donc, tu devras remplacer le nom TrucKinect dans MainDansLaZoneListener par le nom de ta classe, que je connais toujours pas, et que je peux pas deviner (sinon j'aurais utiliser le même nom).

    Voici les classes modifiées pour que ça fonctionne :

    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    package event;
     
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Objects;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.atomic.AtomicBoolean;
     
    public class MainDansLaZoneEventProducer {
     
    	private final Rectangle zone;
    	private final long time, period;
    	private final TrucKinect trucKinect;
    	private AtomicBoolean started;
    	private ExecutorService executor;
    	private Timer timerObserver;
    	private Timer timerEvent;
    	private final List<IMainDansLaZoneListener> listeners;//=> non : private final List<Listener> listeners;
     
    	public enum Type {
    		ENTER, HIT, EXIT
    	}
     
    	private Runnable fireHitEventTask = new Runnable() {
    		public void run() {
    			fireEvent(Type.HIT);
    		}
    	};
    	private Runnable fireEnterEventTask = new Runnable() {
     
    		public void run() {
    			fireEvent(Type.ENTER);
     
    		}
    	};
     
    	private Runnable fireExitEventTask = new Runnable() {
     
    		public void run() {
    			fireEvent(Type.EXIT);
     
    		}
    	};
     
    	public MainDansLaZoneEventProducer(TrucKinect trucKinect, Rectangle zone,
    			long time, long period) {
    		this.zone = zone;
    		this.time = time;
    		this.period = period;
    		this.trucKinect = trucKinect;
    		this.started = new AtomicBoolean(false);
    		this.listeners = new ArrayList<IMainDansLaZoneListener>();
    	}
     
    	public void start() {
    		if (started.compareAndSet(false, true)) {
    			executor = Executors.newSingleThreadExecutor();
    			timerObserver = new Timer();
    			timerEvent = new Timer();
    			timerObserver.schedule(new TimerTask() {
     
    				private boolean mainDansLaZone;
    				private TimerTask timerTask;
     
    				@Override
    				public void run() {
    					final Point position = trucKinect.getPosition();
    					if (position != null && zone.contains(position)) {
    						if (!mainDansLaZone) { // si on a déjà détecté, on ne
    												// fait rien
    							mainDansLaZone = true; // sinon on relève qu'on a
    													// détecter la main dans la
    													// zone
    							// on lance la tâche qui attend avant d'envoyer
    							// l'évenement
    							executor.execute(fireEnterEventTask);
    							timerTask = new TimerTask() { // on lance la tâche
    															// qui attend que la
    															// main est restée
    															// suffisemment
    															// longtemps
     
    								@Override
    								public void run() {
    									fireEvent();
    								}
     
    								private void fireEvent() {
    									if (mainDansLaZone)
    										executor.execute(fireHitEventTask);
    								}
     
    							};
    							timerEvent.schedule(timerTask, time);
    						}
    					} else {
    						if (mainDansLaZone) { // si on n'est pas dans la zone et
    												// qu'on avait été dans la zone
    							mainDansLaZone = false; // on relève qu'on est plus
    													// dans la zone
    							timerTask.cancel(); // on annule la tâche qui attend
    							executor.execute(fireExitEventTask);
    						}
    					}
    				}
     
    			}, period, period);
    		}
    	}
     
    	/**
             * Arrêter l'observation
             */
    	public void stop() {
    		if (started.compareAndSet(true, false)) {
    			executor.shutdownNow();
    			timerEvent.cancel();
    			timerObserver.cancel();
    		}
    	}
     
    	public void addListener(IMainDansLaZoneListener listener) {
    		Objects.requireNonNull(listener, "Listener can't be null");
    		synchronized (listeners) {
    			if (!listeners.contains(listener)) {
    				listeners.add(listener);
    			}
    		}
    	}
     
    	public void removeListener(IMainDansLaZoneListener listener) {
    		synchronized (listeners) {
    			listeners.remove(listener);
    		}
    	}
     
    	private void fireEvent(Type type) {
    		synchronized (listeners) { // on parcourt tous les listeners et on leur
    									// envoie l'événement
    			for (IMainDansLaZoneListener listener : listeners) {
    				listener.mainDansLaZone(type);
    			}
    		}
    	}
     
    	public interface IMainDansLaZoneListener {
    		void mainDansLaZone(Type type);
    	}
     
    }
    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
    package event;
     
    import java.awt.Point;
     
    import javax.swing.JButton;
    import javax.swing.SwingUtilities;
     
    public class TrucKinect {
    	protected final JButton bouton;
     
    	public TrucKinect(JButton bouton) {
    		this.bouton = bouton;
    	}
     
    	public Point getPosition() {
    		Point point = bouton.getMousePosition();
    		if (point!=null) {
    			SwingUtilities.convertPointToScreen(point,
    					bouton);
    		}
    		return point;
    	}
     
    }
    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
    package event;
     
     
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
     
    import javax.swing.JButton;
    import javax.swing.JFrame;
     
    import event.MainDansLaZoneEventProducer.IMainDansLaZoneListener;
    import event.MainDansLaZoneEventProducer.Type;
     
    public class Test {
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame();
    		frame.setVisible(true);
    		final JButton bouton = new JButton("ok");
    		bouton.addActionListener(new ActionListener() {
     
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("OK : le bouton a été actionné");
    			}
    		});
    		frame.getContentPane().add(bouton);
    		frame.pack();
     
    		final MainDansLaZoneEventProducer eventProducer = new MainDansLaZoneEventProducer(
    				new TrucKinect(bouton),
    				new Rectangle(bouton.getLocationOnScreen(), bouton.getSize()), 1000, 100); // buttonBounds ce sont les bounds du bouton (à priori dans l'écran)
     
    		// alternative 1 : classe anonyme
    		eventProducer.addListener(new IMainDansLaZoneListener() {
    			public void mainDansLaZone(Type type) {
    				switch( type ) {
    			    case ENTER: // on entre la zone
    			    	System.out.println("enter");
    			        bouton.getModel().setArmed(true);
    			        bouton.getModel().setPressed(true);
    			        break;
    			    case HIT: // si la main est restée 3 secondes
    			    	System.out.println("hit");
    			        bouton.getModel().setArmed(false);
    			        bouton.getModel().setPressed(false);
    			        bouton.doClick(); // je clique le bouton
    			        break;
    			     case EXIT: // si la main sort (attention avec ce que j'ai fait, elle sort toujours, même si elle est restée 3 secondes...
    				    	System.out.println("exit");
    			        bouton.getModel().setArmed(false);
    			        bouton.getModel().setPressed(false);      
    			        break;		
    			}
    		}});
     
    		//ou alors alternative 2 : classe concrete Listener
    		// eventProducer.addListener(new Listener(bouton));
     
    		eventProducer.start();
     
    		frame.addWindowListener(new WindowAdapter() {
    			@Override
    			public void windowClosed(WindowEvent e) {
    				eventProducer.stop();
    			}
    		});
     
    	}	
    }
    Si tu veux utiliser une implémentation externe concrète de IMainDansLaZoneListener (voir les commentaires que j'ai mis dans Test - alternative 1 & 2) :

    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
    package event;
     
    import javax.swing.JButton;
     
    import event.MainDansLaZoneEventProducer.IMainDansLaZoneListener;
    import event.MainDansLaZoneEventProducer.Type;
     
    public class Listener implements IMainDansLaZoneListener {
     
    	private JButton bouton;
     
    	public Listener(JButton bouton) {
    		this.bouton=bouton;
    	}
     
    	public void mainDansLaZone(Type type) {
    		switch( type ) {
    	    case ENTER: // on entre la zone
    	        bouton.getModel().setArmed(true);
    	        bouton.getModel().setPressed(true);
    	        break;
    	    case HIT: // si la main est restée 3 secondes
    	        bouton.getModel().setArmed(false);
    	        bouton.getModel().setPressed(false);
    	        bouton.doClick(); // je clique le bouton
    	        break;
    	     case EXIT: // si la main sort (attention avec ce que j'ai fait, elle sort toujours, même si elle est restée 3 secondes...
    	        bouton.getModel().setArmed(false);
    	        bouton.getModel().setPressed(false);      
    	        break;		
    		}
    	}
     
    }
    Un exemple avec plusieurs boutons et checkbox (ce qui m'a obligé à faire un petit changement dans TrucKinect) :

    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    package event;
     
     
    import java.awt.GridLayout;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
     
    import javax.swing.AbstractButton;
    import javax.swing.JButton;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
     
    import event.MainDansLaZoneEventProducer.IMainDansLaZoneListener;
    import event.MainDansLaZoneEventProducer.Type;
     
    public class Test {
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame();
    		JPanel panel = new JPanel();
    		panel.setLayout(new GridLayout(0,1));
    		final JButton bouton1 = new JButton("ok");
    		panel.add(bouton1);
    		bouton1.addActionListener(new ActionListener() {
     
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("OK : le bouton 1 a été actionné");
    			}
    		});
    		final JButton bouton2 = new JButton("bouton 2");
    		panel.add(bouton2);
    		bouton2.addActionListener(new ActionListener() {
     
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("OK : le bouton 2 a été actionné");
    			}
    		});
    		final JCheckBox checkbox = new JCheckBox("Une check box...");
    		panel.add(checkbox);
    		checkbox.addActionListener(new ActionListener() {
     
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("OK : la sélection de la checkbox a changé");
    			}
    		});
     
    		frame.getContentPane().add(panel);
    		frame.pack();
    		frame.setLocationRelativeTo(null);
     
    		frame.setVisible(true);
     
    		final MainDansLaZoneEventProducer eventProducerButton1 = createEventProducer(bouton1, 1000);
    		final MainDansLaZoneEventProducer eventProducerButton2 = createEventProducer(bouton2, 1000);
    		final MainDansLaZoneEventProducer eventProducerCheckbox = createEventProducer(checkbox, 1000);
     
    		//ou alors alternative 2 : classe concrete Listener
    		// eventProducer.addListener(new Listener(bouton));
     
    		frame.addWindowListener(new WindowAdapter() {
    			@Override
    			public void windowClosed(WindowEvent e) {
    				eventProducerButton1.stop();
    				eventProducerButton2.stop();
    				eventProducerCheckbox.stop();
    			}
    		});
     
    		eventProducerButton1.start();
    		eventProducerButton2.start();
    		eventProducerCheckbox.start();
     
    	}
     
    	private static MainDansLaZoneEventProducer createEventProducer(
    			AbstractButton bouton, final long time) {
    		final MainDansLaZoneEventProducer eventProducer = new MainDansLaZoneEventProducer(
    				new TrucKinect(bouton),
    				new Rectangle(bouton.getLocationOnScreen(), bouton.getSize()), time, 100); // buttonBounds ce sont les bounds du bouton (à priori dans l'écran)
     
    		eventProducer.addListener(new IMainDansLaZoneListener() {
    			public void mainDansLaZone(Type type) {
    				switch( type ) {
    			    case ENTER: // on entre la zone
    			    	System.out.println("enter");
    			        bouton.getModel().setArmed(true);
    			        bouton.getModel().setPressed(true);
    			        break;
    			    case HIT: // si la main est restée 3 secondes
    			    	System.out.println("hit");
    			        bouton.getModel().setArmed(false);
    			        bouton.getModel().setPressed(false);
    			        bouton.doClick(); // je clique le bouton
    			        break;
    			     case EXIT: // si la main sort (attention avec ce que j'ai fait, elle sort toujours, même si elle est restée 3 secondes...
    				    	System.out.println("exit");
    			        bouton.getModel().setArmed(false);
    			        bouton.getModel().setPressed(false);      
    			        break;		
    			}
    		}});
    		return eventProducer;
    	}	
    }
    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
    package event;
     
    import java.awt.Point;
     
    import javax.swing.AbstractButton;
    import javax.swing.SwingUtilities;
     
    public class TrucKinect {
    	protected final AbstractButton bouton;
     
    	public TrucKinect(AbstractButton bouton) {
    		this.bouton = bouton;
    	}
     
    	public Point getPosition() {
    		Point point = bouton.getMousePosition();
    		if (point!=null) {
    			SwingUtilities.convertPointToScreen(point,
    					bouton);
    		}
    		return point;
    	}
     
    }
    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.

  18. #18
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Encore merci Vous êtes génial !

    Tout Marche dans mon projet (avec la souris).
    Les classes en C++ de la Kinect ne sont pas encore terminées (ce n'est pas moi qui les code)
    Je vous tient au courant pour la réele integration avec la Kinect

  19. #19
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2015
    Messages
    33
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2015
    Messages : 33
    Par défaut
    Bonjour,

    Il y a en fait un problème assez bizarre
    Il arrive environ une fois sur deux (sans changer ni recompiller le programme) que les listeners sur les boutons ne marchent pas.

    J'ai fais pas mal de tests pour essayer de comprendre à quoi c'est du.
    J'ai finalement trouvé le problème (mais pas la solution) :

    Dans le contructeur de MainDansLaZoneEventProducer, il y un Rectangle qui est initialisé avec bouton.getLocation() et bouton.getSize()

    Cependant en faisant System.out.println(bouton.getHeight()) j'obtiens parfois 0. J'ai l'impression qu'il faut un certain temps après que le bouton soit mis sur la fenêtre pour que ses longueures et largeurs soient actualisées

    J'ai essayé de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    while(bouton.getHeight==0);
    addHandListener(bouton);//méthode correspondant à l'ajout du listener
    pour laisser un peu plus de temps. Le beug apparait moins mais il apparait tout de même de temps en temps

    Je vous donne un exemple pour une des fenêtres :

    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    package fenetres;
     
    import javax.swing.JFrame;
     
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Container;
    import java.awt.Frame;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
     
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
     
    public class FenetreCatalogue extends Fenetre implements ActionListener{
     
     
     
    		private static final long serialVersionUID = 1L;
    		private ArrayList<JButton> boutonListe = new ArrayList<JButton>();
    		private JButton tShirtButton = new JButton("T Shirt");
    		private JButton pullButton = new JButton("Pull");
    		private JButton robeButton = new JButton("Robe");
    		private JButton pantalonButton = new JButton("Pantalon");
    		private JButton quitterButton= new JButton("Quitter");
    		private JButton retourButton = new JButton("Retour");
    		private JButton voirPanierButton = new JButton("Voir le Panier");
    		private JButton supprimerButton = new JButton("Supprimer Compte");
    		private JPanel catalogue = new JPanel();
    		private String userName;
     
     
    		private JPanel bouttons = new JPanel();
     
    		public FenetreCatalogue(String userName) {
    			this.userName =userName;
    			setUndecorated(true);
    			setVisible(true); // affichage
    			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    			JLabel image = new JLabel(new ImageIcon("data/vetements.jpg"));
     
    			// Utilisation de BorderLayout
    			Container contenu = getContentPane();
    			contenu.setLayout(new BorderLayout());
    			contenu.setBackground(new Color(255, 255, 255));
     
     
    			//Ajouts des bouttons sur buttons
    			bouttons.add(retourButton);
    			bouttons.add(voirPanierButton);
    			bouttons.add(supprimerButton);
    			bouttons.add(quitterButton);
    			bouttons.setBackground(new Color(255,255,255));
    			boutonListe.add(tShirtButton);
    			boutonListe.add(pullButton);
    			boutonListe.add(robeButton);
    			boutonListe.add(pantalonButton);
     
     
     
    			//Ajout des Listeners
    			for(JButton bouton : boutonListe )
    				bouton.addActionListener(this);
    			quitterButton.addActionListener(this);
    			voirPanierButton.addActionListener(this);
    			retourButton.addActionListener(this);
    			supprimerButton.addActionListener(this);
     
    			//Configuration du panneau catalogue
     
    			catalogue.setLayout(new GridLayout(2,2));
    			catalogue.setBackground(new Color(255,255,255));
    			catalogue.add(tShirtButton);
    			catalogue.add(pullButton);
    			catalogue.add(pantalonButton);
    			catalogue.add(robeButton);
     
    			//Ajouts sur le ContentPane
    			contenu.add(image, BorderLayout.PAGE_START);
    			contenu.add(bouttons,BorderLayout.PAGE_END);
    			contenu.add(catalogue,BorderLayout.CENTER);
     
     
    			this.setExtendedState(Frame.MAXIMIZED_BOTH);
    			while(tShirtButton.getHeight()==0); 
    			for (JButton bouton : boutonListe)
    				addHandListener(bouton);
    			addHandListener(retourButton);
    			addHandListener(voirPanierButton);
    			addHandListener(quitterButton);
    			addHandListener(supprimerButton);
    		}
     
    		public void tShirt(){
    			dispose();
    			new FenetreChoixVetement(userName,"tshirt");
    		}
    		public void robe(){
    			dispose();
    			new FenetreChoixVetement(userName,"robe");		
    		}
    		public void pantalon(){
    			dispose();
    			new FenetreChoixVetement(userName,"pantalon");		
    		}
    		public void pull(){
    			dispose();
    			new FenetreChoixVetement(userName,"pull");		
    		}
    		public void retour(){
    			dispose();
    			new FenetreIdentification();
    		}
    		public void voirPanier(){
    			dispose();
    			new FenetreVisualisation(userName);
     
    		}
    		/********* getUser renvoie l'arrayList des noms d'utilisateurs*********/
    		public ArrayList<String> getUser(){
    			ArrayList<String> usersList = new ArrayList<String>();
    			try {
    				InputStream ips = new FileInputStream("users/utilisateurs.txt");
    				InputStreamReader ipsr = new InputStreamReader(ips);
    				BufferedReader br = new BufferedReader(ipsr);
    				String userName;
    				while ((userName = br.readLine()) != null) {
    					usersList.add(userName);
    				}
    				br.close();
    			} catch (Exception e) {
    				System.out.println(e.toString());
    			}
    			return usersList;
     
    		}
     
    		public void supprimerPanier(String userName){ //Supprime le fichier panierUser.txt
    			File panier = new File("users/panier" + userName + ".txt");
    			panier.delete();
    		}
     
    		/******* Methode génerale pour supprimer un utilisateur*****/
    		public void supprimer(String userName){
    			ArrayList<String> usersList = this.getUser();
    			try {
    				new FileWriter(new File("users/utilisateurs.txt")).close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
     
    			FileWriter writer = null;
    			try {
    				writer = new FileWriter("users/utilisateurs.txt", true);
    				for (int i = 0; i < usersList.size(); i++) {
    					if (!(usersList.get(i).equals(userName))) {
    						writer.write(usersList.get(i) + "\n");
    					}
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			} finally {
    				if (writer != null) {
    					try {
    						writer.close();
    					} catch (IOException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    			supprimerPanier(userName);
    			dispose();
    			new FenetreIdentification();
    		}
     
     
    		public void actionPerformed(ActionEvent e) {
     
    			if(e.getSource()==tShirtButton)
    				tShirt();
    			else if(e.getSource()==robeButton)
    				robe();
    			else if(e.getSource()==pantalonButton)
    				pantalon();
    			else if(e.getSource()==pullButton)
    				pull();
    			else if(e.getSource()== retourButton)
    				retour();
    			else if(e.getSource()==quitterButton)
    				System.exit(0);
    			else if(e.getSource()==voirPanierButton)
    				voirPanier();
    			else if (e.getSource()==supprimerButton)
    				supprimer(userName);
     
    		}
     
    	}
    Cette classe herite de Fenetre qui est simplement une fenêtre avec la methode d'ajout du listener

    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
    package fenetres;
     
    import java.awt.Rectangle;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import javax.swing.*;
    import event.MainDansLaZoneEventProducer;
    import event.TrucKinect;
    import event.MainDansLaZoneEventProducer.IMainDansLaZoneListener;
     
    public abstract class Fenetre extends JFrame implements ActionListener {
     
    	private static final long serialVersionUID = 1L;
     
    	/*public Fenetre(){
    		setUndecorated(true);
    		setVisible(true); 
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		this.setExtendedState(Frame.MAXIMIZED_BOTH);
     
     
    	}*/
     
    	public void addHandListener(final JButton bouton) {
    		final MainDansLaZoneEventProducer eventProducer = new MainDansLaZoneEventProducer(new TrucKinect(bouton),
    				new Rectangle(bouton.getLocationOnScreen(), bouton.getSize()), 1000, 100); 
     
     
    		// alternative 1 : classe anonyme
    		eventProducer.addListener(new IMainDansLaZoneListener() {
    			public void mainDansLaZone(MainDansLaZoneEventProducer.Type type) {
    				switch (type) {
    				case ENTER: // on entre la zone
    					System.out.println("enter");
    					bouton.getModel().setArmed(true);
    					bouton.getModel().setPressed(true);
    					break;
    				case HIT: // si la main est restée 3 secondes
    					System.out.println("hit");
    					bouton.getModel().setArmed(false);
    					bouton.getModel().setPressed(false);
    					bouton.doClick(); // je clique le bouton
    					break;
    				case EXIT: // si la main sort (attention avec ce que j'ai fait,
    							// elle sort toujours, même si elle est restée 3
    							// secondes...
    					System.out.println("exit");
    					bouton.getModel().setArmed(false);
    					bouton.getModel().setPressed(false);
    					break;
    				}
    			}
    		});
     
    		// ou alors alternative 2 : classe concrete Listener
    		// eventProducer.addListener(new Listener(bouton));
     
    		eventProducer.start();
     
    		this.addWindowListener(new WindowAdapter() {
    			@Override
    			public void windowClosed(WindowEvent e) {
    				eventProducer.stop();
    			}
    		});
     
    	}
    }
    J'ai vraiment l'impression que le problème vient uniquement du fait qu'après avoir mis le bouton sur la fenêtre, il garde des dimensions vide et donc que la zone que le producteur d'event doit controller est vide.

    Savez vous comment l'on pourrait corriger ce problème ?

  20. #20
    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 : 56
    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,

    Je n'ai pas regardé ton code, mais je pense que ça vient probablement d'un problème de thread. Le traitement de l'UI et du layouting, va faire que la taille du bouton va être calculée dans le thread SWING (EDT). Si tu instancies le générateur d'évènements avant que le bouton ait été dimensionné et affiché, ça ne fonctionnera pas.

    Par exemple, si tu fais dans le thread main :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    créer la fenêtre
    créer le producteur d'événement avec la taille du bouton
    démarrer le producteur d'événement
    le code swing nécessaire pour "réaliser" la première partie va s'exécuter en parallèle, et donc les parties suivantes vont s'exécuter trop tôt (puisqu'immédiatement après la première partie)

    Solution 1 : tout faire sur le thread SWING, avec SwingUtilities.invokeLater()
    Solution 2 : créer et démarrer le producteur quand l'UI est prête (affichée et dimensionnée), comme j'ai fait dans mon exemple (pack() puis setVisible()), donc dans l'EDT, ou sur évenement de l'UI
    Solution 4 : Utiliser ComponentListener pour mettre à jour le rectangle (solution la plus générique, mais demande quelques modifications dans le producteur)
    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.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [3D] matrice de déformation pour un point de vue décalé
    Par mou013 dans le forum Développement 2D, 3D et Jeux
    Réponses: 3
    Dernier message: 04/02/2006, 19h29
  2. [Débutant] Listener pour une entrée dans le presse papier.
    Par Silvio02 dans le forum Général Java
    Réponses: 6
    Dernier message: 08/01/2006, 23h44
  3. Quel listener pour l'édition d'une JTable?
    Par ®om dans le forum Composants
    Réponses: 4
    Dernier message: 11/05/2005, 22h13
  4. [JSP]comment créer un listener pour ma base de données
    Par Ekimasu dans le forum Servlets/JSP
    Réponses: 14
    Dernier message: 10/05/2004, 15h49

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