Sunteți pe pagina 1din 50

Lectia 1 Its more fun to compute

Obiective:
Cum demaram un proiect Visual Studio.NET
Integrarea catorva componente intr-o aplicatie vizuala
Completarea codului

Mediul integrat Visual Studio .NET ofera o larga gama de ustensile ce permit crearea rapida de
aplicatii. In aceasta lectie ne propunem sa prezentam pasii ce trebuie urmati in crearea unei aplicatii
utilizand Visual Studio.NET.

Imediat dupa lansarea Visual Studio.NET, putem demara crearea unui proiect (figura 1) si selectiona
limbajul ales pentru implementarea aplicatiei (figurile 2,3,4).


Figura 1- Deschiderea unui nou proiect Figura 2 Alegem Visual Basic...


Figura 3 ...Visual C#... Figura 4 sau Visual J#?

Avand in vedere ca Java este unul dintre limbajele cele mai raspandite in mediul academic, vom
alege, si noi, sa implementam proiectele cursului de fata tot in Java, incurajand insa studentii sa
incerce, macar prin analogie, crearea acelorasi proiecte si in limbajele Visual Basic si Visual C#.

Odata confirmat limbajul ales spre implementare, VS.NET afiseaza o interfata grafica (figura 5) in
care programatorul nu trebuie decat sa depuna forme si controale vizuale pentru a realiza
implementarea aplicatiei.


Figura 5 Contextul vizual al aplicatiei... Figura 6 - ... si interfata cu tot ce trebuie.

Pentru aceasta prima lectie ne propunem sa implementam, nu binecunoscutul Hello world!, ci un
mic motor de calcul pentru determinarea lui n! (reamind ca

=
=
n i
i n
, 1
! , pentru orice
*
N n iar
pentru 0 = n , 1 != n prin conventie).

Pentru a asigura interactivitatea aplicatiei cu utilizatorul, aceasta va trebui sa ceara, printr-un
dialog vizual cu utilizatorul, o valoare numerica pozitiva, urmand ca apoi sa afiseze valoarea
calculata.

Deci vom avea nevoie de un text explicativ (Label), un loc (TextBox) in care sa specificam
valoarea lui n, un instrument (Button) care sa declanseze calculele si un al doilea loc (TextBox)
in care afisam rezultatul calculelor.

Plasarea tuturor acestor elemente in cadrul vizual oferit de VS.NET (Form1) este lasat la libera
alegere a programatorului; o solutie posibila este cea din figura 6. Proprietatile tuturor elementelor
plasate in cadrul vizual pot fi inspectate/modificate prin intermediul ferestrei Properties (dreapta
jos). Lista si semnificatia acestor componente este:

label1 (Label) textul explicativ,
textBox1 (TextBox) locul in care specificam numarul n,
button1 (Button) instrumentul care declanseaza calculele, si
textBox2 (TextBox) locul in care specificam rezultatele calculelor

Pe masura ce avansam cu completarea cadrului vizual Form1, VS.NET genereaza si actualizeaza un
fisier corespunzator, avand denumirea form1.jsl (sau form1.vb in cazul utilizarii Visual
Basic, respectiv form1.cs in cazul utilizarii Visual C#).

package WindowsApplication3;

import System.Drawing.*;
import System.Collections.*;
import System.ComponentModel.*;
import System.Windows.Forms.*;
import System.Data.*;

/**
* Summary description for Form1.
*/
public class Form1 extends System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox2;

/**
* Required designer variable.
*/
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/**
* Clean up any resources being used.
*/
protected void Dispose(boolean disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
super.Dispose(disposing);
}

#region Windows Form Designer generated code
/**
* Required method for Designer support - do not modify
* the contents of this method with the code editor.
*/
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox2 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// label1
//
this.label1.set_Location(new System.Drawing.Point(32, 16));
this.label1.set_Name("label1");
this.label1.set_Size(new System.Drawing.Size(128, 24));
this.label1.set_TabIndex(0);
this.label1.set_Text("Introduceti un numar:");
//
// textBox1
//
this.textBox1.set_Location(new System.Drawing.Point(152, 16));
this.textBox1.set_Name("textBox1");
this.textBox1.set_TabIndex(1);
this.textBox1.set_Text("textBox1");
//
// button1
//
this.button1.set_Location(new System.Drawing.Point(32, 56));
this.button1.set_Name("button1");
this.button1.set_Size(new System.Drawing.Size(224, 23));
this.button1.set_TabIndex(2);
this.button1.set_Text("Calculeaza");
//
// textBox2
//
this.textBox2.set_Location(new System.Drawing.Point(32, 104));
this.textBox2.set_Name("textBox2");
this.textBox2.set_Size(new System.Drawing.Size(224, 20));
this.textBox2.set_TabIndex(3);
this.textBox2.set_Text("textBox2");
//
// Form1
//
this.set_AutoScaleBaseSize(new System.Drawing.Size(5, 13));
this.set_ClientSize(new System.Drawing.Size(292, 273));
this.get_Controls().Add(this.textBox2);
this.get_Controls().Add(this.button1);
this.get_Controls().Add(this.textBox1);
this.get_Controls().Add(this.label1);
this.set_Name("Form1");
this.set_Text("I\'ts more fun to compute");
this.ResumeLayout(false);

}
#endregion

/**
* The main entry point for the application.
*/
/** @attribute System.STAThread() */
public static void main(String[] args)
{
Application.Run(new Form1());
}
}

Rularea aplicatiei astfel obtinute conduce la afisarea contextului vizual Form1. Acesta permite
actionarea si interactiunea utilizatorului cu componentele formei fara insa a produce rezultatul
scontat; calculul lui n! (figura 7).


Figura 7 Aplicatia ... o carcasa fara continut Figura 8 Aplicatia ... un mic motor de n!

Este si normal sa fie asa deoarece in afara de functiunile vizuale implicit asigurate de catre
componentele introduse, noi, ca programatori, nu am adaugat nici o semantica relativa la
contextul problemei.

De aceea, pentru a remedia situatia va trebui sa completam functional contextul vizual obtinut. In
acest sens:

introducem doi identificatori in cadrul contextului vizual:
o numar retinand numarul introdus de catre utilizator si respectiv
o factorial pentru a retine rezultatul calculelor.

private int numar, factorial;

analizam intrarea utilizatorului prin tratarea evenimentului TextChanged asociat lui
textBox1, si incarcam valoarea obtinuta in numar:

private void textBox1_TextChanged (Object sender, System.EventArgs e)
{
Integer in=Integer.valueOf(textBox1.get_Text());
numar=in.intValue();
}

Pentru a accesa aceasta zona de cod putem fie sa efectuam dublu-click pe componenta in
cauza (in cazul nostru pe textBox1), fie sa selectionam aceasta componenta si sa
inspectam/utilizam fereastra Properties asociata.

declansam calculul factorialului, prin tratarea evenimentului Click asociat butonului button1
in cadrul caruia, in plus, actualizam textBox2 cu valoarea nou obtinuta:

private void button1_Click (Object sender, System.EventArgs e)
{
factorial=1;
for (int i=1;i<=numar; i++)
factorial*=i;

textBox2.set_Text(""+factorial);
}

Codul modificat al aplicatiei este urmatorul:

package WindowsApplication3;

import System.Drawing.*;
import System.Collections.*;
import System.ComponentModel.*;
import System.Windows.Forms.*;
import System.Data.*;

/**
* Summary description for Form1.
*/
public class Form1 extends System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox2;

private int numar, factorial;

/**
* Required designer variable.
*/
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/**
* Clean up any resources being used.
*/
protected void Dispose(boolean disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
super.Dispose(disposing);
}

