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
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. |
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. |
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. |
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. 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. |
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.