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