#region Windows Form Designer generated code
/**
* Required method for Designer support - do not modify
* the contents of this method with the code editor.
*/
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox2 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// label1
//
this.label1.set_Location(new System.Drawing.Point(32, 16));
this.label1.set_Name("label1");
this.label1.set_Size(new System.Drawing.Size(128, 24));
this.label1.set_TabIndex(0);
this.label1.set_Text("Introduceti un numar:");
//
// textBox1
//
this.textBox1.set_Location(new System.Drawing.Point(152, 16));
this.textBox1.set_Name("textBox1");
this.textBox1.set_TabIndex(1);
this.textBox1.set_Text("textBox1");
this.textBox1.add_TextChanged(
new System.EventHandler(this.textBox1_TextChanged)
);
//
// button1
//
this.button1.set_Location(new System.Drawing.Point(32, 56));
this.button1.set_Name("button1");
this.button1.set_Size(new System.Drawing.Size(224, 23));
this.button1.set_TabIndex(2);
this.button1.set_Text("Calculeaza");
this.button1.add_Click( new System.EventHandler(this.button1_Click) );
//
// textBox2
//
this.textBox2.set_Location(new System.Drawing.Point(32, 104));
this.textBox2.set_Name("textBox2");
this.textBox2.set_Size(new System.Drawing.Size(224, 20));
this.textBox2.set_TabIndex(3);
this.textBox2.set_Text("textBox2");
//
// Form1
//
this.set_AutoScaleBaseSize(new System.Drawing.Size(5, 13));
this.set_ClientSize(new System.Drawing.Size(292, 273));
this.get_Controls().Add(this.textBox2);
this.get_Controls().Add(this.button1);
this.get_Controls().Add(this.textBox1);
this.get_Controls().Add(this.label1);
this.set_Name("Form1");
this.set_Text("I\'ts more fun to compute");
this.ResumeLayout(false);

}
#endregion

/**
* The main entry point for the application.
*/
/** @attribute System.STAThread() */
public static void main(String[] args)
{
Application.Run(new Form1());
}

private void button1_Click (Object sender, System.EventArgs e)
{
factorial=1;
for (int i=1;i<=numar; i++)
factorial*=i;

textBox2.set_Text(""+factorial);
}

private void textBox1_TextChanged (Object sender, System.EventArgs e)
{
Integer in=Integer.valueOf(textBox1.get_Text());
numar=in.intValue();
}
}


Lectia 2 Control the controls

Obiective:
Utilizarea controalelor
Accesarea proprietatilor controalelor
Top 12 al celor mai utilizate controale


Utilizarea controalelor
Asa cum am vazut in lectia anterioara, pentru utilizarea oricarui control Visual J# (si acest lucru
este valabil pentru oricare din limbajele .NET) este suficienta selectarea controlului vizat si
deplasarea (prin drag & drop) a acestuia in forma vizuala. Este foarte probabil ca odata aceasta
operatie terminata veti fi nevoiti sa operati la mici ajustari vizuale, de genul dimensiune si pozitie
exacta a controlului.

Toate controalele sunt sensibile, direct sau indirect, la actiunile utilizatorului exprimate prin mouse
(click, double-click) dar nu numai. Visual Studio .NET genereaza automat cod (in fine, contextul
codului, de tratare a evenimentelor produse de utilizator) urmand ca programatorul sa completeze
acest cod cu cod propriu aplicatiei.

Accesarea proprietatilor
Proprietatile controalelor pot fi accesate fie prin intermediul browser-ului de proprietati fie direct
prin utilizarea metodelor de acces (_get) sau modificare (_set) a controlului.


Figura 8 Un Button selectat si cateva din proprietatile sale afisate (dreapta jos).

In figura 8 se observa selectat obiectul button1 iar in fereastra de proprietati sunt vizibile proprietatile sale. De
exemplu, textul butonului poate fi modificat printr-o linie de cod de genul :

this.button1.set_Text("Calculeaza");

Top 10 al celor mai utilizate controale

Control .NET Class Java Swing
Form
System.Windows.Forms.Form JFrame
Label System.Windows.Forms.Label
JLabel
Button System.Windows.Forms.Button
JButton
TextBox System.Windows.Forms.TextBox
JTextArea
CheckBox System.Windows.Forms.CheckBox
JCheckBox
ComboBox System.Windows.Forms.ComboBox
JComboBox
RadioButton System.Windows.Forms.RadioButton
JRadioButton
GroupBox System.Windows.Forms.GroupBox
PictureBox System.Windows.Forms.PictureBox
ImageIcon
Panel System.Windows.Forms.Panel
JPanel
ListBox System.Windows.Forms.ListBox
JList


Figura 9 O interfata plina ... doar de controale.
Label

Label introduce un text in cadrul vizual, text ce nu poate fi accesat pentru modificare/deplasare in
timpul rularii aplicatiei.

Un astfel de text este caracterizat prin:
Font numele fontului, dimensiune, ingrosat, italic.
Text textul efectiv al controlului.
TextAlign alinierea textului, implicit la stanga
Image controlul poate afisa, pe langa text, si o imagine (ca fundal al textului).

Button

Butoanele ocupa primul loc in clasamentul controalelor accesibile prin Mouse.

Afisand un text pe control, Button mosteneste caracteristicile controlului Label, dar, spre deosebire
de acesta, centreaza textul pe control si, mai important, este accesibil utilizatorului in timpul rularii
aplicatiei. In acest sens, Button este sensibil evenimentelor provenite de la Mouse, cel mai utilizat
fiind evenimentul Click.

TextBox

Utilizand un control TextBox permitem utilizatorului introducerea de date (de la tastatura) in cadrul
vizual al aplicatiei. Uzual, informatia introdusa intr-un TextBox este utilizata fie in urma exprimarii
acestei intentii de catre utilizator prin intermediul unui Button (Calculeaza in exemplul nostru), fie
datorita tratarii de catre controlul TextBox a evenimentului TextChanged, emis de indata ce
continutul controlului este modificat.

Proprietatile cele mai frecvent accesate ale TextBox vizeaza, bineinteles continutul textual (Text) al
controlului, si anume:
MaxLength specifica lungimea maxima a textului continut de control, cu o lungime maxima
admisibila de 32767 caractere,
Multiline specificarea faptului ca textul se poate intinde pe mai multe linii si implicit permiterea
redimensionarii pe verticala a controlului,
PasswordChar campul seteaza caracterul afisat in momentul introducerii textului controlului
(asemeni afisajului utilizat pentru parola utilizatorilor).

CheckBox si RadioButton
In vederea realizarii unei selectii inclusive sau exclusive, prin bifare, a unei optiuni in cadrul vizual,
se uilizeaza doua controale, CheckBox (pentru selectie inclusiva, indicata prin simbolul v) si
RadioButton (pentru selectie exclusiva, indicata prin simbolul ).

Aparitia/disparitia simbolurilor in casutele corespunzatoare se realizeaza prin selectia (repetata) a
aceluiasi control, iar starea actuala a controlului poate fi setata/citita prin intermediul proprietatii
Checked.


GroupBox
GroupBox permite, dupa cum spune si numele, gruparea mai multor butoane (de regula
RadioButton) intr-un singur context vizual (si retinerea tuturor butoanelor intr-o lista proprie,
independenta de restul contextelor vizuale).

Panel
Panel constituie un context vizual ce poate gazdui (grupa vizual) o serie de alte controale permitand
in acelasi timp o proiectare mai usoara a interfatelor complexe. La fel ca celelalte controale vizuale,
poate fi redimensionat si deplasat. El insa nu gestioneaza componentele plasate in interiorul sau asa
cum o face GroupBox.

ListBox si ComboBox

ListBox (respectiv ComboBox) afiseaza un numar constant (respectiv variabil) de linii de
informatii pe ecran, permitand selectia multipla (respectiv o singura selectie). Obtinerea elementului
selectat se poate face prin apelul metodei getSelectedValues( ) si care produce un sir de String
(respectiv getSelectedValue()).

