mercredi 14 février 2018

[Java][Swing][Débutant] Lier deux fenêtres (JFrame)

En concevant une application graphique (swing), nous effectuons, souvent, le choix de créer une fenêtre principale (la mère de toutes les autres fenêtres) et plusieurs fenêtres secondaires (des fenêtres filles) selon les cas d'utilisation de notre système.
Une application de Chat, à titre d'exemple, peut utiliser ce schéma. La classe principale contiendra la liste des amis et les actions globales (Se connecter, Se déconnecter, Ajouter contact, etc..). Chaque fenêtre secondaire (fille) sera dédiée pour une conversation avec un ami. Ainsi, il faut créer autant de fenêtre filles que de conversation en cours.
Dans ce Code Simple, je vais essayer de présenter l'une parmi plusieurs autres idées pour garder le lien entre la fenêtre file et sa mère (la fenêtre principale).
L'idée que je présente est utilisée même au sein de la JDK. Voyons l'exemple :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ExempleDialogue {
 
 static JFrame f;
 
 public static void main (String args[]) {
  
  f = new JFrame();
  f.setSize(500, 250);
  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  
  JButton b = new JButton("Exemple");
  b.addActionListener(ExempleDialogue::actionPerformed);
  
  f.add(b, BorderLayout.CENTER);
  f.setVisible(true);
  
 }
 
 public static void actionPerformed(ActionEvent e){
  JOptionPane.showMessageDialog(f, "Exemple");
 }
 
}



Dans ce code, nous pouvons voir que la fenêtre fille (dans ce cas la boîte de dialogue) doit recevoir sa mère comme un paramètre. Dans ce cas, la classe mère est utilisée comme référence pour positionner la boîte de dialogue et pour gérer la modalité des fenêtres.
Nous pouvons recréer cette solution dans un exemple plus global. Ainsi, nous avons besoin de deux fenêtres. La première fenêtre est la fenêtre mère qui doit recevoir une information à partir de ses filles. La deuxième fenêtre est la classe fille qui doit pouvoir envoyer des informations vers sa mère.
Ainsi,la première fenêtre sera :

class Fenetre1 extends JFrame implements ActionListener {

 JLabel message;
 JButton afficher;
 
 public Fenetre1(){
  
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setTitle("Mère");
  
  message = new JLabel("No current message ...");
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Afficher");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }

}


Cette fenêtre a comme rôle l'affichage d'un message en utilisant le JLabel. Le message doit être reçu à partir d'une fenêtre fille :


class Fenetre2 extends JFrame implements ActionListener {

 JTextField message;
 JButton afficher;
 
 public Fenetre2(){
  
  setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  setTitle("Fille");
  
  message = new JTextField();
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Envoie Message");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }
 
}


Cette fenêtre permet de lire un message. Il nous reste de créer le lien. Cela se fait en deux étapes :

1. Ajouter un mécanisme de récepetion des donées dans la classe mère :


 public void setMessage(String m){
  message.setText(m);
 }


2. Ajouter une référence dans la classe fille pour pouvoir se rappeller de sa mère. Cette référence est utilisée pour le


class Fenetre2 extends JFrame implements ActionListener {

 // ...
 
 Fenetre1 parent;
 
 public Fenetre2(Fenetre1 p){

  //...
  parent = p;
                //...

        }

 public void actionPerformed(ActionEvent ae){
  parent.setMessage(message.getText());
 }

        //...

Le code finale sera ainsi :


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class LierDeuxFenetres {
 
 public static void main (String args[]) {
  (new Fenetre1()).setVisible(true);
 }
}

class Fenetre1 extends JFrame implements ActionListener {

 JLabel message;
 JButton afficher;
 
 public Fenetre1(){
  
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setTitle("Mère");
  
  message = new JLabel("No current message ...");
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Afficher");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }
 
 public void setMessage(String m){
  message.setText(m);
 }
 
 public void actionPerformed(ActionEvent ae){
  (new Fenetre2(this)).setVisible(true);
 }
}

class Fenetre2 extends JFrame implements ActionListener {

 JTextField message;
 JButton afficher;
 
 Fenetre1 parent;
 
 public Fenetre2(Fenetre1 p){
  
  parent = p;
  
  setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  setTitle("Fille");
  
  message = new JTextField();
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Envoie Message");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }
 
 public void actionPerformed(ActionEvent ae){
  parent.setMessage(message.getText());
 }
}

Démo rapide :