Catedra de Telecomunicatii                   

 18/12/2007                   

                      Programare Orientata spre Obiecte (POO)  

 

 

 

Laborator 5

Interfete grafice cu utilizatorul (GUI). Tratarea evenimentelor. Aplicatii bazate pe socket-uri flux (TCP) Java

 

5.1. Descrierea laboratorului

 

In aceasta lucrare de laborator vor fi acoperite urmatoarele probleme:

 

- Aplicatii client-server bazate pe socket-uri TCP care folosesc mostenirea (II)

 

- Interfete grafice cu utilizatorul (GUI), Interfete swing (pdf local), Interfete swing (pagina externa)

 

- Precizari privind colocviul final

 

5.2. Programe de lucru cu socket-uri – clienti si servere (II)

 

5.2.1. Clasele ClientBidirectional si ServerBidirectional

 

 

                   

 

 

Superclasa ElementeComuneClientServer contine elemente comune clientilor si serverelor si este mostenita si extinsa de clienti si servere:

 

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

 import java.net.*;
 import java.io.*; 
 import javax.swing.JOptionPane;  
 
 public class ElementeComuneClientServer {  
    protected ConexiuneRetea conexiune;
    protected Socket socketTCP;
    protected int portTCP;
 
    public ElementeComuneClientServer(String tip) throws IOException {
        portTCP = Integer.parseInt(JOptionPane.showInputDialog(tip + 
                         ": introduceti numarul de port al serverului"));
    }

 }

 

 

Clasa utilitara ConexiuneRetea care incapsuleaza tratarea conexiunilor TCP:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

 import java.net.*;
 import java.io.*;
 import java.util.Scanner;
 
 public class ConexiuneRetea {
    private Socket conexiune;                
    private Scanner scannerTCP;
    private PrintStream printerTCP; 
    public ConexiuneRetea(Socket conexiune) throws IOException {                              
        this.conexiune = conexiune;
        this.scannerTCP = new Scanner(conexiune.getInputStream()); 
        this.printerTCP = new PrintStream(conexiune.getOutputStream()); 
    } 
    public String nextLine() { 
        return this.scannerTCP.nextLine();
    } 
    public int nextInt() { 
        return this.scannerTCP.nextInt();
    }
    public void printLine(String text) { 
        this.printerTCP.println(text); 
        this.printerTCP.flush();
    } 

 }

 

 

 

 

 

 

Clasa ClientBidirectional mosteneste si extinde clasa ElementeComuneClientServer:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

 import java.net.*;
 import java.io.*; 
 import javax.swing.JOptionPane;  
 
 public class ClientBidirectional extends ElementeComuneClientServer {    
    private InetAddress adresaIP;
 
    public ClientBidirectional() throws IOException {
        super("Client");
        adresaIP = InetAddress.getByName(JOptionPane.showInputDialog(
                       "Client: introduceti adresa serverului"));
        socketTCP = new Socket(adresaIP, portTCP);           // Creare socket 
        conexiune = new ConexiuneRetea(socketTCP);
    }
 
    public static void main (String args[]) throws IOException {
        ClientBidirectional client = new ClientBidirectional();
        String mesaj;
 
        while(true) {
            mesaj = JOptionPane.showInputDialog(
                        "Client: introduceti mesajul de trimis");
            client.conexiune.printLine(mesaj); 
            mesaj = client.conexiune.nextLine();
            JOptionPane.showMessageDialog(null, "Client: s-a primit "+mesaj);
            if (mesaj.equals(".")) break;    // Testarea conditiei de oprire 
        }
        client.socketTCP.close();        // Inchiderea socketului si a fluxurilor 
        JOptionPane.showMessageDialog(null, "Client: Bye!"); 
    }

 }

 

 

Clasa ServerBidirectional mosteneste si extinde clasa ElementeComuneClientServer:

 

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

 import java.net.*;
 import java.io.*; 
 import javax.swing.JOptionPane;  
 
 public class ServerBidirectional extends ElementeComuneClientServer {    
    private ServerSocket serverTCP;
 
    public ServerBidirectional() throws IOException {
        super("Server");
        serverTCP = new ServerSocket(portTCP);              // Creare socket server
        socketTCP = serverTCP.accept();                     // Creare socket 
        conexiune = new ConexiuneRetea(socketTCP);
    }
 
    public static void main (String args[]) throws IOException {
        ServerBidirectional server = new ServerBidirectional();
        String mesaj;
 
        while(true) {
          mesaj = server.conexiune.nextLine();
          JOptionPane.showMessageDialog(null, "Server: s-a primit mesajul "+mesaj); 
          mesaj = JOptionPane.showInputDialog(
                        "Server: introduceti mesajul de trimis");
          server.conexiune.printLine(mesaj); 
          if (mesaj.equals(".")) break;     // Testarea conditiei de oprire 
        }
        server.socketTCP.close();    // Inchiderea socketului si a fluxurilor
        JOptionPane.showMessageDialog(null, "Server: Bye!"); 
    }

 }

 