PictureBox
Imaginile pot fi adaugate intr-un context vizual utilizand un control PictureBox atat in scopuri
decorative cat si ca element de interactiune. Fisierul de resursa a imaginii, specificat in proprietatea
Image, poate fi un BMP, JPEG sau GIF.

Aceasta imagine poate, si este deseori, redimensionata (direct prin accesul la imagine prin Mouse
sau indirect ca rezultat al redimensionarii contextului vizual). In urma acestei redimensionari,
imaginea este plasata in coltul din stanga-sus al controlului PictureBox fara nici un fel de ajustare a
imaginii si indiferent de dimensiunile controlului, daca proprietatea SizeMode este setata la
Normal. Daca proprietatea SizeMode este setata la StretchImage, imaginea este ajustata in asa fel
incat sa ocupe intreg spatiul rezervat controlului, iar daca SizeMode este AutoSize, dimensiunea
controlului este ajustata la dimensiunea reala a imaginii sursa. In plus, daca dorim centra imaginea
in control, putem face acest lucru prin utilizarea valorii CenterImage pentru proprietatea
SizeMode.

Timer
Controlul Timer este un exemplu, usor de inteles, de control ce nu are o reprezentare vizuala. Prin
plasarea controlului in contextul vizual al aplicatiei, mediul Visual Studio va afisa un ecran similar
celui din figura 10, devenind astfel vizibil accesul la controlul Timer si la proprietatile acestuia.

Timer are drept scop executia unui cod la intervale de timp regulate. El poate fi activat sau
dezactivat, prin proprietatea Enabled, putandu-i-se stabili frecventa la care intra in actiune, prin
proprietatea Interval, aceasta fiind exprimata in milisecunde. Accesul la codul corespondent
controlului se face, ca in cazul oricarui alt controler, prin dublu click.


Figura 10 Controlul Timer si fereastra de proprietati asociata.

Aceasta actiune ne conduce in metoda Tick asociata controlului. In exemplul urmator, metoda va
selecta/deselecta un alt control existent deja in contextul vizual al aplicatiei, un obiect de tip
RadioButton, radioButton2.

private void timer1_Tick (Object sender, System.EventArgs e)
{
radioButton2.set_Checked(!radioButton2.get_Checked());
}

Acelasi obiect timer1 il vom utiliza pentru generarea diferitelor forme geometrice in exemplul
urmator.

Elemente de grafica 2D

Pentru a avea acces la facilitatile grafice 2D va trebui sa importam biblioteca
System.Drawing.Drawing2D. Invocand metafora atelierului de creatie, doua concepte sunt
esentiale in crearea contextului grafic: panza si zona.

Panza (acel Canvas din Java) este introdusa de aceasta data prin Path, si consta in suprafata pe
care se vor realiza reprezentarile figurilor, liniilor, fara insa a avea o reprezentare vizuala pe ecran.
Pe aceasta panza, putem delimita regiunea in care putem desena efectiv, prin Region.

In exemplu de mai jos este utilizat spatiul unui Panel, panel1, ca zona de desenare a diferitelor
forme geometrice (figura 11).




Figura 11 Diferite forme geometrice desenate in panel1 in diferite momente de timp
controlate de timer1.

package WindowsApplication5;

import System.Drawing.*;
import System.Drawing.Drawing2D.*;
import System.Collections.*;
import System.ComponentModel.*;
import System.Windows.Forms.*;
import System.Data.*;

/**
* Summary description for Form1.
*/
public class Form1 extends System.Windows.Forms.Form
{
private int count;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.RadioButton radioButton1;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.RadioButton radioButton2;
private System.Windows.Forms.RadioButton radioButton3;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Timer timer1;
private System.ComponentModel.IContainer components;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
GraphicsPath gPath = new GraphicsPath();
gPath.AddRectangle(new System.Drawing.Rectangle(new
System.Drawing.Point(0,0),new
System.Drawing.Size(panel1.get_ClientSize().get_Width(),panel1.get_ClientSize().get_Hei
ght())));
//gPath.AddEllipse(0,0,this.get_ClientSize() .get_Width(),this.get_ClientSize()
.get_Height());
//this.set_Region(new Region(gPath));
panel1.set_Region(new Region(gPath));

count=0;
}

/**
* Clean up any resources being used.
*/
protected void Dispose(boolean disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
super.Dispose(disposing);
}

#region Windows Form Designer generated code
/**
* Required method for Designer support - do not modify
* the contents of this method with the code editor.
*/
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Resources.ResourceManager resources = new
System.Resources.ResourceManager(Form1.class.ToType());
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.radioButton1 = new System.Windows.Forms.RadioButton();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.radioButton3 = new System.Windows.Forms.RadioButton();
this.radioButton2 = new System.Windows.Forms.RadioButton();
this.listBox1 = new System.Windows.Forms.ListBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.panel1 = new System.Windows.Forms.Panel();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.groupBox1.SuspendLayout();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.set_Location(new System.Drawing.Point(16, 24));
this.label1.set_Name("label1");
this.label1.set_TabIndex(0);
this.label1.set_Text("Demo Label");
//
// textBox1
//
this.textBox1.set_Location(new System.Drawing.Point(96, 24));
this.textBox1.set_Name("textBox1");
this.textBox1.set_TabIndex(1);
this.textBox1.set_Text("Demo TextBox");
//
// button1
//
this.button1.set_Location(new System.Drawing.Point(248, 24));
this.button1.set_Name("button1");
this.button1.set_Size(new System.Drawing.Size(80, 24));
this.button1.set_TabIndex(2);
this.button1.set_Text("Demo Button");
//
// checkBox1
//
this.checkBox1.set_Location(new System.Drawing.Point(24, 72));
this.checkBox1.set_Name("checkBox1");
this.checkBox1.set_Size(new System.Drawing.Size(128, 24));
this.checkBox1.set_TabIndex(3);
this.checkBox1.set_Text("Demo CheckBox");
//
// radioButton1
//
this.radioButton1.set_Location(new System.Drawing.Point(152, 72));
this.radioButton1.set_Name("radioButton1");
this.radioButton1.set_TabIndex(4);
this.radioButton1.set_Text("radioButton1");
//
// groupBox1
//
this.groupBox1.get_Controls().Add(this.radioButton3);
this.groupBox1.get_Controls().Add(this.radioButton2);
this.groupBox1.set_Location(new System.Drawing.Point(16, 104));
this.groupBox1.set_Name("groupBox1");
this.groupBox1.set_Size(new System.Drawing.Size(104, 88));
this.groupBox1.set_TabIndex(5);
this.groupBox1.set_TabStop(false);
this.groupBox1.set_Text("groupBox1");
//
// radioButton3
//
this.radioButton3.set_Location(new System.Drawing.Point(8, 48));
this.radioButton3.set_Name("radioButton3");
this.radioButton3.set_Size(new System.Drawing.Size(88, 32));
this.radioButton3.set_TabIndex(1);
this.radioButton3.set_Text("radioButton3");
//
// radioButton2
//
this.radioButton2.set_Location(new System.Drawing.Point(8, 24));
this.radioButton2.set_Name("radioButton2");
this.radioButton2.set_Size(new System.Drawing.Size(88, 24));
this.radioButton2.set_TabIndex(0);
this.radioButton2.set_Text("radioButton2");
//
// listBox1
//
this.listBox1.set_Location(new System.Drawing.Point(208, 120));
this.listBox1.set_Name("listBox1");
this.listBox1.set_Size(new System.Drawing.Size(120, 69));
this.listBox1.set_TabIndex(6);
//
// comboBox1
//
this.comboBox1.set_Location(new System.Drawing.Point(208, 192));
this.comboBox1.set_Name("comboBox1");
this.comboBox1.set_Size(new System.Drawing.Size(121, 21));
this.comboBox1.set_TabIndex(7);
this.comboBox1.set_Text("comboBox1");
//
// pictureBox1
//

