In aceasta lucrare de laborator vor fi acoperite urmatoarele probleme:
- Utilizarea firelor de executie
(clasa Threads) – Introducere in threads – link
extern
- Interfete grafice cu utilizatorul
– Interfete grafice swing – link extern
- Precizari privind « colocviul » la laborator
Pentru a crea un nou fir de executie (detalii
privind firele de executie - threads
- in Java) exista doua modalitati.
1. Se poate declara o
clasa ca subclasa a clasei Thread, subclasa care trebuie sa rescrie codul (override)
metodei run() a clasei Thread (care nu contine nici un cod), noul fir de executie fiind creat prin
alocarea si lansarea unei instante a subclasei.
Formatul pentru crearea unei subclase care extinde clasa Thread si ii reimplementeaza metoda run() este urmatorul:
class FirT extends Thread { public void run() {// codul firului de executie }} |
Formatul pentru crearea unei instante a subclasei este urmatorul:
FirT fir = new FirT(); |
2. Se poate declara o clasa care
implementeaza interfata Runnable,
interfata care contine doar declaratia unei metode run()
(declaratie similara celei din clasa Thread,
clasa Thread implementand
interfata Runnable), noul
fir fiind obtinut prin crearea unei
instante a noii clase, pasata
constructorului la crearea unei instante
a clasei Thread, si lansarea noii instante a clasei Thread.
Formatul pentru crearea unei clase care implementeaza interfata Runnable si ii implementeaza metoda run() este urmatorul:
class FirR implements Runnable { public void run() {// codul firului de executie } } |
Formatul pentru crearea unei instante a noii clase si apoi a unei instante
a clasei Thread este urmatorul:
FirR r = new FirR(); Thread fir = new Thread(r); |
In ambele cazuri formatul pentru lansarea noului fir de
executie, este urmatorul:
fir.start(); |
Variante compacte pentru crearea si lansarea noilor fire de executie:
new FirT().start(); // nu exista variabila de tip FirT // care sa refere explicit firul |
FirR r = new FirR(); new Thread(r).start(); // nu exista variabila de tip Thread // care sa refere explicit firul |
Thread fir = new Thread(new FirR()); // nu exista variabila de tip FirRFir.start(); // care sa refere explicit firul |
new Thread(new FirR()).start(); // nu exista variabila de tip Thread// si nici variabila de tip FirR // care sa refere explicit firul |
Urmatorul program va fi folosit pentru a
exeplifica lucrul cu fire de executie.
Clasa FirSimplu
extinde clasa Thread, iar metoda
principala lanseaza metoda run() ca nou fir de executie.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public
class FirSimplu extends Thread { // obiectele
din clasa curenta sunt thread-uri public FirSimplu(String str) { super(str); // invocarea constructorului
Thread(String) } //
al superclasei Thread public
void run() { // “metoda principala” a
thread-ului curent for
(int i = 0; i < 5; i++) {
System.out.println(i + " " + getName()); // obtinerea numelui thread-ului try
{
sleep((long)(Math.random()
* 1000)); // thread-ul “doarme” 0...1 secunda
} catch (InterruptedException e) {} }
System.out.println("Gata!
" + getName()); // obtinerea numelui thread-ului } public
static void main (String[]
args) { new FirSimplu("Unu").start(); // “lansarea”
thread-ului (apeleaza run()) } } |
Executia
FirSimplu:
2 executii DemoDouaFire:

Clasa DemoDouaFire lanseaza doua fire de
executie de tip FirSimplu
executate concurent.
|
1 2 3 4 5 6 |
public
class DemoDouaFire { public
static void main (String[]
args) { new FirSimplu("Unu").start(); // “lansarea”
primului thread new FirSimplu("Doi").start(); // “lansarea”
celui de-al doilea thread } } |
Firele au evolutii diferite, in functie de durata intarzierii introdusa in FirSimplu de linia:
sleep( (long) (Math.random() * 1000) );
Clasa DemoTreiFire lanseaza trei fire de
executie de tip FirSimplu
executate concurent.
|
1 2 3 4 5 6 7 |
public
class DemoTreiFire { public
static void main (String[]
args) { new FirSimplu("Unu").start(); // “lansarea”
primului thread new FirSimplu("Doi").start(); // “lansarea”
celui de-al doilea thread new FirSimplu("Trei").start(); // “lansarea”
celui de-al treilea thread } } |
|
In laborator: 1. Inchideti proiectele anterioare
(Ctrl+W). Creati un nou proiect fire (Project
-> New Project…, selectati D:/, apoi Software2006, apoi numarul
grupei, si scrieti fire). 2. Creati o noua clasa, numita
FirSimplu,
folosind codul dat mai sus. 3. Creati un obiect tip FirSimplu
(cu nume "Test"), inspectati-i campurile (atributele) si metodele. 4. Tot in proiectul fire
creati clasa DemoTreiFire
folosind codul de mai sus. Compilati clasele. 5. Right-click pe clasa,
selectati si executati main().
Urmariti efectul in Terminal Window.
|
Doua variante (aplicatie de sine statatoare si applet) de program "ceas"
bazat pe threads:
|
import java.util.*; import java.text.DateFormat; import java.io.*; public class CeasConsola
implements Runnable { private Thread firCeas = null; private static int contor = 0; public void start() { // (re)pornire fir if (firCeas == null) { firCeas = new Thread(this); firCeas.start();
// apeleaza run() } System.out.println("Ceas pornit"); } public void run() { // executie fir Thread firulMeu = Thread.currentThread(); contor++; while (firCeas == firulMeu) { Calendar cal =
Calendar.getInstance(); Date date =
cal.getTime(); DateFormat df
= DateFormat.getTimeInstance(); System.out.println("["
+ contor + "] " +
df.format(date)); try { Thread.sleep(1000); } catch
(InterruptedException e){ } } } public void stop() { //
oprire fir
System.out.println("Ceas
oprit"); firCeas = null; //
firul dispare } public static void
main(String[] args)
throws IOException { CeasConsola ceas; BufferedReader
in = new BufferedReader (new InputStreamReader(System.in)); while (true) { ceas = new CeasConsola(); ceas.start(); //
(re)pornire fir la citirea in.readLine(); //
unui caracter de la consola ceas.stop(); //
oprire fir la citirea in.readLine(); //
unui caracter de la consola } } } |
import java.applet.Applet; import java.awt.*; import java.util.*; import java.text.DateFormat; public class CeasApplet
extends Applet
implements Runnable { private Thread firCeas = null; private static int contor = 0; public void init() { setBackground(Color.white);
} public void start() { // (re)pornire fir if (firCeas == null) { firCeas = new Thread(this,
"Ceas"); firCeas.start(); // apeleaza run() } } public void run() { // executie fir Thread firulMeu = Thread.currentThread(); contor++; while (firCeas == firulMeu) { repaint(); //
apeleaza paint() (redeseneaza) try { Thread.sleep(1000); } catch
(InterruptedException e){ } } } public void paint(Graphics g) { //
deseneaza Calendar cal =
Calendar.getInstance(); Date date =
cal.getTime(); DateFormat df =
DateFormat.getTimeInstance(); g.drawString("["
+ contor + "] " +
df.format(date), 5, 10); } public void stop(){ // oprire fir firCeas = null; //
firul dispare } } // Applet-ul nu are metoda principala.
// Metodele start(), stop(),
run(), etc. sunt invocate // de browserul Web in care este “executat”. /* Exemplu de includere intr-o pagina
Web (HTML): <HTML> <TITLE> Applet Ceas </TITLE> <BODY> <APPLET CODE=CeasApplet.class WIDTH=200 HEIGHT=50> </APPLET> </BODY> </HTML> */ |
|
In laborator: 1. Testati applet-ul CeasApplet folosind link-ul dat.
Ceas |
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(); } } |

|
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:
3. Un nou mod de tratare
a evenimentelor, utilizat si de interfetele grafice Swing,
care presupune trei operatii:
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 crearea unei ferestre principale prin
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 } } 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. |
La ultima lucrare de laborator (urmatoarea, a 6-a, in ianuarie 2007) vor fi aduse:
- Temele de la lucrarea de laborator 1:
* Sinteza (interpretarea)
raporturilor de eroare obtinute prin modificarea programului Salut.java
(scrisa pe hartie, nu
tiparita la imprimanta).
* Codurile sursa ale
programelor Polinom0, Polinom1 si Polinom2 completate.
- Temele de la lucrarea de laborator 2:
* Listingul
(sau textul scris de mana) cu sarcinile indeplinite pentru a obtine desenul
casei
* Codurile Java pentru cele 2 clase
care corespund numarului de ordine al fiecarui student, codurile continand cel
putin 3 campuri/atribute si 3 metode/operatii.
- Temele de la lucrarea de laborator 3:
* Codurile finale ale
claselor DialogUtilizator02,
Mesaj02
si Pachet02 (listinguri).
* Codurile celor 2 clase date ca
tema data trecuta (listinguri), fiecare continand: cel putin 3
campuri/atribute, cel putin 2 constructori, (cerinta noua!) cel putin 3 metode/operatii. Codurile metodelor
si constructorilor vor neaparat fi complete!
- Temele de la lucrarea de laborator 4:
* Codurile finale ale claselor ReleuDerivat,
ClientBidirectional, ServerBidirectional, si ReleuBidirectional
(scrise pe hartie sau listinguri!)
Pe baza acestor teme (date la lucrarile 1-4),
in urma unor discutii individuale, si tinand cont de activitatea la
laborator, vor fi stabilite calificativele la laborator.