46028984 Interfete Windows in C

Embed Size (px)

DESCRIPTION

d

Citation preview

  • 91

    Interfee Windows n C# Scurt istoric

    C# (pronunai C sharp - in traducere literal C diez) este un limbaj de programare orientat pe obiecte asemntor limbajului C++. El a fost dezvoltat de firma Microsoft, ca soluie standard pentru dezvoltarea aplicaiilor Windows. Creatorii lui sunt Anders Hejlsberg (autor al limbajelor Turbo Pascal i Delphi), Scot Wiltamuth i Peter Golde.

    C# respect standardul ECMA-334 (European Computer Manufactures Association).

    Limbajul C# folosete Microsoft .NET Framework, o colecie de clase care poate fi descrcat prin Internet i care este ntreinut i ameliorat permanent de Microsoft. Prima versiune dateaz din 2001, deci toat aceast soluie tehnologic este de dat recent.

    Clasele coninute n .NET sunt neutre fa de limbaj (aplicaiile pot fi scrise n diverse limbaje) i uureaz munca de programare n realizarea interfeelor aplicaiilor, accesul la date, conectarea la servere de baze de date, accesarea resurselor din Internet, programarea aplicaiilor bazate pe comunicaii prin reele, etc..

    Aplicaiile care folosesc .NET sunt executate ntr-un mediu software denumit CLR (Common Language Runtime). Acesta poate fi asimilat unui procesor virtual, asemntor mainii virtuale Java, care furnizeaz servicii de management a resurselor calculatorului, asigurare a stabilitii i securitii execuiei. Dei Microsoft a conceput CLR ca soluie destinat propriilor sisteme de operare, la ora actual exist astfel de procesoare virtuale i pentru alte sisteme de operare. Astfel, n cadrul proiectului Mono - www.gomono.com, susinut de compania Novell, s-au dezvoltat soluii alternative pentru Linux, Solaris, Mac OS, BSD, HP-UX, i chiar Windows, asigurndu-se astfel portabilitatea aplicaiilor scrise n limbaje bazate pe .NET.

    Tratarea programelor scrise n C#

    Un program scris n C# este supus unei prime compilri n urma creia se obine un cod scris ntr-un limbaj intermediar (CIL - Common Intermediate Language). n

  • 92

    aceast form aplicaia este apoi trimis procesorului virtual (CLR) care realizeaz traducerea n cod main i execut aplicaia.

    Realizarea unei aplicaii elementare n C#

    Dezvoltarea de aplicaii n C# se realizeaz folosind un mediu de programare, firma Microsoft oferind mediul profesional Visual C# .NET. O soluie alternativ gratuit poate fi versiunea Express Edition a mediului profesional (http://www.microsoft.com/express/vcsharp/), utilizabil pentru nvarea limbajului i pentru realizarea interfeelor aplicaiilor Windows. Microsoft ofer ns i varianta realizrii aplicaiilor folosind pachetul gratuit .NET Framework Software Development Kit (SDK). De altfel simpla descrcare a pachetului de baz .NET Framework pus la dispoziie de Microsoft adaug n directorul C:\Windows\Microsoft.NET\Framework\vxx\

    Compilare

    Limbaj intermediar (Common Intermediate

    Language - CIL)

    Compilare CIL - cod main i executare

  • 93

    (xx este versiunea descrcat) compilatorul csc.exe utilizabil n mod linie de comand i care produce cod executabil.

    Exemplu de aplicaie tip consol:

    class Salut {

    public static void Main() {

    System.Console.WriteLine("Salut, prieteni!"); }

    } Aplicaia tip consol va fi salvat ntr-un fiier denumit Salut.cs i apoi va fi

    compilat folosind csc.exe: >csc Salut.cs n urma compilrii va rezulta fiierul Salut.exe care poate fi executat din linia de

    comand:

    Observaie: Pentru a folosi compilatorul csc.exe fr a preciza calea este necesar

    modificarea variabilei de mediu Path. Pentru aceasta se va accesa Control Panel / System / Advanced. n fereastra care se afieaz se va selecta Environment Variables iar n fereastra Environment Variables va fi editat variabila Path adugnd cilor deja existente calea spre directorul care conine compilatorul csc.exe. Pentru .NET versiunea 3.5, cea mai recent n momentul scrierii acestui curs, calea este: C:\WINDOWS\Microsoft.NET\Framework\v3.5.

  • 94

    Noiuni de C#

    Spaii de nume

    Spaiul de nume reprezint un concept aprut n C++ odat cu extinderea programrii obiectuale. Clasele care alctuiesc o aplicaie pot proveni din surse diferite i pot avea din ntmplare aceeai denumire. Dac programatorii au creat clasele n spaii de nume distincte, eventualele coincidene de nume pot fi uor rezovate, denumirea fiecrei clase fiind precedat de denumirea spaiului de nume cruia i aparine.

    Pentru a evita tastarea spaiului de nume naintea fiecrei denumiri de clas n C# se folosete ca i n C++ clauza using.

    .NET Framework definete peste 90 de spaii de nume, majoritatea avnd denumiri ncepnd cu System. n exemplele coninute n cursurile urmtoare vor fi frecvent folosite spaiile de nume System, System.Windows.Form i System.Drawing.

    Exemplul de aplicaie prezentat poate fi rescris folosind clauza using, clasa Console aparinnd spaiului de nume System.

  • 95

    using System; class Salut {

    public static void Main() {

    Console.WriteLine("Salut, prieteni!"); }

    }

    Comentarii

    Programele scrise n C# pot conine explicaii sub forma unor comentarii. Acestea vor asigura n timp nelegerea diferitelor metode i rolul funcional al variabilelor folosite.

    Ca i n C++, n n C# pot fi folosite dou tipuri de comentarii: comentarii "n linie", introduse prin //. Un astfel de comentariu se ncheie la

    sfritul liniei curente; comentarii pe unul sau mai multe rnduri consecutive. Zona care conine

    comentariul este delimitat prin /* (comentariu) */. De regul se folosesc comentariile n linie, cel de-al doilea tip fiind folosit frecvent

    n timpul depanrii programelor mari i complexe, pentru a suprima din program anumite zone.

    Tipuri de date

    n mare C# folosete tipurile de date simple existente i n C++. Fiecare dintre tipurile simple este ns dublat de o clas din spaiul de nume System. Rolul acelei clase este puin evident n acest moment. n cele ce urmeaz va fi inclus un exemplu n care vor fi referite proprieti ale tipurilor simple n acelai mod n care sunt referite proprieti ale claselor. De exemplu int.MaxValue, furnizeaz valoarea ntreag cea mai mare care poate fi pstrat ntr-o variabil de tip int. Tot dublarea tipurilor simple prin clase va face posibil folosirea unor variabile aparinnd unor tipuri simple n situaii n care sunt acceptate doar obiecte.

  • 96

    a. Tipuri de date ntregi: Numr de bii Tip simplu Clas Semn

    8 sbyte System.SByte cu semn 8 byte System.Byte fr semn 16 short System.Int16 cu semn 16 ushort System.UInt16 fr semn 32 int System.Int32 cu semn 32 uint System.UInt32 fr semn 64 long System.Int64 cu semn 64 ulong System.UInt64 fr semn

    Exemple de declaraii: int a = 12, b, contor; // Se putea scrie i System.Int32 a = 12, b, contor;

    b. Tipuri de date reprezentate n virgul mobil Numr de bii Tip simplu Clas

    32 float System.Single 64 double System.Double

    c. Tipul decimal Limbajul C# admite pe lng tipurile de date numerice menionate un tip nou,

    decimal. Pentru decimal lungimea de reprezentare este de 128 bii iar clasa corespunztoare din spaiul de nume System este System.Decimal.

    d. Tipul bool C# admite declararea de variabile logice, ale cror valori posibile sunt true i

    false. Pentru declararea unei astfel de variabile se folosete bool, clasa corespunztoare din spaiul de nume System fiind System.Boolean.

    Operatorii relalionali (==, !=, =) genereaz o valoare de tip bool.

    e. Tipul char

  • 97

    Tipul char permite declararea unei variabile care va conine un caracter n format Unicode (pe 16 poziii binare). Clasa corespunztoare din spaiul de nume System este System.Char.

    f. tipul string O simplificare semnificativ pe care o aduce C# n raport cu C++ este

    introducerea tipului string pentru declararea variabilelor care conin iruri de caractere. Clasa corespunztoare din spaiul de nume System este System.String.

    Exemple: string a = "X = "; // Se putea i System.String a = "X = "; double p = 129.2; int nr = a.Length; // .Length furnizeaz lungimea irului a. string b = a + p + "mm";

    n C# operatorul '+' indic fie operaia de adunare fie cea de concatenare (unire) a dou iruri de caractere. Pentru toate tipurile de date menionate (mai exact pentru toate tipurile derivate din clasa Object, rdcina ierarhiei de clase destinate pstrrii datelor) este definit metoda ToString() care returneaz o reprezentare sub form de ir de caractere a valorii variabilei pentru care este apelat. Expresia care definete valoarea variabilei b ncepnd cu a, un string, variabila real p este automat convertit n ir de caractere chiar dac nu este apelat n mod explicit metoda ToString(). O soluie mai clar ar fi fost ns:

    string b = a + p.ToString() + "mm";

    g. Variabile de tip tablou O variabil de tip tablou se declar adugnd o pereche de paranteze drepte ([ ])

    dup cuvntul rezervat care definete tipul valorilor coninute. Exemplu: int [ ] tab; Dup declarare valoarea variabilei tab este null. Variabila va primi o valoare

    diferit de null n momentul rezervrii unei zone de memorie pentru pstrarea elementelor tabloului, folosind operatorul new:

    tab = new int[12]; De obicei declararea se combin cu alocarea de memorie, scriindu-se: int [ ] tab = new int[12];

    sau, dac se realizeaz concomitent i atribuirea de valori: int tab [ ] = new int[4] {1, 4, -2, 5}; // sau chiar mai simplu: int tab [ ] = {1, 4, -2, 5};

  • 98

    Ulterior se poate folosi variabila tab pentru un alt ir de valori int, astfel: tab = new int[5];

    n acest caz, dei nu s-a realizat o eliberare explicit a memoriei (n C# nu exist operatorul delete), blocul de memorie alocat iniial va fi n mod automat eliberat i repus la dispoziia aplicaiei. Procesul de identificare a blocurilor de memorie devenite disponibile face obiectul activitii unei componente a CLR denumit garbage collector (colector de reziduuri).

    Exemplu: S se scrie o aplicaie tip consol care afieaz valorile numerice maxime i minime care pot fi memorate folosind diferite tipuri de variabile.

    using System; class Dimens { public static void Main() {

    Console.WriteLine("Sbyte: {0} la {1}",sbyte.MinValue, sbyte.MaxValue); Console.WriteLine("byte: {0} la {1}",byte.MinValue, byte.MaxValue); Console.WriteLine("Short: {0} la {1}",short.MinValue, short.MaxValue); Console.WriteLine("uShort: {0} la {1}",ushort.MinValue, ushort.MaxValue); Console.WriteLine("int: {0} la {1}",int.MinValue, int.MaxValue); Console.WriteLine("uint: {0} la {1}",uint.MinValue, uint.MaxValue); Console.WriteLine("long: {0} la {1}",long.MinValue, long.MaxValue); Console.WriteLine("ulong: {0} la {1}",ulong.MinValue, ulong.MaxValue); Console.WriteLine("float: {0} la {1}",float.MinValue, float.MaxValue); Console.WriteLine("double: {0} la {1}",double.MinValue, double.MaxValue);

    } }

  • 99

    Operatorii limbajului C# n definirea unui limbaj, stabilirea operatorilor care pot fi folosii la scrierea

    expresiilor i a regulilor lor de utilizare reprezint o etap important. Limbajele de nivel nalt folosesc un mare numr de operatori i chiar permit extinderea setului de operatori pentru a putea scrie expresii n care intervin variabile aparinnd tipurilor structurate (obiecte).

    Operatorii matematici din C# + - * / % (modulo) x % y furnizeaz restul mpririi ntregi a lui x la y.

    Exemplu de utilizare a operatorului '%':

    if((an % 4 == 0 && an % 100 !=0) || an % 400 == 0) System.Console.WriteLine(an + " este bisect."); Operatorul % se aplic doar tipurilor ntregi.

    Operatorul "/" poate provoca trunchiere n cazul operanzilor ntregi.

    Evaluarea expresiilor aritmetice se efectueaz de la stnga la dreapta respectnd ordinea de evaluare normal.

    Operatorii de comparare i logici Operatorii de comparare (relaionali) din C# sunt : > >= <

  • 100

    n C# termenii pentru care sunt folosii operatorii && i || sunt obligatoriu de tip bool. n C# nu opereaz regula din C conform creia o valoare numeric diferit de 0 are valoarea de adevr true i o valoare 0 are valoarea de adevr false.

    Conversiile de tip Limbajul C# este mult mai riguros n ceea ce privete corespondena tipurilor

    termenilor dintr-o expresie. Frecvent utilizarea ntr-o expresie a unor operanzi de tipuri diferite este semnalat ca eroare. Eliminarea erorilor se va face fie folosind operatorii de tanstipaj (ca n C) fie apelnd metode din clasa Convert.

    Operatorii de conversie de tip (transtipaj sau cast) (nume-tip) expresie expresie este convertit n tipul specificat : x = Math.Sqrt((double)n) alfa = (float)a / j ;

    Conversia explicit folosind metodele clasei Convert permite trecerea unei variabile sau a unei expresii dintr-un tip n altul. Exemplu:

    int z = Convert.ToInt32(312.14);

    Practic dac este necesar o conversie se va folosi facilitatea mediului de programare de a afia pemanent posibilitile de continuare a scrierii i se va selecta varianta dorit.

    Operatorii de incrementare i de decrementare ++ i -- n funcie de poziia operatorului fa de variabila incrementat, se realizeaz pre

    i post incrementare (decrementare)

  • 101

    Operatorii i expresiile de atribuire Expresia : i = i + 3;

    n care variabila din stnga egalului se repet n dreapta acestuia se mai poate scrie astfel :

    i += 3 ;

    Instruciunile limbajului C#

    Instruciunea de decidere - if

    Ca i n C, ansamblul de instruciuni cuprinse ntre acolade formeaz o instruciune compus sau un bloc de instruciuni. Instruciunile din interiorul unui bloc de instruciuni sunt executate n ordinea n care sunt scrise.

    Variante de scriere a instruciunii if

    if ( expLogica ) instruciune;

    if (expLogica ) { mai multe instruciuni }

    if (expLogica ) instruciune; else instruciune;

    if (expLogica ) { mai multe instruciuni } else { mai multe instruciuni }

    if (expLogica ) instruciune; else { mai multe instruciuni }

    if (expLogica ) { mai multe instruciuni } else instruciune;

    int n = 5 ;

    x = n++ ; atribuie 5 lui x

    x = ++n ; atribuie 6 lui x

  • 102

    Indentarea instruciunilor sau a blocurilor de instruciuni (scrierea decalat) din if nu este obligatorie dar are mare importan n nelegerea i depanarea programului.

    Instruciunea while

    Instruciunea while permite realizarea unei structuri repetitive (ciclu) condiionate anterior. Corpul ciclului poate fi executat o dat, de mai multe ori sau de loc.

    Exemplu fundamental:

    int contor = 1; while ( contor

  • 103

    valoare convenabil pentru a determina intrarea n ciclu. Exacutarea instruciunilor din corpul ciclului va corecta automat valoarea iniial.

    Pentru astfel de cazuri exist ns i o cale mai simpl, respectiv folosirea instruciunii do.

    Exemplu:

    g = 9.81; t = 0; do { d = (g * t * t ) / 2; Console.WriteLine( t + " " + d); t = t + 1; } while (d

  • 104

    break; . .

    }

    Executarea instruciunii break provoac o ieire imediat din ciclul for. Ea poate fi folosit i pentru a iei din ciclurile while sau do.

    Instruciunea foreach

    Instruciunea foreach a fost preluat n C# din Visual Basic. Ea permite parcurgerea sistematic a elementelor unui ir sau a unei liste, realizabil n C# folosind una dintre clasele din spaiul de nume System.Collection.

    Exemple: int sir = new int[12]; foreach (int i in sir) i = 10; ...

    foreach (int i in sir) Console.Write("{0} ", i);

    n exemplu, primul foreach pune 10 n toate elementele din irul de valori ir iar al doilea afieaz valorile sdin ir pe o linie.

    Instruciunea switch

    Instruciunile de ciclare prezentate, sunt folosite pentru realizarea blocurilor de instruciuni a cror execuie ncepe cu prima linie i este controlat de ctre programator. Instruciunea switch este folosit tot pentru a construi un bloc de instruciuni dar punctul de unde ncepe execuia depinde de valoarea unei expresii avnd valori ntregi.

    Sintaxa instruciunii este:

    switch (expresie) { case constanta_1 : instruciuni case constanta_2 : instruciuni . . .

  • 105

    default : instruciuni; }

    Fiecare dintre punctele de unde poate ncepe execuia blocului este etichetat printr-o constant avnd valoare ntreag. Dac expresia de testat corespunde uneia dintre constante, execuia blocului ncepe din punctul indicat de aceasta.

    Cazul default este facultativ.

    Exemplu : switch (t) { case 's': rez = Math.Sin(Math.PI * x / 180.0); Console.WriteLine("rezultatul este : " + rez); break; case 'c': rez = Math.Cos(Math.PI * x / 180.0); Console.WriteLine("rezultatul este : " + rez); break; case 't': rez = Math.Sin(Math.PI * x / 180.0) / Math.Cos(3.14159 * x / 180.0); Console.WriteLine("rezultatul este : " + rez); break; default: Console.WriteLine("Caracter incorect!"); break; }

    Ca i n cazul ciclurilor, instruciunea break provoac o ieire imediat din blocul realizat folosind switch.

    Observaie: n C# break apare i n secvena introdus prin clauza default.

    Programare obiectual n C#

    Limbajul C# permite scrierea de aplicaii folosind exclusiv programarea obiectual. O aplicaie scris n C# este alctuit dintr-un ansamblu de clase, una dintre ele fiind clasa principal deoarece conine metoda Main(), punctul de intrare n aplicaie.

    Exemplu fundamental:

  • 106

    Se consider o aplicaie care afieaz a cta zi din an este o zi dat prin definirea anului, lunii i a zilei din lun.

    Pentru rezolvarea problemei s-a creat clasa DCalend:

    class DCalend { private int anul; private int luna; private int ziua;

    public DCalend(int aa, int ll, int zz) { anul = aa; luna = ll; ziua = zz; }

    public bool AnBisect() { return (anul % 4 == 0) && ((anul % 100 != 0) || (anul % 400 == 0)); }

    public int ZiuaDinAn() { int[] luniz = new int[] { 0,31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; return luniz[luna - 1] + ziua + (luna > 2 && AnBisect() ? 1 : 0); } }

    Ca i n C++, n C# o clas conine n principal un numr de membri date sau cmpuri (anul, luna, ziua) i un numr de metode (funcii) care opereaz asupra membrilor date. Metodele clasei DCalend sunt:

    DCalend(), o metod care poart numele clasei i iniializeaz membrii date ai acesteia. n programarea obiectual o astfel de metod se numete constructor;

    AnBisect(), care returneaz o valoare bool care indic dac anul este an bisect i

    ZiuaDinAn() care calculeaz a cta zi din an este ziua definit prin valorile curente din cmpurile clasei.

    Spre deosebire de C++ n clasele C# metodele sunt scrise integral. Folosind clasa DCalend s-a scris urmtoarea aplicaie tip consol:

    using System;

    namespace POB01

  • 107

    { class Program { public static void Main(String[] args) { DCalend data = new DCalend(2007, 8, 29); Console.WriteLine("Ziua din an = {0}", data.ZiuaDinAn()); }

    }

    class DCalend { private int anul; private int luna; private int ziua;

    public DCalend(int aa, int ll, int zz) { anul = aa; luna = ll; ziua = zz; }

    public bool AnBisect() { return (anul % 4 == 0) && ((anul % 100 != 0) || (anul % 400 == 0)); }

    public int ZiuaDinAn() { int[] luniz = new int[] { 0,31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; return luniz[luna - 1] + ziua + (luna > 2 && AnBisect() ? 1 : 0); } } }

    Pe lng clasa DCalend aplicaia mai are clasa Program care conine doar metoda principal Main(). n metoda principal se declar i se iniializeaz (prin apelul constructorilui) obiectul data i apoi se afieaz pe ecran a cta zi din an este data. Pentru apelul metodelor clasei DCalend se scrie:

    data.ZiuaDinAn() dac metoda este apelat dintr-o alt clas, respectiv AnBisect() dac metoda este apelat dintr-o alt metod a aceleiai clase.

    n programarea obiectual se definete i o a treia variant de apel a unei metode, nume_clas.metod. Un exemplu este apelul deja utilizat, Math.Sin(...). Math este o clas din spaiul de nume System care conine definiiilor funciilor matematice implementate n C#. O funcie astfel apelat opereaz asupra argumentelor sale, pentru apelul ei nefiind necesar definirea n prealabil a unui obiect aparinnd aceleiai

  • 108

    clase. Pentru a declara o astfel de funcie, n programarea obiectual se folosete cuvntul rezervat static. n ecemplul dat metoda AnBisect() putea fi declarat static. Avantajul ar fi fost acela de a o putea folosi n orice aplicaie, fr a fi necesar cunoaterea clasei DCalend i fr a defini un obiect din clasa DCalend.

    Cmpurile pot fi i ele definite ca fiind statice. O astfel de soluie este indicat n cazul cmpurilor care au aceleai valori pentru toate instanele clasei. n exemplul dat, irul de valori ntregi luniz este constant, deci poate fi declarat static.

    Clasa DCalend ar fi atunci definit astfel:

    class DCalend { private int anul; private int luna; private int ziua; static int[] luniz = new int[] { 0,31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

    public DCalend(int aa, int ll, int zz) { anul = aa; luna = ll; ziua = zz; }

    public static bool AnBisect(int anul) { return (anul % 4 == 0) && ((anul % 100 != 0) || (anul % 400 == 0)); }

    public int ZiuaDinAn() { return luniz[luna - 1] + ziua + (luna > 2 && AnBisect(anul) ? 1 : 0); } }

    Proprieti

    Ca i n orice alt limbaj care permite programarea obiectual, n C# o clas are membri date denumii i cmpuri i membri coninnd cod denumii metode. Clasele C# mai pot conine i ali membri coninnd cod denumii proprieti, extrem de importani n .NET Framework.

    Originea problemei rezolvate prin introducerea proprietilor este urmtoarea:

  • 109

    n POO membrii date sunt de regul declarai privai (private). Accesul la un astfel de cmp dinafara clasei care l conine este atunci rezolvat prin adugarea unei perechi de metode:

    o metod pentru modificarea valorii, denumit de obicei setnume_camp(tip val_noua) i

    o metod pentru preluarea valorii, denumit de obicei getnume_camp(). O astfel de soluie este destul de greoaie i mrete considerabil numrul de

    metode ale claselor care trebuie scrise. De exemplu mediul de programare Netbeans destinat scrierii de aplicaii n Java ofer ca facilitate dezvoltatorilor scrierea automat a perechii de funcii de acces set - get.

    n C#, prin introducerea proprietilor se ncearc o simplificare accesului la cmpurile private.

    Exemplu: Se consider cmpul anul din clasa DCalend prezentat deja. Se poate aduga

    clasei DCalend secvena urmtoare de cod care definete proprietatea Anul:

    public int Anul { set { anul = value; } get { return anul; } }

    Se observ c proprietatea definit are acelai nume cu cmpul privat pe care l acceseaz, cu diferena c ncepe cu o majuscul. De altfel programatorii n C# denumesc n mod sistematic membrii publici ai claselor cu denumiri care ncep cu o majuscul. De asemenea se vede c definirea unei proprieti nseamn tratarea n dou secvene de cod a impunereii valorii cmpului (set : cmp = value) i a prelurii acesteia (get : return cmp). Evident secvena de cod introdus prin set poate testa valabilitatea valorii value.

    Exemplu de utilizare a proprietii n funcia Main():

    public static void Main(String[] args) {

  • 110

    DCalend data = new DCalend(2007, 8, 29); Console.WriteLine("Ziua din an = {0}", data.ZiuaDinAn()); data.Anul = 2006; Console.WriteLine("Ziua din an = {0}", data.ZiuaDinAn()); }

    Parametrii metodelor

    n C# parametrii metodelor sunt ntodeauna transferai prin valoare. Ca i n C, n acest caz modificrile operate n cadrul metodei asupra valorilor parametrilor formali ai acesteia nu schimb valorile variabilelor corespunztoare din metoda apelant. Exemplu: using System;

    namespace Test { class Invers {

    public static void Main(string[] args) { Invers z = new Invers(); z.Calcule(); }

    public void Calcule() { int a=10, b=2; Console.WriteLine("Valori initiale: a = {0}, b = {1}", a, b); Inv(a, b); Console.WriteLine("Dupa apel: a = {0}, b = {1}", a, b); }

    public void Inv(int x, int y) { int aux; aux = x; x = y; y = aux; } } }

    Metoda Inv() din exemplul dat este eronat deoarece transmiterea prin valoare a parametrilor face ca inversarea realizat s nu afecteze variabilele din metoda apelant (a i b).

  • 111

    Pentru a impune ca transmiterea parametrilor s nu se realizeze prin valoare ci prin referin, n C# se folosete clauza ref. Aplicaia din exemplul precedent ar fi trebuit scris atunci astfel:

    using System;

    namespace Test { class Invers {

    public static void Main(string[] args) { Invers z = new Invers(); z.Calcule(); }

    public void Calcule() { int a=10, b=2; Console.WriteLine("Valori initiale: a = {0}, b = {1}", a, b); Inv(ref a, ref b); Console.WriteLine("Dupa apel: a = {0}, b = {1}", a, b); }

    public void Inv(ref int x, ref int y) { int aux; aux = x; x = y; y = aux; } } }

  • 112

    Motenirea

    Toate limbajele destinate programrii obiectuale permit realizarea unor clase derivate din clase existente. Clasa derivat motenete membrii date, metodele i proprietile clasei de baz. n cadrul ei se pot ns aduga noi membri, date sau metode, prin care se realizeaz practic un proces de specializare a noii clase.

    La definirea unei clase derivate programatorul poate de asemenea nlocui unele dintre metodele clasei de baz cu metode noi, mai bine adaptate. Redefinirea metodelor clasei de baz se mai numete i suprascriere, noile metode avnd evident aceeai declaraie cu cele din clasa de baz.

    Exemplu: using System;

    namespace TestOvr { class Program { static void Main(string[] args) { Derivata obj = new Derivata(); obj.Autentifica_te(); } }

    public class ClasaDeBaza { public void Autentifica_te() { Console.WriteLine("Clasa de baza"); } }

    public class Derivata : ClasaDeBaza { public void Autentifica_te() { Console.WriteLine("Clasa derivata"); } }

    }

  • 113

    Noua clas, Derivata a fost declarat folosind sintaxa public class Derivata : ClasaDeBaza astfel indicndu-se relaia de derivare. n C# o clas poate avea o singur clas printe (nu se admite motenirea multipl).

    O situaie aparte apare n cazul metodelor declarate virtuale. Acestea fac posibil un comportament normal al obiectelor declarate ca aparinnd tipului de baz i instaniate cu obiecte aparinnd unui tip derivat. n C# la suprascrierea unei astfel de metode se precizeaz printr-un cuvnt rezervat modul n care noua metod va opera. Modurile posibile sunt override i new. Diferena dintre cele dou declaraii va fi prezentat prin dou exemple.

    a. Modul override

    using System;

    namespace TestOvr { class Program { static void Main(string[] args) { ClasaDeBaza obj = new Derivata(); obj.Autentifica_te(); } }

    public class ClasaDeBaza { public virtual void Autentifica_te() { Console.WriteLine("Clasa de baza"); } }

    public class Derivata : ClasaDeBaza { public override void Autentifica_te() { Console.WriteLine("Clasa derivata"); } } }

    Rezultat:

  • 114

    b. Modul new

    using System;

    namespace TestOvr { class Program { static void Main(string[] args) { ClasaDeBaza obj = new Derivata(); obj.Autentifica_te(); } }

    public class ClasaDeBaza { public virtual void Autentifica_te() { Console.WriteLine("Clasa de baza"); } }

    public class Derivata : ClasaDeBaza { public new void Autentifica_te() { Console.WriteLine("Clasa derivata"); } }

    }

    Rezultat:

    Tratarea excepiilor

    n timpul exectrii unui program pot aprea situaii n care o eroare (denumit i excepie program) produs ntr-un modul al programului face imposibil continuarea acestuia. Dac uneori se pot include secvene de validare a datelor pentru ca situaiile de eroare s fie evitate, n alte cazuri acest lucru nu este posibil sau ar complica mult scrierea programului. O modalitate elegant de rezolvare a situaiilor care pot aprea o

  • 115

    constituie interceptarea prin program i tratarea excepiilor. n principiu trebuie realizat o ncadrare n structuri try - catch a secvenelor de cod care ar putea genera erori n timpul execuiei, dup modelul:

    try { . . (secventa de cod generatoare de erori) } catch (Exception ex) { . . . (tratare excepie) }

    O secven de cod poate declana uneori mai multe tipuri excepii. C# permite n aceste cazuri interceptarea separat a fiecruia dintre tipurile care ar putea aprea, dup modelul:

    try { . . . (secventa de cod generatoare de erori) } catch (NullReferenceException ex) { . . . (tratare excepie 1) }

    catch (ArgumentOutOfRangeException ex) { . . . (tratare excepie 2) }

    catch (Exception ex) { . . . (tratare excepie 3) }

    Aplicaia astfel structurat conine trei blocuri de tratare a excepiilor, blocul executat stabilindu-se n mod automat n timpul execuiei. Ultimul bloc primete ca argument un obiect din clasa Exception. Aceast clas este rdcina ierarhiei de clase folosite la specificarea naturii excepiei, deci indiferent ce excepie este generat, dac niciunul dintre blocurile catch n-a fost executat, se execut ultimul bloc.

  • 116

    Realizarea unei aplicaii Windows n C#

    Pentru a exemplifica modul de funcionare al Visual Studio 2005 pentru realizarea aplicaiilor Windows, s ncercm s implementm aplicaia de calcul a greutii ideale, cunoscut deja. S pornim Visual Studio 2005 i s crem un nou proiect. De data aceasta, vom alege ca ablon de proiect Windows Application. Fie grideala numele proiectului.

    Aplicaia ne va afia un panou n care putem realiza interfaa aplicaiei. Dup cum se observ, n centrul panoului se gsete o machet numit Form1, pe care vom construi interfaa. n partea stng, este disponibil o bar cu instrumente (Toolbox) care va conine controalele pe care le vom utiliza la construirea interfeei. Aceste controale pot fi aduse pe macheta formei cu ajutorul mouse-ului. Toolbox-ul este echivalentul componentei Palette din NetBeans.

  • 117

    n partea dreapt mediul de programare afieaz panourile Solution Explorer (echivalent oarecum cu Inspector din NetBeans) i Properties (avnd acelai rol ca i n NetBeans). Primul ne afieaz componentele proiectului, iar cel de-al doilea, proprietile obiectelor de pe interfa. S incercm acum s construim interfaa din figura de mai jos.

    Pentru construirea interfeei, am utilizat trei controale Label, pentru care am modificat proprietatea Text n Inaltimea(cm):, Varsta (ani): i respectiv Greutatea (Kg):, trei controale TextBox aliniate cu controalele Label, un control CheckBox cruia i-am schimbat proprietatea Text n Barbat i dou controale Button, pentru care am schimbat proprietatea Text n Calcul i respectiv Gata.

    Fiecrui control de pe machet, i se atribuie automat un identificator (nume), n concordan cu tipul controlului. Astfel, dac vei selecta pe rnd controalele i vei vedea ce nume li s-au atribuit (proprietatea Name din panoul Properties), vei vedea de exemplu c pentru controalele TextBox s-au atribuit numele implicite textBox1, textBox2 i textBox3, controlului CheckBox i s-a dat numele checkBox1, iar butoanelor button1 respectiv button2. Putem lucra fr probleme cu aceste denumiri, ns este recomandabil s schimbm numele obiectelor n concordan cu contextul programului, cel puin a obiectelor referite n funciile care vor fi scrise.

    S redenumim controalele astfel: controalele TextBox, de sus n jos: h, v i respectiv g, iar controlul CheckBox s.

    La fel ca i n NetBeans, mediul Visual C# genereaz automat funciile de tratare a evenimentelor dorite. Pentru a scrie de exemplu funcia asociat evenimentului "Clic pe butonul Calcul" se va selecta cu un dublu clic butonul i apoi va fi editat funcia button1Click() generat de mediul de programare. Trebuie observat c numele funciei este obinut prin alturarea numelui controlului cruia i este asociat (button1) a numelui evenimentului tratat (Click).

  • 118

    Trecerea ntre modul Designer (machet) i modul editare cod, se poate face n dou moduri: fie se selecteaz din tab-urile de selecie de sus a panoului central, fie se apas butoanele din partea de sus a panoului Solution Explorer.

    S implementm acum funcia:

    private void button1_Click(object sender, EventArgs e) { Double gre; gre=50+0.75*(Convert.ToInt16(h.Text)-150)+0.25*(Convert.ToInt16(v.Text)-20); if (!s.Checked) gre=gre*0.9; g.Text=Convert.ToString(gre); }

    Ce observm. 1. i n C#, la fel ca i n Java, controalele de tip TextBox conin informaii de tip

    String. Spre deosebire de Java ns, coninutul controlului va putea fi citit sau scris mai simplu. Nu mai este nevoie s apelm metode pentru a prelua coninutul ci vom utiliza proprietatea Text. Astfel, pentru controlul h de exemplu, h.getText() din Java va deveni pur i simplu h.Text n C#;

  • 119

    2. Conversia datelor de la un tip la altul se face cu ajutorul clasei Convert. Astfel, Convert.ToInt16() va converti argumentul funciei ntr-un ntreg, Convert.ToDouble() va converti n double, Convert.ToString() ntr-un ir de caractere, etc.

    3. Nu mai este nevoie s precizm tipul explicit al literalilor, expresia fiind evaluat automat la tipul variabilei din stnga (nu mai scriem 50., este suficient s scriem 50).

    4. Starea de selecie a controlului CheckBox este accesibil prin intermediul proprietii Checked a acestuia.

    S implementm acum funcia care se va executa la apsarea butonului de terminare a aplicaiei (Gata). Va trebui s intm n Designer i s selectm butonul (dublu click). Apoi editm metoda generat:

    private void button2_Click(object sender, EventArgs e) { Application.Exit(); }

    Se poate observa imediat c echivalentul liniei System.exit(0) din Java este Application.Exit().

    nainte de execuie, aplicaia va trebui compilat. Pentru aceasta se alege Rebuild Solution din n meniul Build. Dac sunt semnalate erori, acestea vor fi afiate n partea de jos a ecranului. Se poate ajunge uor la linia pe care este eroarea selectnd cu un dublu click mesajul de eroare. Dup corectarea erorilor, aplicaia este lansat n execuie prin apsarea butonului triunghiular verde .

  • 120

    Utilizarea controalelor Windows

    S ncepem s nvm cum pot fi utilizate diferitele controale puse la dispoziie de Windows Form Designer. Primul control despre care vom discuta l cunoatei deja. Este

    Butonul

    Probabil butonul este unul din cele mai utilizate controale n interfeele Windows. Includerea unui buton n interfaa aplicaiei realizeaz adugarea unui obiect aparinnd clasei Button.

    Spre deosebire de alte clase asociate controalelor Windows, aceast clas nu este derivat direct din clasa Control, ci din clasa BaseButton, deoarece exist mai multe tipuri de butoane, despre care vom vorbi n cele ce urmeaz. Ca obiect, butonul va oferi utilizatorului un set de proprieti, un set de metode i va fi capabil s produc un set de evenimente. Cteva din proprieti sunt:

    FlatStyle seteaz aspectul butonului. Dac stilul este PopUp, butonul va apare ca fiind plat, chiar dac utilizatorul pune cursorul mouse-ului deasupra lui. n caz contrar butonul va avea aspect tridimensional;

    Enabled seteaz starea de activ/inactiv al butonului. Dac aceast proprietate este false, butonul apare ca inactiv, textul sau pictograma de pe buton sunt afiate n gri i el nu poate fi apsat;

    Image permite utilizatorului s specifice o imagine (pictogram, bitmap, etc.) ce va fi afiat pe buton;

    ImageAlign permite specificarea poziiei imaginii n cadrul butonului; TextAlign permite specificarea poziiei textului n cadrul butonului;

    n ceea ce privete evenimentele, n mod evident evenimentul principal produs de buton este Click. Acesta se produce atunci cnd utilizatorul apas butonul cu ajutorul mouse-ului, sau cnd se apas tasta Enter i butonul are controlul (focus-ul). Pentru a intercepta cest eveniment, s ne reamintim, va trebui s-i asociem o funcie de tratare (engl. handler) n cadrul formei.

  • 121

    Butoanele RadioButton i CheckBox

    Dei aspectul acestor controale este diferit de cel al butonului, din punct de vedere al programrii obiectuale ele au aceeai clas de baz. Vor fi ns declarate ca obiecte aparinnd clasei RadioButton i respectiv CheckBox.

    Butoanele radio sunt utilizate pentru a specifica aciuni mutual-exclusive, n sensul c la un momentdat, dintr-un grup de butoane unul singur poate avea starea selectat. Pentru a putea impune acest mod de funcionare fiecare grup de butoane radio va fi inclus n interiorul unui alt control aparinnd clasei GroupBox, despre care vom vorbi mai trziu. Butoanele radio sunt deci folosite pentru a permite utilizatorului s aleag o singur opiune din mai multe posibile.

    Controlul de tip CheckBox este afiat sun forma unei casete ptrate mici care poate avea do stri, selectat sau neselectat. Spre deosebire de butoanele radio, casetele nu sunt grupate, starea de selectare a uneia nefiind legat de starea altor casete folosite n fereastr.

    S vedem acum care sunt proprietile i evenimentele specifice fiecrui tip de control n parte.

    Cteva dintre proprietile controlului RadioButton sunt: Appearance permite trecerea de la forma standard la o reprezentare sub

    forma unui buton obinuit. n acest al doilea caz, la selectarea butonului radio, butonul va ramne apsat;

    AutoCheck dac aceast proprietate este true, la selectarea controlului este afiat un punct negru n interiorul lui iar dac este false, punctul negru nu este afiat;

    CheckAlign prin intermediul acestei proprieti, se poate indica modul de aliniere a textului asociat controlului n raport cu controlul nsui. Valorile posibile sunt left, middle, sau right;

    Checked indic starea controlului. Dac controlul este selectat, proprietatea are valoarea true;

    Evenimentele specifice butonului radio sunt: CheckChanged este generat la schimbarea strii a unui buton radio. Acest

    eveniment va fi generat de dou ori: odat pentru controlul care era selectat i acum devine neselectat i apoi nc odat pentru controlul care se selecteaz;

    Click este generat atunci cnd se selecteaz butonul cu mouse-ul (clic).

  • 122

    n mod similar i controlul CheckBox va prezenta un set de proprieti specifice, care suplimentar fa de cele ale butonului radio sunt:

    CheckState Spre deosebire de controlul RadioButton, care are doar 2 stri (marcat sau nemarcat), controlul CheckBox poate avea 3 stari: marcat, nemarcat i nedeterminat (Checked, Unchecked i Indeterminate). n starea nedeterminat, eticheta asociat controlului devine gri, pentru a specifica faptul c valoarea marcajului este nevalid, sau, starea controlului nu are nici o semnificaie n circumstana actual.

    ThreeState dac aceast proprietate este false, controlul nu poate intra in starea nedeterminat prin setarea proprietilor, ci doar prin intermediul metodelor asociate.

    i acum evenimentele: CheckedChanged este generat la modificarea strii de marcare a controlului

    (proprietatea Checked). Interesant este c la un control cu proprietatea ThreeState poziionat pe true, se poate ntmpla ca s se schimbe starea de marcare fr ca acest eveniment s se produc. Aceasta se ntmpl cnd starea controlului devine nedeterminat.

    CheckedStateChanged este generat la modificarea valorii proprietii CheckedState. Evenimentul este generat i la trecerea n starea nedeterminat.

    Cam att despre aceste controale.

    Controlul GroupBox

    Este un control utilizat pentru a realiza grupri de controale. De regul un astfel de control este folosit pentru a realiza gruparea mai multor controale din clasa RadioButton care trebuie s formeze un grup. Controlul GroupBox este afiat sub forma unui cadru dreptunghiular n interiorul cruia sunt incluse controalele care vor compune grupul. Astfel de controale pot fi utilizate ns i pentru a evidenia grupuri de controale ale aplicaiei care ndeplinesc mpreun o anumit funcie.

    Dac un set de controale sunt plasate n interiorul casetei de grupare, aceasta devine controlul printe al fiecruia dintre controale, n locul formei. Astfel, ca efect, n cazul unui grup de butoane radio un singur buton din interiorul casetei de grupare va putea fi n starea selectat la un momentdat. De asemenea, prin plasarea controalelor n

  • 123

    interiorul casetei de grupare, un set de proprieti ale acestora va putea fi modificat prin simpla modeificare a proprietii corespunztoare pentru caseta de grupare.

    Controalele Label i LinkLabel

    Sunt controale care n principiu afieaz etichete pentru clarificarea funciei altor controale sau, respectiv, legturi spre diferite adrese de internet. Apar ca texte afiate pe ecran (n cazul LinkLabel textul este subliniat). Cteva din proprietile comune celor dou controale, care pot fi modificate de utilizator sunt:

    BorderStyle specific tipul chenarului care nconjoar controlul. Implicit, nu exist chenar.

    FlatStyle specific modul n care este afiat controlul. Image permite specificarea unei imagini (bitmap, icon, jpeg, etc) care va fi

    afiat n interiorul controlului. ImageAlign specific poziia imaginii afiate n raport cu marginile controlului. Text specific textul afiat de ctre control. TextAlign - specific poziia textului n raport cu marginile controlului.

    Controlul TextBox

    Controalele TextBox sunt probabil cele mai utilizate controale pentru interfeele intrare-ieire. Prin modul lor de funcionare permit introducerea sau afiarea unor tipuri de date diferite, permind de asemenea introducerea parolelor. Dei exist dou clase de astfel de controale (TextBox i respectiv RichTextBox) ambele derivate din clasa TextBaseBox, n acest moment ne vom ocupa doar de controlalele standard, adic de clasa TextBox.

    Controalele de tip TextBox permit manipularea irurilor de caractere folosind comenzile uzuale din Windows: copy, paste, delete, etc.

    Principalele proprieti ale acestor controale sunt: CausesValidation dac aceast proprietate este true, la primirea focusului

    controlul va genera dou evenimente: Validating i Validated. Aceste evenimente sunt utilizate pentru validarea datelor coninute de control nainte de pierderea focusului.

  • 124

    CharacterCasing specific tipul literelor cu care sunt afiate textele n control: Lower toate literele sunt mici, Normal i mici i majuscule, respectiv Upper toate literele sunt majuscule.

    MaxLength specific numrul maxim de caractere a textului din control. Dac valoarea acestei proprieti este 0, lungimea textului este limitat doar de capacitatea de memorie a calculatorului.

    Multiline uzual, controlul afieaz o singur linie de text. Prin setarea acestei proprieti, controlul va fi capabil s afieze mai multe linii.

    PasswordChar textul este afiat sub form de parol (stelue). Dac proprietatea Multiline este true, aceast aceast proprietate nu funcioneaz.

    ReadOnly dac aceast proprietate este true, controlul va permite doar afiarea textelor, nu i introducerea lor.

    SelectedText proprietatea permite accesul la zona din textul controlului care a fost selectat de operator.

    SelectionLength Lungimea zonei selectate n control. SelectionStart poziia primului caracter din textul selectat n control.

    Principalele evenimente generate de controlul TextBox: Enter, GotFocus, Leave, Validating, Validated, LostFocus Aceste

    evenimente sunt generate n ordinea n care au fost prezentate. Sunt aa numitele evenimente de focus. Sunt generate ori de cte ori controlul de tip TextBox primete focusul, mai puin Validating i Validated care se produc numai n cazul n care proprietatea CausesValidation = true.

    KeyDown, KeyPress, KeyUp Sunt aa numitele evenimente de taste. Permit monitorizarea modificrilor produse n textul din control prin intermediul tastaturii. KeyDown i KeyUp recepioneaz codul de scanare al tastei acionate (vezi unu). KeyPress recepioneaz n schimb codul ASCII al tastei.

    Change este generat ori de cte ori textul coninut de control este modificat.

    i acum, pentru a nelege mai bine modul de funcionare al acestor controale, s ncercm s refacem exemplele din capitolul de Java: conversia temperaturii i respectiv formatarea textului.

    1. S crem un proiect intitulat Temperatura, de tip Windows Application. Vom realiza interfaa din figur.

  • 125

    Pentru controalele de pe interfa, vom modifica proprietile n felul urmtor: pentru controlul Label, proprietatea Text in Temperatura; pentru controlul TextBox, proprietatea Name n temp. Pentru controalele RadioButton, de sus n jos, proprietatea Text n Celsius->Fahrenheit i Name n cf, respective Text n Fahrenheit->Celsius i Name n fc; pentru controlul GroupBox, proprietatea Text n Transformare; Pentru controalele Button, de la stnga la dreapta, proprietatea Text n Calcul i respectiv Gata.

    Putem creea imediat funcia asociat apsrii butonului Gata: dubli click pe buton i editm codul:

    private void button2_Click(object sender, EventArgs e) { Application.Exit(); }

    Am dori ca implicit, transformarea s se fac n sensul Celsius->Fahrenheit, adic la pornirea programului s fie implicit selectat controlul cf. Starea de selectare a unui astfel de control, dup cum am vzut mai nainte, este memorat n proprietatea Checked. Modificarea strii de selecie se poate face folosind panoul Properties sau prin program, incluznd n constructorul clasei o linie suplimentar:

    public Form1() { InitializeComponent(); cf.Checked = true; }

    i acum s implementm funcia asociat apsrii butonului Calcul:

    Label

    TextBox

    RadioButton

    GroupBox

    Button

  • 126

    private void button1_Click(object sender, EventArgs e) { Double v = Convert.ToDouble(temp.Text); if (cf.Checked) v = 9.0 / 5.0 * v + 32; else v = 5.0 / 9.0 * (v - 32); temp.Text = Convert.ToString(v); }

    1. S crem un proiect nou, numit FormatText, pentru care s construim interfaa de mai jos:

    Dup cum se poate vedea, avem un control Label i dou controale CheckBox. S modificm pentru controlul Label proprietatea Text n Text afiat cu fontul impus,

    proprietatea Name n text i respectiv la proprietatea Font s modificm dimensiunea fontului la 9. Pentru aceasta, selectai cu mouse-ul caseta din dreapta proprietii i apsai butonul afiat. Apoi, n caseta de dialog Font, modificai dimensiunea fontului.

    n mod similar vor fi modificate proprietile celor dou controale CheckBox, n felul urmtor: Text n Bold, respectiv Italic iar Name n B respectiv I.

    click

  • 127

    n timpul funcionrii aplicaiei, selectarea unui control de tip CheckBox va produce evenimentul CheckChange. Pentru a asocia acestui eveniment o funcie este suficient s selectm controlul corespunztor cu un dublu clic.

    Funcia asociat controlului B va fi:

    private void B_CheckedChanged(object sender, EventArgs e) { FontStyle f = text.Font.Style; text.Font = new Font("Microsoft Sans Serif", 9, f ^ FontStyle.Bold); }

    Secvena de cod scris trebuie puin explicat. In C# literele sunt obiecte din clasa Font, deci ele vor putea fi construite, astfel nct s arate cum dorim noi. Unele dintre caracteristicile fontului sunt la rndul lor obiecte din clase specifice. Astfel, stilul literei este un obiect din clasa FontStyle. n prima linie de program, am declarat un obiect din clasa FontStyle, cruia i-am atribuit stilul curent al literelor cu care este scris textul. Sintaxa este uor de neles: stilul unui obiect de clasa Font este memorat n proprietatea Style, iar fontul textului este memorat n proprietatea Font, rezultnd sintaxa text.Font.Style.

    Un obiect din clasa FontStyle este n esen o masc de bii, avnd un singur bit 1 pe o poziie specific stilului respectiv, restul biilor fiind 0. Pentru exemplificare, s presupunem ca stilul este reprezentat pe 8 bii, bitul de pondere 1 fiind Bold. S presupunem de asemenea c valoarea curent a stilului este 00110000. Biii 1 identific componentele de stil prezente n stilul fontului. Pentru a aduga stilul Bold, va trebui s setm bitul de pondere 1 la valoarea 1. Acest lucru este foarte uor, prin intermediul unei operaii SAU pe bit.

    | 0 1 & 0 1 ^ 0 1 0 0 1 0 0 0 0 0 1 1 1 1 1 0 1 1 1 0

    Cum masca pentru Bold va fi 00000010, prin intermediul operaiei SAU pe bit vom obine 00110000 | 00000010 00110010

  • 128

    Adic stilului curent i va fi adugat i Bold. Operaia de retragere a stilului Bold aparent se poate face similar, printr-o operaie I pe bit cu inversul mtii stilui, adica

    00110000 & 11111101 00110000

    Din pcate, nu se poate scrie !FontStyle.Bold, pentru c obiectele FontStyle nu suport operaia de negare. Ce-i de facut? Mecanismul este simplu i este motenit din tehnicile caracteristice limbajelor de asamblare. Se realizeaz o opeaie SAU EXCLUSIV cu masca de bii. Astfel, dac bitul luat n considerare este setat, el va fi resetat, n caz contrar va fi setat.

    00110000 ^ 00110010 ^ 00000010 00000010 00110010 00110000

    Este ceea ce am fcut n a doua linie de program. Am impus fontului cu care este scris textul, un nou font, cu numele Microsoft Sans Serif, de dimensiune 9, cu stilui f^FontStyle.Bold. Astfel, dac se bifeaz butonul, textul va deveni Bold, iar dac se debifeaz, textul va deveni normal. Mecanismul este n acest caz complet diferit fa de cel din Java, n care stilul asociat unui font era o valoare ntreag.

    Similar procedm pentru Italic:

    private void I_CheckedChanged(object sender, EventArgs e) { FontStyle f = text.Font.Style; text.Font = new Font("Microsoft Sans Serif", 9, f ^ FontStyle.Italic); }

    Controale cu list

    Controlul ComboBox Acest control combin n fapt mai multe controale. n acest control vom regsi un

    control TextBox, prezentat anterior i respectiv un control ListBox despre care vom vorbi puin mai trziu. Controlul ComboBox apare ca un TextBox avnd n partea stng un buton cu o sgeat. Dac se apas pe acesta, controlul se extinde n jos, expunnd o list de elemente.

  • 129

    Principalele proprieti ale acestui control sunt: DropDownStyle - stilul n care este afiat controlul la deschiderea listei. DropDown utilizatorul poate edita partea de TextBox a controlului i trebuie s

    apese butonul sgeat pentru a deschide partea de ListBox. Simple la fel ca i DropDown, cu excepia faptului c partea de ListBox a

    controlului este tot timpul vizibil. DropDownList utilizatorul nu poate edita partea de TextBox a controlului i

    trebuie s apese butonul sgeat pentru a deschide partea de ListBox. DroppedDown Indic dac partea de list a controlului este deschis sau nu. Items este reprezentat sub forma unei colecii care stocheaz obiectele

    coninute de ComboBox. MaxLength prin setarea acestei proprieti la o valoare diferit de 0, se

    specific numrul maxim de caractere ce pot fi introduse n partea de TextBox a controlului.

    SelectedIndex indic indexul obiectului curent selctat n lista controlului. Obiectele sunt ordonate n list pe baza unui index bazat pe 0.

    SelectedItem indic obiectul curent selectat n list. SelectionStart indic indexul primului obiect selctat n lista asociat controlului. SelectionLength lungimea textului selectat n partea de TextBox asociat

    controlului. Sorted dac aceast proprietate este true, elementele din lista asociat

    controlului vor fi sortate n ordine alfabetic.

    Evenimentele principale generate de controlul din clasa ComboBox sunt: SelectedIndexChanged se produce la schimbarea seleciei n zona de list a

    controlului. DropDown se produce cnd partea de ListBox a controlului se deschide. KeyDown se produce cnd o tast este apsat n zona de TextBox a

    controlului. KeyUp - se produce cnd o tast este eliberat n zona de TextBox a controlului. TextChanged se produce la schimbarea textului din partea de TextBox a

    controlului.

  • 130

    Pentru a nelege modul de lucru cu acest control, s relum aplicaia din capitolul de Java. Vom crea un nou proiect de tip Windows Application, numit ComboImagini. Pentru acest proiect vom realiza interfaa din figura de mai jos.

    Interfaa conine dou controale Label i un control ComboBox. S modificm proprietile controalelor astfel: pentru controlul Label de sus, proprietatea Text n Imagine; iar pentru controlul ComboBox, proprietatea Name n cbimagine. Pentru controlul Label de jos: tergem coninutul proprietii Text; modificm proprietatea Name n imagine; modificm proprietatea AutoSize n False (astfel vom putea stabili noi dimensiunile controlului); deschidem subarborele proprietii Size i modificm valorile de la Width i Height la 150; modificm proprietatea BorderStyle la FixedSingle.

    Acum trebuie s adugm proiectului directorul Imagini care conine fiierele .gif care urmeaz s fie afiate. Probabil c ai observat c pentru fiecare soluie deschis, aplicaia expert creaz un director cu acelai nume, care conine la rndul lui un numr de subdirectoare. Directorul Imagini va trebui s fie copiat n subdirectorul care conine programul executabil. Acesta este ComboImagini\ComboImagini\bin\Debug.

    Vom insera acum n controlul imagini imaginea din fiierul Caine.gif. Pentru aceasta, vom selecta cu mouse-ul proprietatea Image i apoi butonul afiat.

  • 131

    n caseta Select Resource, vom selecta opiunea Local resource: i vom appsa butonul Import. Apoi, n caseta Open vom selecta fiierul dorit, vom apsa butonul Open i apoi OK. Astfel imaginea va fi afiat n control.

    Acum s populm controlul ComboBox. Putem s-l populm adugnd elemente la proprietatea Items, apsnd butonul din dreapta i adugnd informaia n caseta aprut:

    Dup introducerea tuturor informaiilor, se apas butonul OK i controlul este populat. Dar, aa cum spuneam i n capitolul de Java, o soluie mult mai elegant este popularea controlului prin cod.

  • 132

    Adugarea elemetelor n lista controlului ComboBox se face prin completarea coleciei Items. Dou dintre metodele care permit completarea acestei colecii sunt:

    Add(Object obj) adaug la nceputul listei obiectul specificat; Insert(int Index, Object obj) adaug obiectul specificat n list pe poziia Idex.

    Vom putea astfel popula obiectul ComboBox i prin codul de mai jos:

    public Form1() { InitializeComponent(); cbimagine.Items.Add("Caine"); cbimagine.Items.Add("Pisica"); cbimagine.Items.Add("Pasare"); cbimagine.Items.Insert(1, "Iepure"); cbimagine.SelectedIndex = 0; }

    Observai faptul c prin stabilirea indicelui selectat ca fiind 0 n controlul ComboBox este afiat implicit textul Caine, iar ordinea n care apar textele n list este Caine,Iepure,Pisica respectiv Pasare.

    La schimbarea seleciei n controlul ComboBox, va trebui ca imaginea s se schimbe. Adic, va trebui s implementm o funcie, care s se execute la producerea evenimentului SelectedIndexChange, care s schimbe imaginea. Este de menionat c acest eveniment se trateaz n peste 90% din aplicaiile care folosesc controale ComboBox. Crearea acestei funcii este din nou foarte simpl, pur i simplu selectm cu un dublu clic controlul ComboBox:

    private void cbimagine_SelectedIndexChanged(object sender, EventArgs e) { String nume; nume = "Imagini/" + cbimagine.SelectedItem + ".gif"; imagine.Image = Image.FromFile(nume); }

    Codul funciei este foarte asemntor cu cel din Java. Se compune nti numele complet al fiierului care conine imaginea, apoi proprietatea Image a controlului imagine este actualizat cu o imagine preluat din acel fiier (Image.FromFile()).

  • 133

    Controalele ListBox i CheckedListBox Controalele de acest tip sunt utilizate pentru a afia un set de stringuri, din care

    unul sau mai multe pot fi selectate la un momentdat. Clasa ListBox ofer funcionalitate att controlului ListBox ct controlului ComboBox. Clasa CheckedListBox este derivat din aceasta i adaug fiecrui string din list un control de tip CheckBox, utilizat pentru selectare.

    Ctve din proprietile furnizate de clasa ListBox sunt: SelectedIndex indic indicele bazat pe 0 a elementului selctat n list, sau a

    primului element selctat n lista, n cazul seleciei multiple. ColumnWidth specific limea coloanelor, n listele cu coloane multiple. Items conne sub forma unei colecii toate elementele stocate n list. Multicolumn specific numrul de coloane din list. SelectedIndices o colecie care conine toi indicii elementelor selectate din

    list. SelectedItem aceast proprietate conine elementul selectat n list dac

    selecia este simpl, respectiv primul elemen selectat din list n cazul seleciei multiple. SelectedItems o colecie care conine elementele selectate din list. Sorted dac aceast proprietate este true, elementele vor fi afiate n list n

    ordine alfabetic. CheckedIndices - o colecie care conine indicii elementelor din list care au

    caseta checkbox bifat su n stare nedeterminat (doar pentru CheckedListBox). CheckedItems - o colecie care conine elementele din list care au caseta

    checkbox bifat su n stare nedeterminat (doar pentru CheckedListBox). CheckOnClick dac acaest proprietate este true, starea unui element se

    schimb cnd asupra lui se efectueaz click.

    Cteva din metodele clasei: ClearSelected() terge toate seleciile (nu elementele selectatae!) din list. FindString() caut primul string care ncepe cu irul specificat ca parametru n

    list. GetSelected() returneaz o valoare care specific dac un element este

    selectat. SetSelected() seteaz sau terge selectarea unui element.

  • 134

    GetItemChecked() returneaz o valoare care indic faptul c checkbox-ul asociat unui element este bifat (doar pentru CheckedListBox).

    GetItemCheckState() returneaz o valoare care indic starea casetei checkbox asociat elementului (doar pentru CheckedListBox).

    SetItemChecked() seteaz starea casetei checkbox a elemenetului specificat ntr-una din strile posibile (doar pentru CheckedListBox).

    SetItemCheckState() Seteaz starea unui element (doar pentru CheckedListBox).

    Cteva evenimente: ItemCheck se produce cnd starea de selectare a unui element se schimb. SelectedItemChanged se produce la schimbarea indexului elementelor

    selectate. Pentru exemplificare, s refacem exemplul din Java. Vom deschide un nou

    proiect numit Liste, cu interfaa de mai jos.

    Am uitilzat dou controale GroupBox pentru care am modificat proprietatea Text n Ingrediente disponibile, respectiv Ingrediente selectate, dou controale CheckedListBox cu proprietatea Name Lst i respectiv Ldr i un control Button cu proprietatea Text ->. De asemenea, pentru lista din stnga vom seta proprietatea CheckOnClick la true, pentr a putea bifa elementele selectate. nainte de a face altceva, pentru a obine o interfa estetic, este de dorit s aliniem i s facem de aceeai dimensiune controalele de acelai tip. Pentru aceasta, se selecteaz pe rnd,

  • 135

    dou cte dou, controalele GroupBox i CheckedListBox. Dimensiunea se face egal ca n figura de mai jos din stnga, iar alinierea ca n figura de mai jos din dreapta.

    Vom aduga acum ingredientele n lista din stnga. S adugm urmtoarele ingrediente: Faina, Lapte, Oua, Zahar, Lamai, Rom, Frisca, Vanilie, Stafide, Ciocolata, Zahar Pudra, Drojdie, Gem, Cafea, Scortisoara. Avem din nou 2 posibiliti de adugare: fie la prioprietatea Items a obiectului Lst, completnd lista, fie prin cod, cu ajutorul unor instruciuni de forma

    Lst.Items.Add("Faina");

    Vom aduga de aceast dat ca i informaie la proprietatea Items. Observai adugarea automat a barei de scroll atunci cnd informaia depete dimensiunea listei.

    i acum, la apsarea butonului, s trecem elementele selectate n lista din dreapta. Pentru aceasta se selecteaz cu dublu click butonul i se editeaz funcia:

    private void button1_Click(object sender, EventArgs e) { if (Lst.CheckedItems.Count > 0) { Ldr.Items.Clear(); foreach (string item in Lst.CheckedItems) { Ldr.Items.Add(item.ToString());

  • 136

    } for (int i = 0; i < Lst.Items.Count; i++) Lst.SetItemChecked(i, false); } }

    Ce se petrece de fapt. Se numr nti elementele selectate n lista din stnga (Lst.CheckedItems.Count). Dac exist elemente selctate, se terge lista din dreapta. Apoi, fiecare element selctat n lista din stnga (foreach (string item in Lst.CheckedItems)) este adugat (dup convertirea la ir de caractere! S nu uitm c elementele coleciei Items sunt obiecte Objects!) n lista din dreapta. Apoi, proprietatea Checked este resetat pentru toate obiectele din colecia listei din stnga.

    Meniuri

    Un meniu este foarte uor de adugat i de configurat. n Toolbar, la Menus&Toolbars cutai obiectul MenuStrip. Acesta poate fi adus pe machet i configurat.

    Vei observa apariia unei casete n care este afiat textul Type Here. Introducei acolo textul pentru primul meniu derulant. n momentul tastrii textului, vei observa c se deschid alte dou casete, permind adugarea intrrilor de meniul derulant, respective a unui alt meniu derulant.

    Realizai un meniu cu dou meniuri derulante, Imagini i Culori. Adugai n meniul derulant Imagini intrrile Caine, Pisica, Pasare i Iepure, iar n meniul derulant Culori intrrile Rosu, Albastru, Verde si Iesire. Pentru fiecare intrare din meniurile derulante schimbai proprietatea Name astfel ca s fie ca i proprietatea Text (adic Caine Caine, etc).

    S adugm acum cele dou controale Label ca i n exemplul din Java. Primului control s-I schimbm proprietatea Name n Imagine, iar celui de al doilea n Nume. De asemenea, pentru primul control s modificm proprietatea AutoSize n False i valorile

  • 137

    de la Width i Height la 150; modificm proprietatea BorderStyle la FixedSingle. De asemenea, pentru cel de-al doilea control s modificm proprietatea Text n Caine.

    S copiem acum directorul Imagini n directorul Debug i s afim imaginea Caine.gif n controlul Imagini.

    i acum, s implementm metodele care se lanseaz n execuie la selectarea unei intrri din meniu. Cum? Foarte simplu. Selectm pe rnd cu dublu clic fiecare intrare n parte:

    private void Caine_Click(object sender, EventArgs e) { String nume; nume = "Imagini/" + Caine.Text + ".gif"; Imagine.Image = Image.FromFile(nume); Nume.Text = Caine.Text; }

    Ar trebui s obinem patru astfel de funcii, n principiu identice, singura diferen fiind numele elementului de meniu care le lanseaz n execuie. E corect, dar neelegant din punctul de vedere al programrii, pentru c rezult o mulime de funcii identice. Mai elegant ar fi s scriem o singur funcie, care s fie lansat n execuie la selectarea oricrei intrri din meniu, iar n codul funciei s fie identificat intrarea i tratat n consecin.

    Pentru a vedea cum se poate face acest lucru, s ne uitm mai atent la antetul funciei Caine_Click(). Acest antet este

    private void Caine_Click(object sender, EventArgs e)

    Se observ c numele dat de ctre mediul de programare funciei este dat de elementul creia i este sociat i evenimentul care o lanseaz n execuie. De asemenea, observm c funcia primete doi parametri. Primul este un obiect object, iar al doilea un obiect EventArgs. n momentul apelului, funcia primete prin primul parametru numele obiectului creia i este asociat. Parametrul aparine clasei object, pentru c, s ne reamintim, toate obiectele grafice utilizate pe interfa aparin unor clase derivate din aceasta. Deci, vom putea obine clasa corect a elementului ce genereaz funcia, printr-o simpl operaie de transtipaj. n cazul nostru, elementele de meniu sunt obiecte de clas ToolStripMenuItem. Deci, am putea scrie funcia astfel:

  • 138

    private void Caine_Click(object sender, EventArgs e) { ToolStripMenuItem intrare = (ToolStripMenuItem) sender; String nume; nume = "Imagini/" + intrare.Text + ".gif"; Imagine.Image = Image.FromFile(nume); Nume.Text = intrare.Text; }

    Obiectul intare va conine ntotdeauna intrarea de meniu selectat cu mouse-ul. Dar cum facem acum s poat fi i lansat n execuie la selectarea unei intrri de meniu? Mecanismul prin care o funcie este lansat n execuie la producerea unui eveniment de ctre un obiect de interfa este simplu. Se creaz un handler, care face legtura dinte obiect i funcie, preciznd evenimentul care o lanseaz. Forma general a unui astfel de handler, este

    obiect.eveniment += new tip_handler(funcie);

    unde obiect este obiectul cruia i este asociat handlerul, eveniment este evenimentul care lanseaz funcia, tip_handler este n general EventHandler (depinde de eveniment) iar funcie este numele funciei care va fi lansat n execuie. Deci, pentru a asocia evenimentului Click aceeai funcie i pentru celelelte 3 intrari de meniu, va fi suficient s definim cei trei handleri asociai:

    public Form1() { InitializeComponent(); Pisica.Click +=new EventHandler(Caine_Click); Pasare.Click += new EventHandler(Caine_Click); Iepure.Click += new EventHandler(Caine_Click); }

    Compilai i lansai n execuie programul. Observai funcionarea corect.

    S schimbm acum culoarea textului. Dublu click pe Rosu i implemenm codul:

    private void Rosu_Click(object sender, EventArgs e) { Nume.ForeColor = Color.Red;

  • 139

    }

    Codul nu necesit explicaii suplimentare. Din nou, ar fi bine s scriem o singur funcie care s trateze intrrile din meniul Culori. nti vom scrie handlerii:

    public Form1() { InitializeComponent();

    Iepure.Click += new EventHandler(Caine_Click); Albastru.Click+=new EventHandler(Rosu_Click); Verde.Click+=new EventHandler(Rosu_Click); Iesire.Click+=new EventHandler(Rosu_Click); }

    i apoi vom modifica funcia:

    private void Rosu_Click(object sender, EventArgs e) { ToolStripMenuItem intrare = (ToolStripMenuItem)sender; if (intrare==Rosu) Nume.ForeColor = Color.Red; if (intrare==Albastru) Nume.ForeColor = Color.Blue; if (intrare==Verde) Nume.ForeColor = Color.Green; if (intrare == Iesire) Application.Exit(); }

    Compilai i executai programul.

    Desenarea n C#

    Desenele n C# sunt obiecte ale clasei Graphics. La fel ca i n Java, desenarea se poate face ntr-o funcie specializat, numit OnPaint(). n acest caz, codul care trebuie implementat are forma

    Protected override void OnPaint(PaintEventArgs e) { Graphics g=e.Graphics; // cod de implemntat }

  • 140

    Aceast funcie va fi apelat de fiecare dat la generarea formei i ori de cte ori sistemul de operare sesizeaz necesitatea redesenrii. Dar desenarea se poate face i n orice alt funcie, de exemplu n funcia generat la apsarea unui buton. n acest caz funcia va fi de forma:

    Protected void button1_Click(object sender, EventArgs e) { Graphiocs g=this.CreateGraphics(); // cod de implementat g.Dispose(); }

    Pentru realizarea aplicaiei n C# vom utiliza aceast a doua metod. S deschidem un nou proiect, numit Desenare i s implementm interfaa din figur. Am adugat un control Panel, care va reprezenta zona de desenare, cruia i-am schimbat proprietatea Name n panel i BorderStyle n FixedSingle. Am adugat de asemenea un control GroupBox cu proprietatea Text Figura, dou controale RadioButton cu proprietatea Text Elipsa i Dreptunghi i proprietatea Name el, respectiv dr i dou controale Button, cu proprietile Text i Name Date i respectiv Grafic. Acum va trebui s adugm aplicaiei o fereastr de dialog care va servi la introducerea dimensiunilor figurilor geometrice. Pentru aceasta se va selecta Add n meniul contextual al intrrii Desenare din Solution Explorer (clic cu butonul din dreapta pe Desenare) i apoi Windows Form. Va apare fereastra de dialog Add New Item n care vom alege Windows Form, iar la Name vom tasta Dimensiuni.cs i apoi Add.

  • 141

    Observai c a aprut o nou machet, pe care putem acum construi noua interfa. Aceasta va fi ca n figura de mai jos. Am adugat dou controale Label cu proprietatea Text Inaltime i Latime, dou controale TextBox cu proprietatea Name inalt respectiv lat i un control Button, cu proprietile Text i Name OK. n plus, pentru ca butonul s se comporte implicit ca un buton de confirmare a aciunilor din machet, se seteaz proprietatea DialogResult la OK.

  • 142

    Vom implementa acum funcia asociat evenimentului Click pe butonul Date. Dar nainte, vom aduga clasei Form1, dou variabile de tip int, n care vom salva dimensiunile impuse n macheta copil.

    public partial class Form1 : Form { int H, L; public Form1() { InitializeComponent(); }

    Deosebirea fa de Java este c noua form a fost implementat ntr-o clas separat. Problema care apare este c, la fel ca i n Java, obiectele h i l sunt obiecte private ale clasei Dimensiuni. Pentru a le putea accesa, este nevoie s adugm clasei dou metode publice, care s returneze valorile stocate n aceste controale. Vom intra deci n zona de cod a clasei Dimensiuni i vom aduga metodele

    public int GetH() { return Convert.ToInt16(inalt.Text); }

    public int GetL() { return Convert.ToInt16(lat.Text); }

    i acum selectai cu un dublu clic butonul Date i editai funcia generat:

    private void Date_Click(object sender, EventArgs e) { Dimensiuni dm = new Dimensiuni(); if (dm.ShowDialog() == DialogResult.OK) { H = dm.GetH(); L = dm.GetL(); } }

    Not: O soluie mai elegant oferit de C# este definirea unor proprieti, Inalt i Lat. naintea adugrii acestora se vor aduga clasei ferestrei de dialog variabilele hh i ll. Acestea vor primi valori preluate din casetele de text n momentul nchiderii

  • 143

    ferestrei. Proprietile Inalt i Lat vor premite att impunerea ct i preluarea valorilor variabilelor hh i ll.

    public int Inalt { set { hh = value; } get { return hh; } }

    public int Lat { set { ll = value; } get { return ll; } }

    Ce face funcia Date_Click()? Creaz un nou obiect Dimensiuni, pe care-l afieaz cu ajutorul metodei ShowDialog(). La apsarea butonului OK, revenirea din forma copil se face cu transmiterea spre forma printe a codului DialogResult.OK. Dac revenirea se face n acest fel, prelum dimensiunile nscrise n forma copil. i acum, pentru scrierea funciei n care are loc desenarea, se selecteaz cu un dublu clic butonul Grafic i se editeaz codul generat de mediul de programare.

    private void Grafic_Click(object sender, EventArgs e) { Graphics g = panel.CreateGraphics(); Color fundal=panel.BackColor; g.Clear(fundal); Pen pen = new Pen(Color.Black); int x=panel.Width/2 - L/2; int y=panel.Height/2 - H/2; Rectangle r = new Rectangle(x, y, L, H); if (dr.Checked) g.DrawRectangle(pen, r); if (el.Checked) g.DrawEllipse(pen, r);

  • 144

    g.Dispose(); }

    Ce conine funcia? nti s-a construit un context grafic, g, peste controlul panel. Apoi s-a salvat n obiectul Color fundal - culoarea fundalului controlului panel i s-a ters imaginea din acest control folosind culoarea de fundal. S-a construit apoi un obiect Pen de culoare neagr. n C#, linia de desenare este ntotdeauna un obiect Pen. Dup care, s-a determinat centrul contextului de desenare asociat controlului panel i s-a desenat elipsa sau dreptunghiul n funcie de dimensiunile preluate din fereastra de dialog. Pentru desenarea elipsei i a dreptunghiului, s-a creeat n prealabil un obiect Rectangle.