this.pictureBox1.set_Image(((System.Drawing.Image)(resources.GetObject("picture
Box1.Image"))));
this.pictureBox1.set_Location(new System.Drawing.Point(16, 248));
this.pictureBox1.set_Name("pictureBox1");
this.pictureBox1.set_Size(new System.Drawing.Size(136, 100));

this.pictureBox1.set_SizeMode(System.Windows.Forms.PictureBoxSizeMode.Stretc
hImage);
this.pictureBox1.set_TabIndex(8);
this.pictureBox1.set_TabStop(false);
//
// panel1
//

this.panel1.set_BorderStyle(System.Windows.Forms.BorderStyle.FixedSingle);
this.panel1.get_Controls().Add(this.label2);
this.panel1.set_Location(new System.Drawing.Point(168, 224));
this.panel1.set_Name("panel1");
this.panel1.set_Size(new System.Drawing.Size(160, 128));
this.panel1.set_TabIndex(9);
this.panel1.add_Paint( new
System.Windows.Forms.PaintEventHandler(this.panel1_Paint) );
//
// label2
//
this.label2.set_Location(new System.Drawing.Point(8, 8));
this.label2.set_Name("label2");
this.label2.set_TabIndex(0);
this.label2.set_Text("This is a Panel");
//
// label3
//
this.label3.set_Location(new System.Drawing.Point(16, 216));
this.label3.set_Name("label3");
this.label3.set_Size(new System.Drawing.Size(112, 23));
this.label3.set_TabIndex(10);
this.label3.set_Text("ImageControl Demo");
//
// label4
//
this.label4.set_Location(new System.Drawing.Point(208, 96));
this.label4.set_Name("label4");
this.label4.set_Size(new System.Drawing.Size(100, 16));
this.label4.set_TabIndex(11);
this.label4.set_Text("ListBox");
//
// timer1
//
this.timer1.set_Enabled(true);
this.timer1.add_Tick( new System.EventHandler(this.timer1_Tick) );
//
// Form1
//
this.set_AutoScaleBaseSize(new System.Drawing.Size(5, 13));
this.set_ClientSize(new System.Drawing.Size(344, 365));
this.get_Controls().Add(this.label4);
this.get_Controls().Add(this.label3);
this.get_Controls().Add(this.panel1);
this.get_Controls().Add(this.pictureBox1);
this.get_Controls().Add(this.comboBox1);
this.get_Controls().Add(this.listBox1);
this.get_Controls().Add(this.groupBox1);
this.get_Controls().Add(this.radioButton1);
this.get_Controls().Add(this.checkBox1);
this.get_Controls().Add(this.button1);
this.get_Controls().Add(this.textBox1);
this.get_Controls().Add(this.label1);
this.set_Name("Form1");
this.set_Text("Controls Demo");
this.groupBox1.ResumeLayout(false);
this.panel1.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion

/**
* The main entry point for the application.
*/
/** @attribute System.STAThread() */
public static void main(String[] args)
{
Application.Run(new Form1());
}


private void timer1_Tick (Object sender, System.EventArgs e)
{
radioButton2.set_Checked(!radioButton2.get_Checked());
panel1.Refresh();
}

private void panel1_Paint (Object sender, System.Windows.Forms.PaintEventArgs
e)
{
count++;
count%=4;

LinearGradientBrush myBrush;
switch(count)
{
case 0: {
myBrush = new LinearGradientBrush(
new Point (0,0),
new Point(300,300),
Color.get_Black(),
Color.get_White());
Point[] pts={new Point(0,0),new Point(30,90),new
Point(120,80)};
e.get_Graphics().DrawPolygon(new Pen(myBrush,1),pts);
} break;
case 1: {
myBrush = new LinearGradientBrush(
new Point(0,0),
new Point(300,300),
Color.get_Blue(),
Color.get_White());
e.get_Graphics().DrawArc(
new Pen(myBrush,1),
new Rectangle(new Point(0,0),new
Size(panel1.get_ClientSize().get_Width()-1,
panel1.get_ClientSize().get_Height()-1)),0, 360);
} break;
case 2: {
myBrush = new LinearGradientBrush(
new Point (0,0),
new Point(300,300),
Color.get_Black(),
Color.get_White());
Point[] pts={new Point(0,0),new Point(30,90),new
Point(120,80)};
e.get_Graphics().DrawLines(new Pen(myBrush,1),pts);
} break;
default: {
myBrush = new LinearGradientBrush(
new Point (0,0),
new Point(300,300),
Color.get_Black(),
Color.get_Red());
e.get_Graphics().FillRegion(myBrush, panel1.get_Region());
}
}
}
}



Lectia 3 Obiecte si clase



Obiective:
Obiecte
Clase (Constructori, Modificatori de acces, Metode)
In mod obisnuit, orice program pe care l-ati conceput sau il veti concepe este compus din doua parti
distincte: datele (de intrare si/sau iesire) si operatiile ce actioneaza asupra acestora. Este evident ca
veti specifica modul in care se va realiza reprezentarea datelor, prin intermediul tipurilor de date, si
modalitatile de actionare asupra datelor, prin intermediul functiilor. Pana in prezent, aceste doua
elemente, care sunt inseparabile si vitale in aceeasi masura unui program, au fost tratate separat.
In cele ce urmeaza vom vedea cum putem obtine o tratare unitara a acestora.
Clasele: implementarea unor tipuri abstracte de date
O caracteristica importanta a unui puternic limbaj de programare este aceea de a oferi
programatorului posibilitatea de a-si construi tipuri de date diferite de cele standard, acestea
numindu-le user defined, deci tipuri utilizator. Limbajul Java poseda aceasta caracteristica si si-o
manifesta prin intermediul cuvantului cheie class.
Astfel, am largit universul datelor, prin introducerea de noi tipuri de date, dar universul paralel, cel
al operatiilor asupra datelor a ramas acelasi, acestea actionand tot asupra unor date de tip implicit.
Pe de alta parte, deseori intereseaza mai mult efectul decat modul si elementele care au dus la
producerea acestuia. Astfel, tipurile de date utilizator nu ofera siguranta elementelor componente,
acestea fiind deseori expuse unor operatii care pot produce efecte colaterale.
Introducerea tipurilor abstracte de date ofera acea siguranta structurala si unitate a exprimarii, deci a
operatiilor. Odata intrati in lumea tipurilor abstracte de date, obtinem egalitatea dintre cele doua
elemente, datele si operatiile. Cuvantul cheie class este cel care ne deschide poarta spre lumea OOP
(Object Oriented Programming), cu ajutorul acestuia putand defini tipuri abstracte de date.
O clasa reuneste datele si operatiile in cadrul aceluiasi tip de data. In plus, exista posibilitatea
protejarii elementelor componente, atat date cat si functii, nu in vederea necunoasterii acestora de
catre utilizatorii ulteriori ci impotriva distrugerii lor accidentale (caracteristica cunoscuta sub
denumirea de incapsulare).
Astfel, putem scrie: Clasa = Date + Operatii.
Pentru a aduce un argument in plus in favoarea claselor sa tinem cont ca in programarea standard,
modulata sau nu, programul este cel care sumeaza datele si operatiile si nicidecum un tip de data. Si
atunci, ce inseamna un program atunci cand vorbim despre programarea orientata spre obiecte? In
mod sigur, mult mai mult decat o simpla sumare. Va lasam pe voi sa gasiti raspunsul la aceasta
intrebare.
Un exemplu de tip abstract de data implementat sub forma unei clase
Sa exemplificam cele mai sus prezentate pe cazul numerelor circulare. Prin numar circular
intelegem un numar al carui domeniu de valori este circular, deci ajuns la valoarea maxima,
urmatoarea valoare ce o va lua va fi cea minima, urmand sa parcurga, din nou, intreg domeniul de
valori. Ca exemple de numere circulare nu amintim decat unghiurile, avand domeniul de valori
intervalul [0
o
,360
o
].
Observam ca, odata cu mentionarea numarului ca fiind circular se va specifica si intervalul in care
acesta poate lua valori. Abordand aceasta problema prin intermediul claselor, vom defini un nou tip
de data care va reuni atat datele, variabile de instantiere, cat si functiile, ca metode membre ale
clasei..
public class CircularNum {
private int num,upper,lower;

public CircularNum() {
num=lower=upper=0;
}

public void setLimits(int l,int u) {
lower=l; upper=u;
}

public int setVal(int v) {
int range=upper-lower+1;

while (v>upper) v-=range;
while (v<lower) v+=range;
return num=v;
}

public int getVal() {
return num;
}

public String toString() {
return new String(""+num+" between "+lower+" and "+upper);
}

public static void main(String[] s) {
CircularNum angle = new CircularNum();
CircularNum x_coord = new CircularNum();

angle.setLimits(0,359);
angle.setVal(570);
System.out.println(""+angle);

x_coord.setLimits(0,79);
x_coord.setVal(-15);
System.out.println("Coordonata x este: "+x_coord.getVal());
}
}
Metode
Faptul ca o functie apartine unei clase, deci este functie membra a acelei clase, este specificat prin
plasarea implementarii functiei in cadrul declaratiei clasei respective. O astfel de functie o vom
numi metoda a clasei.
Modificand semnatura metodei si mai precis, lista parametrilor acesteia, este posibila obtinerea mai
multor implementari ale aceleeasi metode in cadrul unei clase, fara a exista pericolul ambiguitatii.
De exemplu metoda setVal ar putea avea doua variante:
public class CircularNum {

public int setVal(int v) {
int range=upper-lower+1;

while (v>upper) v-=range;
while (v<lower) v+=range;
return num=v;
}

public int setVal() {
return setVal(lower);
}

}
Fiecare metoda membra poseda un argument ascuns, numit this, care este pasat automat metodei de
catre compilator. Acest argument nu este altceva decat un pointer catre obiectul care realizeaza
apelul metodei, si care realizeaza uniunea dintre membrii unei clase si metodele care actioneaza
asupra acestora, deci functiile membre. Intelegerea modului de actionare a acestui pointer este utila
in descoperirea modului de functionare al functiilor membre.
Cu toate ca utilizarea explicita a lui this este rar intalnita, acesta poate fi mentionat in cadrul unei
metode membre:
public int setVal(int num) {
int range=upper-lower+1;

while (num>upper) num-=range;
while (num<lower) num+=range;

return this.num=num;
}

Ascunderea informatiei
Incapsularea presupune mult mai mult decat simpla reuniune dintre date si functii, ea invoca si
fenomenul de ascundere a informatiei. Acest lucru este posibil prin limitarea accesului la datele
membre unei clase, uneori chiar functii, acestea fiind componente a caror comportare poate sa
ramana ascunsa exteriorului clasei, interesand numai efectul lor.
Poate ca ar fi sugestiv exemplul unui ceas. Cu toate mecanismele sale complicate, acesta este usor
de manuit, noi avand acces numai la cateva butoane, deci actionand asupra catorva elemente.
Acestea, la randul lor, provoaca declansarea unui proces care se va finaliza prin modificarea orei,
respectiv a datei. Nu ne intereseaza structura intima a obiectului (ca utilizatori vorbind).
Modificatori de acces
In cadrul declararii unei clase exista trei variante, trei grade de blocare a accesului la elementele
componente, date sau functii. Aceste nivele sunt:
private - membrii fiind accesibili numai functiilor membre;
protected - posedand caracteristicile lui private numai ca, in plus, membrii sunt accesibili si
claselor derivate;
public - acesti membri fiind accesibili oricarei apelari exterioare.
De retinut ca ordinea in care sunt utilizate aceste trei grade ale accesibilitatii nu este impusa, dar
membrii unei clase neinclusi in niciunul din aceste nivele sunt presupusi a fi privati, deci private.
Revenind la exemplul utilizat pana acum, observam ca datele sunt private iar metodele sunt lasate
publice. In acest caz singurele elemente ale clasei la care utilizatorul are acces direct sunt functiile
membre declarate publice, prin cuvantul cheie public, restul de elemente fiind manevrate prin
intermediul acestora.
Metodele care realizeaza modificari ale valorilor atributelor clasei se numesc modificatori (cele care
debueaza prin set...) iar cele care realizeaza inspectarea acestor valori se numesc metode de acces
(cele care debuteaza prin get...). Insistam asupra unui aspect deosebit de important, si anume,
modificarea unor date private se poate realiza numai prin intermediul unor functii membre.
Constructori
Constructorii nu numai ca atribuie valori initiale elementelor membre dar pot efectua diferite
operatii cum ar fi alocare dinamica de memorie, deschideri de fisiere si enumerarea ar putea
continua. Un constructor este un tip special de metoda membra avand acelasi nume cu numele clasei
a carei membra este.
public class CircularNum {

public CircularNum() {
num=lower=upper=0;
}

}
In cadrul constructorului pot fi apelate alte functii, membre sau nu.
Apelul contructorilor se va produce in locul declararii unui obiect. In cazul nostru, putem declara o
variabila de tip CircularNum prin

CircularNum angle = new CircularNum();

Momentul in care este apelat un constructor trebuie cautat in cadrul executiei programului, mai
precis in momentul declararii obiectului respectiv. Constructorii garanteaza initializarea corecta a
obiectului inaintea utilizarii sale efective. In cazul nostru, mai intai se stabileste domeniul unui
numar circular si abia apoi i se atribuie o valoare.
Ca orice alta metoda, constructorul poate fi redefinit prin utilizarea a diferite semnaturi. Iata cateva
alte variante posibile ale constructorului clasei CircularNum, impreuna cu apelurile corespunztoare:
public class CircularNum {

public CircularNum() {
num=lower=upper=0;
}

public CircularNum(int l, int u) {
if (l<u) {
num=lower=l;
upper=u;
} else {
num=lower=u;
upper=l;
}
}

public CircularNum(int num, int l, int u) {
this(l,u);
setVal(num);
}

}

Prima varianta de constructor este constructorul implicit, iar cea de a treia varianta utilizeaza apelul
celei de a doua (cu doi parametri) impreuna cu apelul unei metode membre, setVal(). Apelul
constructorilor este:


CircularNum ob1=new CircularNum(),
ob2=new CircularNum(0,360),
ob3=new CircularNum(30,0,360);


Lectia 4 Ierarhii de clase



Obiective:
Compunere si mostenire
Ierarhii de clase

Reutilizarea codului
Nu de putine ori, scriind programe in maniera clasica, eram pusi in situatia de a rescrie, readapta,
proceduri scrise anterior, deseori oprindu-ne asupra metodelor utilizate in cadrul acestora. Era clar
ca, acea etapa a procesului de implementare dura mai mult timp decat ar fi fost necesar. In plus,
exista riscul aparitiei de erori, din diferite motive.
Solutia in aceasta directie ne este oferita tot de programarea orientata spre obiecte, oferindu-ne doua
modalitati de a reutiliza codul:
prin compunere: deci includerea de obiecte in cadrul altor obiecte,
prin mostenire: deci prin crearea unor obiecte completand colectia de obiecte existente.
Compunerea
Prin includerea unui obiect in cadrul altuia, acesta din urma va avea drept elemente membre, toate
elementele membre ale obiectului inclus. Este o situatie asemanatoare cu includerea de structuri in
cadrul structurilor.
Accesul catre elementele membre ale obiectului inclus se va realiza, evident, prin intermediul
acestuia.
class Point2D {
protected float x,y;

public Point2D() {
x=y=0;
}

public Point2D(float x,float y) {
set(x,y);
}

public void set(float x, float y) {
this.x=x;
this.y=y;
}

public float getX() {
return x;
}

public float getY() {
return y;
}

public String toString() {
return ""+x+" , "+y;
}
}

public class CircleByComposition {
protected Point2D center;
protected float radius;

public CircleByComposition () {
center=new Point2D();
radius=0;
}

public void setRadius(float r) {
radius=r;
}

public void setCenter(Point2D p) {
center=p;
}

public float getRadius() {
return radius;
}

public Point2D getCenter() {
return center;
}

public String toString() {
return "Circle with center at "+center+" and radius of "+radius;
}

public static void main(String[] s) {
CircleByComposition c = new CircleByComposition ();
c.setRadius(10);

c.getCenter().set(15, 7);

System.out.println(""+c);
}
}
Mostenirea
O varianta mult imbunatatita de reutilizare a codului, este aceea de a mosteni proprietatile unor
obiecte construite anterior, in vederea obtinerii de noi obiecte.
Mostenirea se caracterizeaza prin trecerea atributelor de la o clasa, de baza, la alta, derivata, asa
cum clasa insectelor este clasa de baza atat pentru clasa albinelor cat si cea a tantarilor.
Deci clasele derivate poseda toate caracteristicile clasei de baza. In plus, derivatiile pot fi imbogatite
structural si/sau functional. Pe de alta parte, incercand o reprezentare a claselor, observam o
ierarhizare, o asezare pe nivele, asemanatoare arborilor. Spunem asemanatoare datorita faptului ca
exista posibilitatea ca o clasa derivata, deci un FIU, sa aiba mai multe clase de baza, mai multi
TATI, ordinea importantei nivelelor ramanand insa aceeasi.
Functie de necesitati, derivarea claselor va fi un proces cu durata variabila. In acest sens, se prefera
conceperea unor clase de baza simple in locul unora dezvoltate, cea din urma varianta ducand
deseori la mosteniri incomode, de prisos.
Avantaje ale mostenirii
Chiar daca, la un prim contact cu acest concept, ar parea ca mostenirea este asemanatoare cu
procesul de includere a obiectelor in obiecte, exista cateva elemente caracteristice mostenirii si care
nu sunt regasite in cazul compunerii:
codul poate fi comun mai multor clase,
clasele pot fi extinse, deseori fara a se recompila clasele originale,
functiile utilizand obiecte din clasa de baza pot utiliza in mod automat si obiecte derivate ale
acelei clase.
class Point2D {
protected float x,y;

public Point2D() {
x=y=0;
}

public Point2D(float x,float y) {
set(x,y);
}

public void set(float x, float y) {
this.x=x;
this.y=y;
}

public String toString() {
return ""+x+" , "+y;
}

public float getX() {
return x;
}

public float getY() {
return y;
}
}

public class CircleByExtension extends Point2D {
protected float radius;

public CircleByExtension() {
radius=0;
}

public void setRadius(float r) {
radius=r;
}

public void setCenter(_Point2D p) {
x=p.getX();
y=p.getY();
}

public float getRadius() {
return radius;
}

public _Point2D getCenter() {
return new _Point2D(x,y);
}

public String toString() {
return "CircleByExtension with center at "+x+" , "+y+" and radius of "+radius;
}

public static void main(String[] s) {
CircleByExtension c = new CircleByExtension();
c.setRadius(10);

c.setCenter(new _Point2D(15, 7));

System.out.println(""+c);
}
}
Astfel, elementele membre ale clasei de baza devin elemente membre si ale clasei derivate, obiectul
intermediar disparand. Clasele derivate sunt tratate ca subclase ale claselor de baza. Pornind de la
acest aspect, obiectele derivate pot fi atribuite obiectelor de baza

Point2D p;
CircleByExtension c;
p=c;

fara a fi necesara o conversie de tip. In astfel de atribuiri, se vor copia numai membrii clasei de baza,
adica:


p.x=c.x;
p.y=c.y;

In plus, nu putem efectua atribuiri de acest tip unor obiecte ce nu sunt legate prin relatia de
mostenire.
Polimorfismul
Deseori, motivul pentru care derivam o clasa nu este acela de a o imbunatati din punct de vedere
structural ci de a redefini, respectiv rescrie, functionalitatea acesteia.

Atunci cand functiile unei clase de baza sunt rescrise intr-una derivata spunem ca aceste clase sunt
polimorfe. Aceasta denumire trebuie sa ne sugereze faptul ca vom avea o singura denumire si mai
multe actiuni, altfel spus, o singura interfata, metode multiple.
Sa vedem acum cum arata obiectele polimorfe. Pentru aceasta, sa ne uitam la functia membra
toString() a claselor Point2D si CircleByExtension, functie ce va avea ca efect returnarea
informatiilor asupra starea obiectului corespunzator. Cum CircleByExtension provine din Point2D,
CircleByExtension si Point2D sunt obiecte din aceeasi categorie, altfel spus, sunt polimorfe.
Pentru a obtine obiecte polimorfe, va trebui sa construim o ierarhie de clase si apoi sa redefinim
functiile apartinand clasei de baza in clasele derivate.
Astfel, daca modificam contextul functiei main() din exemplul anterior cu:
public static void main(String[] s) {
CircleByExtension c = new CircleByExtension();
c.setRadius(10);
c.setCenter(new _Point2D(15, 7));

Point2D p;

p = new Point2D(2,3);
System.out.println("p as Point"+p); // apel toString() ptr p ca Point2D

p=c;
System.out.println("p as Circle"+p); // apel toString ptr p ca CircleByExtension
}
observam cele doua apeluri ale metodei toString() asociate obiectului p, identice ca formulare dar
diferite ca efect, datorita tipului obiectului la momentul rularii aplicatiei.
Lectia 5 Clase abstracte si interfete



Obiective:
Clase abstracte
Interfete

Clase abstracte

In cele mai multe situatii, clasa de baza a unei ierarhii va trebui sa fie foarte generala, elementele
specifice ramanand a fi atasate derivarilor acesteia. De fapt, generalitatea clasei de baza poate atinge
un astfel de grad incat, aceasta clasa nici sa nu intervina in crearea obiectelor. Astfel de clase se
numesc clase abstracte.

Atunci cand in cadrul unei clase, cel putin o metoda ramane la stadiul de semnatura (fara a i se da si
implementarea), acea metoda se numeste abstracta, iar clasa, devine, implicit, clasa abstracta. In
aceasta situatie, clasa nu va putea servi "decat" ca punct de intrare intr-o ierarhie de clase,
instantierea obiectelor din clasa respectiva fiind imposibila.

Abstractizarea trebuie inteleasa in adevaratul sens al cuvantului deoarece nu este permisa definirea
de obiecte din astfel de clase. Trebuie construite mai intai clase derivate din acestea, in cadrul carora
se vor redefini metodele abstracte. In cazul in care raman metode neimplementate, clasele derivate
in aceasta situatie raman abstracte. Cu alte cuvinte, o clasa abstracta poate fi extinsa de o alta clasa,
abstracta sau nu.

abstract class Figure {
double x,y;

public Figure(double x,double y) {
this.x=x;
this.y=y;
}

public String toString() {
return "x "+x+" y "+y;
}

abstract double area();
}

class Circle extends Figure {
double radius;

public Circle(double x,double y,double r) {
super(x,y);
radius=r;
}

public String toString() {
return super.toString()+" radius "+radius+" area "+area();
}

public double area() {
return Math.PI*radius*radius;
}
}

class Rectangle extends Figure {
double dx,dy;

public Rectangle(double x,double y,double dx,double dy) {
super(x,y);
this.dx=dx;
this.dy=dy;
}

public String toString() {
return super.toString()+" dx "+dx+" dy "+dy+" area "+area();
}

public double area() {
return dx*dy;
}
}

public class testAbstracts {
public static void main(String[] s) {
Figure f=new Circle(1,2,4);
System.out.println(""+f);

Circle c=new Circle(1,1,3);
System.out.println(""+c);

Rectangle r=new Rectangle(1,2,5,10);
System.out.println(""+r);
}
}
Constructorii nu pot fi metode abstracte.
Definind o clasa abstracta, reusim sa stabilim un protocol de comunicare cu utilizatorul. Protocolul,
unic fiind, va fi atasat unui set de metode, caracteristic claselor derivate, altfel spus interfata este
unica, iar metodele multiple.
Interfete
Ca o solutie pentru obtinerea mostenirii multiple, Java ofera instrumentul de lucru al interfetelor. O
interfata consta intr-o colectie de constante si semnaturi de metode care urmeaza a fi implementate
in clasele care utilizeaza interfata. Aceste metode sunt implicit publice. Obiectele de tip interfata pot
fi utilizate atat ca argumente ale metodelor dar si ca rezultat al acestora. Cu ajutorul ierarhiilor pot fi
obtinute ierarhii de interfete.
abstract class Location {
double x,y,z;

public Location(double x,double y,double z) {
this.x=x;
this.y=y;
this.z=z;
}

abstract public String toString();
}

interface _2D {
double area();
}

interface _3D {
double volume();
}

abstract class Object2D extends Location implements _2D {

Object2D(double x,double y) {
super(x,y,0);
}
public String toString() {
return "x "+x+" y "+y+" z "+z +" area "+area();
}
}

abstract class Object3D extends Location implements _2D,_3D {
Object3D(double x,double y,double z) {
super(x,y,z);
}

public String toString() {
return "x "+x+" y "+y+" z "+z+" area "+area()+" volume "+volume();
}
}

class Circle extends Object2D {
double radius;

public Circle(double x,double y,double radius) {
super(x,y);
this.radius=radius;
}

public double area() {
return Math.PI*radius*radius;
}
}

class Sphere extends Object3D {
double radius;

public Sphere(double x,double y,double z,double radius) {
super(x,y,z);
this.radius=radius;
}

public String toString() {
return "x "+x+" y "+y+" z "+z+" radius "+radius+" area "+area()+" volume
"+volume();
}

public double area() {
return 4*Math.PI*radius*radius;
}

public double volume() {
return 4.*Math.PI*radius*radius*radius/3.;
}
}

public class testInterfaces1 {
public static void main(String[] s) {
_2D f=new Circle(1.,2.,4.);
System.out.println(""+f);

f=new Sphere(1.,1.,3.,4.);
System.out.println(""+f);

}
}
Evident ca puteam deriva clasa Object3D din clasa Object2D, lasand-o sa implementeze doar
interfata _3D dar, intr-o astfel de implementare, nu mai era la fel de clar ce metode raman de
implementat la nivelul clasei Object3D.
Mai trebuie observata si utilizarea interfetei _2D ca tip al obiectului f (din cadrul main).


Lectia 6 Tratarea erorilor prin exceptii



Obiective:
Detectarea si prinderea unei exceptii, Blocul try-catch,
Exceptii standard in Java,
Construirea propriilor exceptii.

Ce este o exceptie?

O exceptie este, de fapt, un eveniment care nu permite executia normala a metodei sau domeniului
de scop in cadrul caruia acesta apare. Aparitia acestui eveniment poate fi identificata prin testarea
explicita a unor conditii (exceptionale) sau poate fi semnalata chiar de interpretorul Java. Este
importanta distinctia dintre conditiile exceptionale si problemele normale care pot apare in contextul
aplicatiei curente. O conditie exceptionala nu permite continuarea procesarii deoarece informatia
necesara contextului curent lipseste; tot ceea ce se poate face este trecerea la contextul (metoda,
domeniu,) urmator.

Ce se intampla atunci cand este lansata o exceptie?

Se creaza un obiect de tip Exception (prin new).
Calea de executie in cadrul careia exceptia a aparut (si deci cea pe care nu o putem continua)
este intrerupta
Din contextul curent generator de exceptie este lansat obiectul de tip Exception (prin throw)
Mecanismul de tratare a exceptiei cauta un loc in program de unde poate continua o executie
normala a acestuia. Iar acesta este locul in care se trateaza exceptia (prin try-catch).

Lansarea exceptiilor:

throw Expresie;

Tratarea exceptiilor se realizeaza prin:

try {
... // instructiuni prin a caror executie poate apare exceptia
} catch (Argument) {
// instructiuni de tratare a exceptiei
}

sau

try {
... // instructiuni prin a caror executie poate apare exceptia
} catch (Argument) { }

catch (Argument) { }

sau

try{
} finally {
// instructiuni de tratare a exceptiei
}

sau

try{

} catch (Argument) {
// instructiuni de tratare a exceptiei
} finally {}

Exceptiile standard in Java sunt urmatoarele (toate derivand din clasa Exception):

RuntimeException IllegalMonitorStateException ProtocolException
ArithmeticException NullPointerException SocketException
IndexOutOfBoundsException SecurityException UnknownHostException
ArrayIndexOutOfBoundsException EmptyStackException UnknownServiceException
StringIndexOutOfBoundsException NoSuchElementException ClassNotFoundException
ArrayStoreException IOException CloneNotSupportedException
ClassCastException EOFException IllegalAccesException
IllegalArgumentException FileNotFoundException NoSuchMethodException
IllegalThreadStateException InterruptedIOException AWTException
NumberFormatException UTFDataFormatException InstantiationException
NegativeArraySizeException MalformedURLException InterruptedException

Construirea propriilor exceptii

Prin extinderea clasei Exception putem defini exceptii adaptate aplicatiei curente. Exemplul de mai
jos este edificator in acest sens.

class MyException extends Exception {
MyException(String s) {
super(s) ;
}
}

class Example {
static void trigger() throws MyException {
throw new MyException (Dont worry be happy!);
}
}

public static void main(String[] s) {
System.out.println(Food is expensive!);
try {
trigger();
} catch (MyException e) {
// System.out.println(Positive attitude:);
System.out.println(e);
} finally {
System.out.println(It can be worst!);
}
}

Executia exemplului anterior va produce iesirea urmatoare la terminal:

Food is expensive!
Dont worry, be happy!
It can be worst!

Secventa specificata prin finally este executata indiferent daca exceptia a aparut sau nu.



Lectia 7 Sistemul I/O



Obiective:
Tipuri de intrari si iesiri
Lucrul cu fisiere,
Fluxuri de date,
Analiza lexicala.
Serializarea obiectelor

Tipuri de intrari
Intrarile in Java sunt obtinute prin intermediul ierarhiei de clase ce are drept clasa de baza
InputStream, aceasta ierarhie tratand intrari provenind de la siruri de byte
(ByteArrayInputStream), de la String (StringBufferInputStream), din fisiere (FileInputStream),
din mecanismul pipe (PipedInputStream), dintr-o secventa de fluxuri colectate toate intr-unul
singur (SequenceInputStream), sau alte surse (FilterInputStream, ObjectInputStream,
DataInputStream, BufferedInputStream).

Tipuri de iesiri
Iesirile Java pot fi realizate pornindu-se de la clasa de baza OutputStream, printr-un sir de byte
(ByteArrayOutputStream), printr-un fisier (FileOutputStream), un pipe (PipeOutputStream),
sau altele (PrintStream, ObjectOutputStream, FilterOutputStream, DataOutputStream).

Un exemplu binecunoscut in randul programatorilor C/C++ il constituie programul care afiseaza pe
terminal, deci la iesirea standard, ceea ce se tasteaza, deci intrarea standard (programul echo).
Varianta Java a acestui program ilustreaza uzul dispozitivelor standard, System.in si System.out,
in cele ce urmeaza.

import java.io.*;

public class Echo {
public static void main(String[] s) {
DataInputStream in = new DataInputStream(
new BufferedInputStream(System.in)
);
String myinput;

try {
while((myinput = in.readLine()).length() != 0)
System.out.println(myinput);
} catch(Exception e) {
e.printStackTrace();
}
}
}

Observati ca intrarea, retinuta in myinput, nu este recuperata, si deci disponibila afisarii, decat dupa
apasarea lui Enter.

Lucrul cu fisiere
Utilizarea fisierelor apare in mod frecvent in 3 situatii; ca flux de intrare, ca flux de iesire sau ca
director. Vor trata pe rand toate aceste ipostaze. Pentru ilustrarea utilizarii unui fisier ca flux de
intrare, respectiv de iesire, sa consideram exemplul urmator care implementeaza o clasa (CopyFile)
ce are drept scop copierea fisierului precizat ca prim argument in fisierul avand numele cel de al
doilea argument al liniei de comanda (fara sa numaram si cuvantul java si CopyFile).

import java.io.*;

public class CopyFile {
public static void main(String[] s) {
if (s.length!=2) System.out.println("Ask the teacher...or find out yourself!");
else
try{
FileInputStream in = new FileInputStream(s[0]);
FileOutputStream out = new FileOutputStream(s[1]);
int readed=in.read();

while (readed>-1) {
out.write(readed);
readed=in.read();
}
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("See you next time!");
}
}
}

Tot despre fisiere vorbim si atunci cand dorim sa inspectam continutul directoarelor.

import java.io.*;

class PDFFilter implements FilenameFilter {
public boolean accept(File dir, String fileName) {
return fileName.endsWith(".pdf")||fileName.endsWith(".PDF");
}
}

public class DirectoryList {

public static void main(String[] s) {
String workingDirectory=".";
if (s.length==1) workingDirectory=s[0];

// File list WITHOUT filter

File directoryFile =new File(workingDirectory);
String directoryListWithoutFilter[]=directoryFile.list();
System.out.println(workingDirectory+" contains the following NON-FILTERED
files:");
for (int i=0;i<directoryListWithoutFilter.length;i++)
System.out.println(directoryListWithoutFilter[i]);

// File list WITH filter
FilenameFilter pdfFilter=new PDFFilter();
String directoryListWithFilter[]=directoryFile.list(pdfFilter);
System.out.println(workingDirectory+" contains the following FILTERED
files:");
for (int i=0;i<directoryListWithFilter.length;i++)
System.out.println(directoryListWithFilter[i]);
}
}


Analiza lexicala
In general, prin analiza lexicala a unui sir de caractere consta in impartirea acestuia in atomi lexicali
(cuvinte, numere, caractere cu rol de separator).

import java.util.*;
import java.io.*;

public class LexicalAnalysis {

static String[] tokens={"strawberry","apple","cherry","caise"};
static StringTokenizer st;

public static void main(String[] s) {
System.out.println("Which fruits do you prefer to eat in june?");
System.out.println("Separate your answers using \"space\" ");
DataInputStream in = new DataInputStream(
new BufferedInputStream(System.in)
);
String myinput;

try {
while((myinput = in.readLine()).length() != 0)
analyze(myinput);
} catch(Exception e) {
e.printStackTrace();
}
}

static void analyze(String s) {
System.out.println("Your answer is : " + s);
st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
String token = st.nextToken();
boolean correctFruit=false;
for (int i=0;i<tokens.length;i++) {
if (token.equals(tokens[i])) { correctFruit=true; break; }
}
if (!correctFruit) System.out.println(""+token+" is not in june!!!");
}
}
}

Raspunsul utilizatorului este supus analizei prin StringTokenizer atata timp cat exista tokeni,
hasMoreTokens(), fiecare token de analizat fiind obtinut prin nextToken().

Daca sirul de analizat este prea complex, se poate utiliza o combinatie de StringBufferInputStream
si StreamTokenizer.

import java.util.*;
import java.io.*;

public class LexicalStreamAnalysis {

static String[] tokens={"strawberry","apple","cherry","caise"};
static StreamTokenizer st;

public static void main(String[] s) {
System.out.println("Which fruits do you prefer to eat in june?");
System.out.println("Separate your answers using \"space\" ");
try {
Reader in = new InputStreamReader(System.in);
analyze(in);
in.close();
} catch (Exception e) { e.printStackTrace(); }

}

static void analyze(Reader in) {
try {
st = new StreamTokenizer(in);
int type = st.nextToken();

while (type!=StreamTokenizer.TT_EOF) {
if (type==StreamTokenizer.TT_WORD) {
boolean correctFruit=false;
for (int i=0;i<tokens.length;i++) {
if (st.sval.equals(tokens[i])) {
correctFruit=true; break;
}
}
if (!correctFruit) System.out.println(""+st.sval+" is not in
june!!!");
}
type=st.nextToken();
}
} catch (Exception e) { e.printStackTrace(); }
}
}

Serializarea obiectelor
Nu rare sunt situatiile in care se doreste fie transmiterea de obiecte intre aplicatii diferite (prin
intermediul asa-numitelor fisiere cu tip), fie recuperarea in cadrul unei aceleeasi aplicatii a
obiectelor produse in cadrul rularilor anterioare ale acesteia. In oricare din cele doua situatii, Java
ofera un mecanism special de salvare/recuperare a obiectelor, mecanism numit serializare.
Pentru a putea serializa instantele unei clase, aceasta trebuie sa implementeze (direct sau prin
mostenire) interfata java.io.Serializable iar clasele implicate in serializare si care asigura fluxurile
de obiecte dinspre si inspre aplicatie sunt ObjectOutput, ObjectOutputStream si ObjectInput,
ObjectInputStream.

Urmatorul exemplu contine elementele esentiale ale unei aplicatii ce opereaza cu obiecte
serializabile.

import java.io.*;

public class GraphicalObject implements Serializable {
public int x,y;
public transient int oldx,oldy;
public String name="noname";

public GraphicalObject(String name, int x,int y) {
this.name=name;
this.x=x;
this.y=y;
}

public String toString() {
return "Object: "+name+" has "+x+" , "+y + " coordinates.";
}

public void setX(int x) {
oldx=this.x;
this.x=x;
}

public void setY(int y) {
oldy=this.y;
this.y=y;
}

public void setName(String name) {
this.name=name;
}

public int getX() {
return x;
}

public int getY() {
return y;
}

public String getName() {
return name;
}

public static void main(String[] s) {
if (s.length!=1) System.out.println("Use SAVE to produce an object or \n use
LOAD to load an produced object!");
else {
try {
if (s[0].toUpperCase().equals("SAVE")) {
int randX=(int)(Math.random()*100);
int randY=(int)(Math.random()*100);
String randName=new String("GO_"+randX+"_"+randY);
GraphicalObject myObject = new GraphicalObject(
randName, randX,randY);
FileOutputStream out = new FileOutputStream(
"briefcase.job");
ObjectOutputStream objout = new ObjectOutputStream(
out);
objout.writeObject(myObject);
System.out.println("Object "+myObject+ " saved!");
objout.close();
out.close();
} else if (s[0].toUpperCase().equals("LOAD")) {
FileInputStream in = new FileInputStream(
"briefcase.job");
ObjectInputStream objin = new ObjectInputStream(in);
GraphicalObject myObject =
(GraphicalObject)objin.readObject();
System.out.println("Object "+myObject+ " loaded!");
objin.close();
in.close();
} else System.out.println("Ask the teacher ... or find out
yourself!");
} catch (IOException e) { e.printStackTrace(); }
catch (ClassNotFoundException ce) { ce.printStackTrace(); }
}
}
}
Observati ca exista atribute ale obiectelor GraphicalObject care nu sunt serializabile (utilizandu-se
in declaratia acestora cuvantul transient).

S-ar putea să vă placă și