Nu uitati: Daca bara de stare a executiei este activa () verificati cu Alt+Tab daca a aparut o fereastra Java (in spatele ferestrelor vizibile).

 

Nu uitati: Pentru a opri executia, right click pe  si Reset Machine (sau Ctrl+Shift+Tab).

In laborator:

1. Lansati in executie BlueJ. Inchideti proiectele anterioare (Ctrl+W). Creati un proiect socket

      (Project->New Project…, selectati D:/,   POO2007,   numarul grupei, si scrieti socket).

2. In proiectul socket creati clasele ConexiuneRetea, ClientBidirectional, ServerBidirectional si ElementeComuneClientServer folosind codurile date mai sus.

3. Compilati codurile.

 

                                                                 

 

5.2.2. Clasa releu intre client si server

    

     

 

Adaugarea unei clase ReleuBidirectional pe post de retransmitator al mesajelor intre ClientBidirectional si ServerBidirectional:

 

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

 import java.net.*;
 import java.io.*; 
 import javax.swing.JOptionPane;  
 
 public class ReleuBidirectional extends ElementeComuneClientServer {    
    private ServerSocket serverTCPReleu;  
 
    private InetAddress adresaIPServerFinal;
    private ElementeComuneClientServer parteClient = 
                new ElementeComuneClientServer("Releu/server");    
 
    public ReleuBidirectional() throws IOException {
        super("Releu/client");
        adresaIPServerFinal = InetAddress.getByName(JOptionPane.showInputDialog(
                       "Releu/client: introduceti adresa serverului local"));
        parteClient.socketTCP = new Socket(adresaIPServerFinal, 
                                      parteClient.portTCP); // Socket spre server 
        parteClient.conexiune = new ConexiuneRetea(parteClient.socketTCP);
 
        serverTCPReleu = new ServerSocket(portTCP);         // Creare socket server
        socketTCP = serverTCPReleu.accept();                // Socket spre client
        conexiune = new ConexiuneRetea(socketTCP);
    }
 
    public static void main (String args[]) throws IOException {
        ReleuBidirectional releu = new ReleuBidirectional();
        String mesaj;
 
        while(true) {
          mesaj = releu.conexiune.nextLine();
          releu.parteClient.conexiune.printLine(mesaj);
          JOptionPane.showMessageDialog(null, "Releu/client: s-a primit " +mesaj);
 
          mesaj = releu.parteClient.conexiune.nextLine();
          releu.conexiune.printLine(mesaj);
          JOptionPane.showMessageDialog(null, "Releu/server: s-a primit " +mesaj);
 
          if (mesaj.equals(".")) break;    // Testarea conditiei de oprire 
        }
        releu.socketTCP.close();    // Inchiderea socketurilor si a fluxurilor 
        releu.parteClient.socketTCP.close();  
        JOptionPane.showMessageDialog(null, "Releu: Bye!"); 
    }

 }

 

 

In laborator:

1. In proiectul socket creati clasa ReleuBidirectional folosind codul dat mai sus. Compilati codul.

2. La un calculator right-click pe ServerBidirectional. Executati main(). Folositi portul 6000.

 

 

3. La un alt calculator (daca nu aveti la dispozitie un alt calculator in retea, deschideti inca o sesiune BlueJ) right-click pe clasa ReleuBidirectional, selectati si executati main().

4. Folositi adresa primului calculator, pe care se executa ServerBidirectional (adresa "localhost" in cazul in care folositi 3 sesiuni BlueJ pe acelasi calculator), port 7000 (spre client) si port 6000 (spre server).

 

 

5. La un alt calculator (daca nu aveti la dispozitie un alt calculator in retea, deschideti inca o sesiune BlueJ) right-click pe clasa ClientBidirectional, selectati si executati main().

6. Folositi adresa celui de-al doilea calculator, pe care se executa ReleuBidirectional (adresa "localhost" in cazul in care folositi 3  sesiuni BlueJ pe acelasi calculator), si port 7000.

7. Urmariti efectul in Terminal Window pe cele trei calculatoare.

 

 

5.3. Interfete grafice cu utilizatorul (GUI)

5.3.1. Modalitati de a crea containerul de nivel maxim

 

Pentru a crea containere de nivel maxim (detalii privind interfetele grafice swing in Java) exista mai multe modalitati, printre care:

 

1. Utilizarea unui obiect de tip JFrame,

 

 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 public class TestUtilizareFrame_Swing  {      // Test grafic cu JtextField si JTextArea
   private static JTextField inTextGrafic;     // Intrare -linie de text grafica (JtextField)
   private static JTextArea outTextGrafic;     // Iesire - zona de text grafica (JtextArea)
 
   public TestUtilizareFrame_Swing() {         // Initializari grafice
      // Crearea obiectului cadru (frame), cu titlu specificat
      JFrame frame = new JFrame("Test utilizare Frame"); 
      Container containerCurent = frame.getContentPane();
      containerCurent.setLayout(new BorderLayout());
 
      outTextGrafic = new JTextArea(5, 40);    // Zona de text non-editabila de iesire 
      JScrollPane scrollPane = new JScrollPane(outTextGrafic,
                     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
                     JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
 
      containerCurent.add("Center", scrollPane);
      outTextGrafic.setEditable(false);
 
      inTextGrafic = new JTextField(40);       // Camp de text editabil de intrare
      containerCurent.add("South", inTextGrafic);
 
      frame.pack();                 // Impachetarea (compactarea) componentelor 
      frame.setVisible(true);       // Fereastra devine vizibila 
      inTextGrafic.requestFocus();  // Cerere focus pe intrarea text din fereastra curenta     
   }
 
   public static void main (String args[]) {
      TestUtilizareFrame_Swing testUtilizareFrame = new TestUtilizareFrame_Swing();
   }
 }

 

 

In laborator:

1. Inchideti proiectele anterioare (Ctrl+W). Creati un nou proiect gui

    (Project -> New Project…, selectati D:/, apoi Software2006, apoi numarul grupei, si scrieti gui).

2. Creati o noua clasa, numita TestUtilizareFrame_Swing, folosind codul dat mai sus.

3. Compilati codul, apoi right-click pe clasa, selectati si executati main(). Urmariti efectul.

 

2. Extinderea prin mostenire a clasei JFrame,

 

 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 public class TestExtindereFrame_Swing extends JFrame { // Test cu JtextField si JTextArea
   private static JTextField inTextGrafic;     // Intrare -linie de text grafica (JtextField)
   private static JTextArea outTextGrafic;     // Iesire - zona de text grafica (JtextArea)
 
   public TestExtindereFrame_Swing() {         // Initializari grafice
      super("Test extindere Frame");           // Stabilire titlu fereastra (JFrame)
      Container containerCurent = this.getContentPane();
      containerCurent.setLayout(new BorderLayout());
 
      outTextGrafic = new JTextArea(5, 40);    // Zona de text non-editabila de iesire 
      JScrollPane scrollPane = new JScrollPane(outTextGrafic,
                     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
                     JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
 
      containerCurent.add("Center", scrollPane);
      outTextGrafic.setEditable(false);
 
      inTextGrafic = new JTextField(40);       // Camp de text editabil de intrare
      containerCurent.add("South", inTextGrafic);
 
      pack();                      // Impachetarea (compactarea) componentelor in container
      setVisible(true);            // Fereastra devine vizibila 
      inTextGrafic.requestFocus(); // Cerere focus pe intrarea de text din fereastra curenta     
   }
   public static void main (String args[]) {
      TestExtindereFrame_Swing testFrame = new TestExtindereFrame_Swing();
   }
 }

 

Optional, in laborator:

1. Tot in proiectul gui creati o noua clasa, numita TestExtindereFrame_Swing, folosind codul dat.

2. Compilati codul, apoi right-click pe clasa, selectati si executati main(). Urmariti efectul.

 

5.3.2. Crearea interactivitatii in interfetele grafice

 

Pentru introducerea interactivitatii, (detalii privind interfetele grafice swing in Java) trebuie tratate evenimentele din interfata grafica. In Java exista mai multe moduri de tratare a evenimentelor.

 

Incepand cu versiunea initiala, JDK 1.0, interfetele grafice realizate cu biblioteca AWT au 2 moduri de tratare a evenimentelor:

 

 

1. Implementand metoda action(), care:

- primeste ca parametri un obiect de tip Event care incapsuleaza evenimentul produs, si un obiect de tip Object care incapsuleaza parametrii acestuia,

- testeaza atributele target si id ale obiectului de tip Event pentru a identifica obiectul tinta (in care s-a produs evenimentul) si tipul de actiune produsa, si trateaza apoi evenimentul respectiv

 

 

2. Implementand metoda handleEvent(), care:

- primeste ca parametru un obiect de tip Event care incapsuleaza evenimentul produs,

- testeaza atributele target si id ale obiectului de tip Event pentru a identifica obiectul tinta (in care s-a produs evenimentul) si tipul de actiune produsa, si trateaza apoi evenimentul respectiv

Incepand cu versiunea JDK 1.1, interfetele grafice realizate cu biblioteca AWT au un nou mod de tratare a evenimentelor, utilizat si de interfetele grafice Swing, prin:

 

 

I. (a) declararea unei clase care implementeaza o interfata « ascultator de evenimente », (care contine metode ce trebuie implementate de utilizator pentru tratarea evenimentului respectiv), sau (b) declararea unei clase care extinde o clasa predefinita care implementeaza o interfata « ascultator de evenimente »

 

 

 

II. (a) implementarea tuturor metodelor definite in interfata « ascultator de evenimente », sau (b) re-implementarea metodelor dorite din clasa care implementeaza interfata

 

 

 

 

III. inregistrarea unui obiect din clasa « ascultator de evenimente » de catre fiecare dintre componentele grafice (numite tinta sau sursa) pentru care se doreste tratarea evenimentului respectiv

 

Programul EcouGrafic_Swing exemplifica extinderea clasei JFrame si tratarea evenimentelor.

 

 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 
 public class EcouGrafic_Swing extends JFrame { // Ecou grafic cu JtextField si JTextArea
 
   private static JTextField inTextGrafic;      // Intrare - linie text grafica (JtextField)
   private static JTextArea outTextGrafic;      // Iesire - zona text grafica (JtextArea)
   private static JScrollBar vertical;
 
   public EcouGrafic_Swing() {                  // Initializari grafice
      super("Ecou grafic simplu Swing");        // Stabilire titlu fereastra (JFrame)
      Container containerCurent = this.getContentPane();
      containerCurent.setLayout(new BorderLayout());
 
      outTextGrafic = new JTextArea(5, 40);     // Zona text non-editabila de iesire 
      JScrollPane scrollPane = new JScrollPane(outTextGrafic,
                     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
                     JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
      vertical = scrollPane.getVerticalScrollBar();
      containerCurent.add("Center", scrollPane);
      outTextGrafic.setEditable(false);
      outTextGrafic.append("Pentru oprire introduceti '.' si <Enter>\n\n");
 
      inTextGrafic = new JTextField(40);        // Camp de text editabil de intrare
      containerCurent.add("South", inTextGrafic);
 
      // Inregistrare obiect "ascultator" de "evenimente actionare" la "obiectul sursa"
      inTextGrafic.addActionListener(new AscultatorInText());
 
      // Inregistrare obiect "ascultator" de "evenimente fereastra" la "sursa" fereastra
      this.addWindowListener(new AscultatorInchidere());
 
      pack();                      // Impachetarea (compactarea) componentelor in container
      setVisible(true);            // Fereastra devine vizibila 
 
      inTextGrafic.requestFocus(); // Cerere focus pe intrarea text din fereastra curenta     
   }
 
   // Clasa interna "ascultator" de "evenimente actionare" 
   // implementeaza interfata ActionListener
   class AscultatorInText implements ActionListener {
 
      // Tratarea actionarii intrarii de text (introducerii unui "Enter")
      public void actionPerformed(ActionEvent ev) { 
 
         String sirCitit = inTextGrafic.getText();  // Citirea unei linii din intrarea text                  
         inTextGrafic.setText("");                  // Golirea intrarii text 
         outTextGrafic.append("S-a introdus: "+sirCitit+"\n"); // Scriere linie in zona text 
 
         vertical.setValue(vertical.getMaximum() - vertical.getVisibleAmount());
         validate(); repaint();
         if (sirCitit.equals(new String(".")))   System.exit(0);   // Conditie terminare 
      }      
   }

 

   // Metoda de test. Punct de intrare in program. 
 
  public static void main (String args[]) {
      EcouGrafic_Swing ecouGrafic = new EcouGrafic_Swing();
   }
 }
 
 // Clasa "adaptor pentru ascultator" de "evenimente fereastra", extinde WindowAdapter
 class AscultatorInchidere extends WindowAdapter {
    // Tratarea inchiderii ferestrei curente
    public void windowClosing(WindowEvent ev) { System.exit(0); } // Terminarea programului }
 }

 

 

In laborator:

1. Tot in proiectul gui creati o noua clasa, numita EcouGrafic_Swing, folosind codul dat.

2. Compilati codul, apoi right-click pe clasa, selectati si executati main(). Urmariti efectul.

 

 

 

5.4. Precizari privind colocviul final            

 

 

La ultima lucrare va fi sustinut si colocviul de laborator la care vor fi aduse toate temele de casa de la lucrarile 1, 2, 3 si 4. Colocviul va fi consta in intrebari din temele de casa.

 

 

Nota finala la laborator (30% din nota finala) va fi stabilita in functie de

- prezenta la laborator,

- activitatea la laborator (care va include datele la care au fost predate temele) si de

- cunostintele de POO dovedite la colocviul final.