Documente Academic
Documente Profesional
Documente Cultură
5. Controale
Un control reprezintă un obiect care are o componentă grafică. Un control este situat pe un
formular (o fereastră) și interacționează cu utilizatorul, furnizând informații pe care utiliza-
torul le poate utiliza. Exemple de controale sunt casetele text, etichetele, butoanele, listele
derulante, elementele de meniu, barele cu instrumente și, în general, tot ceea ce se poate
vedea și cu care se poate interacționa într-o aplicație Windows.
O componentă este similară unui control, cu diferența că nu are nicio componentă vizuală în
timpul rulării. Atunci când adăugați o componentă pe un formular (în modul design), aceasta
nu apare pe suprafața formularului, ci în component tray, situată sub formular (Figura 5.1).
Puteți să selectați componentele, apoi să utilizați panoul de proprietăți pentru a le vizualiza
și modifica proprietățile. În timpul rulării componentele sunt invizibile utilizatorului, deși
acestea pot afișa unele obiecte vizibile cum ar fi meniuri, ferestre dialog sau pictograme.
Figura 5.2 prezintă toolbox-ul asociat cu Visual C#, care afișează o gamă standard de 67 de
controale și componente. Săgeata (arrow tool) din colțul stânga sus nu reprezintă practic un
control sau o componentă, ci instrumentul de selecție.
97
Medii și Tehnologii de Programare – curs
98
Controale
Aplicațiile cu interfețe grafice sunt de obicei programate astfel încât sunt conduse de
evenimente. Sistemele de operare sunt un alt exemplu clasic de programe conduse de
evenimente pe cel puțin două nivele. La cel mai de jos nivel, handlerele de întreruperi se
comportă ca handlere de evenimente hardware, cu procesorul în rol de coordonator
(dispatcher). Sistemele de operare se comportă, de asemenea, ca și coordonatori pentru
procese, transmițând datele și întreruperile soft către procese utilizator, care de multe ori
sunt programate ca și handlere de eveniment.
99
Medii și Tehnologii de Programare – curs
De obicei, un control etichetă are doar rol de afișare a unui text, astfel că nu vă veți folosi de
evenimentele acestuia. În schimb, alte controale, cum ar fi butoanele sau barele de derulare,
nu ne vor fi de mare folos dacă programul nu poate răspunde la evenimentele lor. De
exemplu, doriți să creați pe un formular câte un buton pentru fiecare fișier dintr-un director,
iar la click pe un buton să se deschidă fișierul asociat. Dacă nu cunoașteți dinainte numărul
de fișiere din director, nu veți ști de câte controale veți avea nevoie.
O soluție la această problemă este utilizarea operatorului += care vă permite adăugarea unei
proceduri eveniment pentru un control sau componentă. Următoarea secvență de cod
ilustrează acest mod de lucru:
private void Form1_Load(object sender, EventArgs e)
{
Button btn = new Button();
btn.SetBounds(100, 100, 50, 32);
btn.Text = "Mesaj";
this.Controls.Add(btn);
btn.Click += btn_Click;
}
Atunci când scrieți cod pentru adăugarea unei noi proceduri eveniment folosind operatorul
+=, mediul Visual Studio vă propune, la apăsarea tastei TAB, în prima etapă asocierea
evenimentului în cauză cu o procedură eveniment (având numele compus din numele
controlului și al evenimentului: numeControl_numeEveniment), apoi crearea efectivă a proce-
durii eveniment respective (vezi Figura 5.4).
Figura 5.4. Oferirea de ajutor din partea Visual Studio pentru inserarea unei proceduri eveniment
Puteți utiliza aceeași metodă ca procedură eveniment pentru mai multe controale, de
exemplu butoane. În acest caz, codul poate converti parametrul sender într-un obiect buton,
putând astfel să determinați prin proprietățile Name sau Text butonul care a fost apăsat.
Pentru a șterge un control de pe un formular ștergeți-l din colecția de controale asociată
formularului. Pentru eliberarea resurselor asociate controlului în cauză, setați orice variabilă
care se referă la acesta la valoarea null. Iată un exemplu:
this.Controls.Remove(btn);
btn = null;
100
Controale
În acest mod puteți să ștergeți atât controalele create dinamic, cât și pe cele create în modul
design. De asemenea, puteți să ștergeți asocierea dintre evenimentul unui control și o
procedură eveniment, prin utilizarea operatorului -=, precum puteți vedea în exemplul de
mai jos:
btn.Click -= btn_Click;
Figura 5.5. Fereastra de proprietăți vă permite modificarea proprietăților unui control în modul design.
Proprietăți compuse
Doar câteva proprietăți au valori compuse. Proprietatea Location include coordonatele X și Y
ale colțului stânga-sus al controlului. Proprietatea Size conține lățimea și înălțimea controlu-
lui. Proprietatea Font include numele fontului, dimensiunea acestuia și alte caracteristici
specifice fonturilor (bold, italic etc.).
Fereastra de proprietăți afișează aceste proprietăți cu un semn plus („+”) în stânga acestora,
prin intermediul căruia puteți desfășura proprietățile respective. Figura 5.6 afișează aceeași
fereastră de proprietăți ca cea din Figura 5.5, însă cu proprietățile Font și Location
desfășurate.
101
Medii și Tehnologii de Programare – curs
Puteți modifica toate caracteristicile unei proprietăți compuse prin intermediul unei ferestre
dialog afișate la click pe butonul situat în partea dreaptă a proprietății compuse. De exemplu,
pentru proprietatea Font va fi afișată fereastra dialog din Figura 5.7.
Figura 5.6. Fereastra de proprietăți vă permite modificarea proprietăților complexe în modul design.
Figura 5.7. Fereastra dialog care vă permite modificarea caracteristicilor unui font.
Proprietăți restrictive
Unele proprietăți permit valori restrictive. De exemplu, proprietatea Visible poate primi
numai valorile true sau false. Dacă dați click pe o asemenea proprietate, vă va fi afișată o listă
derulantă din care puteți alege una dintre valorile permise pentru acea proprietate.
102
Controale
Alte proprietăți restrictive au asociate valori de tip enumerare. Proprietatea FlatStyle a unui
buton permite selectarea valorilor Flat, Popup, Standard și System. Puteți da dublu click pe
valoarea unei proprietăți restrictive pentru ciclarea valorilor posibile pe care le poate lua
acea proprietate.
Unele proprietăți pot conține referințe la alte controale. De exemplu, proprietatea ImageList
reprezintă o referință la o componentă ImageList care conține imaginile pe care controlul le
poate afișa.
În fine, alte proprietăți restrictive pot afișa diferite editoare care permit introducerea în mod
grafic a valorilor unei proprietăți. Un astfel de exemplu este proprietatea Anchor, care
permite „ancorarea” marginilor unui control la marginile containerului, astfel încât controlul
își păstrează poziția relativă în cazul redimensionării containerului.
Proprietăți colecție
Unele proprietăți reprezintă colecții de obiecte. De exemplu, un control de tip ListBox
afișează o listă de elemente text. Proprietatea Items a acestuia reprezintă o colecție ce
conține acele elemente. Inițial, fereastra de proprietăți afișează valoarea acestei proprietăți
ca și “(Collection).” La apăsarea butonului din dreapta proprietății de tip colecție va apărea o
fereastră dialog în care puteți edita elementele colecției.
Alte proprietăți pot conține o colecție de obiecte care, la rândul lor, să conțină o colecție de
obiecte. De exemplu, controlul ListView are proprietatea Items care reprezintă o colecție de
elemente de tip ListViewItem. Fiecare element din colecție reprezintă un obiect care are o
proprietate SubItems, care la rândul ei este o colecție (Figura 5.8). La afișarea controlului în
mod detaliat, un obiect din colecția Items reprezintă un rând din afișarea tabelară, iar
proprietatea SubItems reprezintă valorile secundare de pe acel rând.
Figura 5.8. Obiectele din colecția Items a controlului ListView au fiecare câte o proprietate SubItems, care
reprezintă de asemenea o colecție.
103
Medii și Tehnologii de Programare – curs
O proprietate poate fi văzută ca orice membru public al obiectului de tip control, putând să o
accesați prin numele controlului urmat de caracterul punct și de numele proprietății. Dacă o
proprietate conține o referință la un obiect, puteți utiliza proprietățile acelui obiect folosind
aceeași sintaxă:
if (textBox1.Font.Bold)
MessageBox.Show("Bold");
else
MessageBox.Show("Not bold");
Dacă o proprietate reprezintă o colecție sau un vector, puteți să parcurgeți într-o buclă
valorile din colecție la fel cum parcurgeți o colecție sau un vector:
foreach (Object selected_item in lstChoices.SelectedItems())
Debug.WriteLine(selected_item.ToString());
Rețineți faptul că unele proprietăți ale controalelor sunt read-only, astfel că nu veți putea să
le modificați. Un astfel de exemplu este proprietatea Bottom care este calculată automat în
funcție de alte două proprietăți:
control.Bottom = control.Top + control.Height;
104
Controale
105
Medii și Tehnologii de Programare – curs
TopLevelControl Returnează cel mai de sus ascendent al controlului. De obicei este cea
mai din afară fereastră care conține controlul. Este read-only.
Visible Determină dacă controlul este vizibil.
Width Determină lățimea controlului.
5.2.3. Metode
O metodă execută cod asociat cu un control. Metodele pot primi parametri la fel ca orice altă
funcție. Deoarece metodele execută cod, nu le puteți apela în modul design, ci puteți să le
apelați numai prin cod, în timpul rulării.
106
Controale
5.2.4. Evenimente
Un control sau un alt obiect generează un eveniment pentru înștiințarea programului despre
apariția unor modificări în anumite circumstanțe. Adesea acțiunea de generare a unui
eveniment se mai numește „aruncarea” unui eveniment. Clasele specifice controalelor
furnizează evenimente relevante pentru scopul pentru care au fost create. De exemplu,
controlul Button furnizează un eveniment Click pentru înștiințarea programului despre
apăsarea unui buton de către utilizator.
Programul răspunde la un eveniment prin crearea unui handler de eveniment care „prinde”
evenimentul și întreprinde acțiunile potrivite acestuia. Fiecare eveniment își definește pro-
priul format al handlerului și determină parametrii pe care handlerul de eveniment îi va
primi. Adesea, acești parametri oferă informații suplimentare legate de eveniment.
De exemplu, atunci când o parte a formularului este acoperită sau expusă, formularul
generează evenimentul Paint. Handler-ul evenimentului Paint primește ca parametru un
obiect de tip PaintEventArgs. Proprietatea Graphics a acestui parametru reprezintă o
referință la un obiect de tip Graphics pe care programul îl poate folosi pentru redesenarea
conținutului formularului.
Unele handlere de eveniment primesc parametri care sunt utilizați pentru trimiterea de
informații legate de eveniment înapoi la obiectul care le-a generat. De exemplu, handlerul
evenimentului FormClosing al unei clase formular are un parametru de tip
FormClosingEventArgs. Acesta reprezintă un obiect care are o proprietate Cancel. Dacă
aceasta este setată pe true, formularul anulează evenimentul FormClosing și formularul
rămâne deschis în continuare. De exemplu, handlerul de eveniment poate verifica dacă
datele introduse de utilizator sunt formatate corect, în caz contrar programul afișând un
mesaj de eroare, iar formularul rămânând deschis.
107
Medii și Tehnologii de Programare – curs
Majoritatea evenimentelor asociate unui control sunt specifice acelui tip de control.
Controalele moștenesc un set de evenimente de la clasa de bază Control, însă le pot
supraîncărca, modificându-le astfel comportamentul.
108
Controale
109
Medii și Tehnologii de Programare – curs
110
Controale
Secvențe de evenimente
În unele situații sunt generate o serie de evenimente care apar într-o anumită ordine.
Evenimente de mouse
Atunci când dați click pe un control, apar următoarele evenimente în ordinea indicată. Prima
instanță a evenimentului MouseMove poate apărea de oricâte ori mișcați mouse-ul cât timp
butonul de mouse este apăsat. Evenimentul final MouseMove apare indiferent dacă mișcați
mouse-ul sau nu.
MouseDown
[MouseMove]
Click
MouseClick
MouseUp
111
Medii și Tehnologii de Programare – curs
MouseCaptureChanged
MouseMove
Atunci când dați dublu-click pe un control, apar următoarele evenimente în ordinea indicată:
MouseDown
[MouseMove]
Click
MouseClick
MouseUp
MouseCaptureChanged
MouseMove
MouseDown
DoubleClick
MouseDoubleClick
MouseUp
MouseCaptureChanged
MouseMove
Evenimente de redimensionare
Atunci când redimensionați un control, apar următoarele evenimente în ordinea indicată.
Aceste evenimente sunt repetate atât timp cât redimensionați controlul.
Layout
Resize
SizeChanged
Evenimente de mutare
Atunci când mutați un control, apar următoarele evenimente în ordinea indicată. Aceste
evenimente sunt repetate atât timp cât mutați controlul.
Move
LocationChanged
112
Controale
113
Medii și Tehnologii de Programare – curs
114
Controale
tabelară.
TextBox Afișează text pe care utilizatorul îl poate modifica în timpul rulării.
Timer Implementează un temporizator care declanșează un eveniment la intervale
de timp definite de utilizator.
ToolStrip Oferă un container pentru obiecte Windows toolbar (controale Button, Label,
ComboBox, TextBox, ProgressBar etc.).
ToolStripContainer Oferă panouri pe fiecare parte a ferestrei (acestea pot conține controale de
tip ToolStrip, MenuStrip și StatusStrip) și un panou central (acesta poate
conține orice controale).
ToolTip Afișează un text ajutător dacă utilizatorul poziționează cursorul de mouse
deasupra controlului asociat.
TrackBar Permite utilizatorului să deplaseze un cursor de-a lungul unei bare pentru a
selecta o valoare numerică.
TreeView Afișează date ierarhice într-o formă grafică, arborescentă.
VScrollBar Afișează o bară de derulare verticală.
WebBrowser Permite navigarea prin pagini web din cadrul ferestrei. Controlul afișează
rezultatele exact ca browserul Internet Explorer. O posibilă utilizare a acestui
control este afișarea de help în format web.
Chiar dacă aveți la îndemână atâtea unelte puternice, nu întotdeauna este ușor să alegeți cel
mai potrivit control pentru o anumită situație. Pentru simplificarea codului de tratare a
erorilor, ar trebui să alegeți cel mai restrictiv control care poate să îndeplinească sarcina
dorită, deoarece cu cât controalele sunt mai restrictive, cu atât utilizatorul are mai puține
opțiuni de introducere a datelor invalide.
115
Medii și Tehnologii de Programare – curs
6. Formulare
Clasa Form din Visual C# este derivată indirect din clasa Control. Lanțul complet de
moșteniri este următorul: Control → ScrollableControl → ContainerControl → Form. Un
formular moștenește proprietățile, metodele și evenimentele definite de clasa Control, cu
excepția cazului în care acestea sunt supraîncărcate. Din multe puncte de vedere, un
formular este doar un alt tip de control.
6.1. Transparență
Obiectul Form oferă, suplimentar față de obiectul Control, o serie de proprietăți pe care le
puteți folosi pentru a face o fereastră total sau parțial transparentă. Proprietatea Opacity
determină opacitatea unei ferestre. În modul design, fereastra de proprietăți arată valoarea
acestei proprietăți sub formă de procentaj, unde 100% semnifică faptul că formularul este
complet opac, iar 0% că fereastra este complet transparentă. În timpul rulării trebuie să
tratați valoarea proprietății Opacity ca număr în virgulă mobilă cu valori între 0.0 (complet
transparent) și 1.0 (complet opac).
O aplicație poate utiliza pentru Opacity valori mai mici de 100% pentru a permite
utilizatorului să vadă ce se întâmplă în spatele ferestrei. De exemplu, puteți construi o
fereastră parțial transparentă pentru implementarea unui dialog de căutare, astfel încât
utilizatorul să poată vedea documentul pe măsură ce căutarea avansează.
Figura 6.1 prezintă un formular cu opacitatea 66%. Puteți vedea încă marginile ferestrei,
bara de titlu, meniurile și butoanele, însă puteți observa de asemenea fereastra de dedesubt.
Figura 6.1. O fereastră cu opacitate 66% permite vizualizarea ferestrei situate dedesubt.
116
Controale
Dacă opacitatea este mai mare de 0%, fereastra se comportă normal, cu excepția aspectului
imaterial al acesteia, utilizatorii putând interacționa cu aceasta ca și cu orice altă fereastră.
Dacă opacitatea este 0%, fereastra este complet transparentă, iar utilizatorul poate interac-
ționa cu ea numai prin intermediul tastaturii (schimbarea focalizării controalelor cu tasta
TAB, acționarea comenzilor prin combinații de taste). În orice caz, fereastra nu va detecta
click-urile de mouse.
Dacă opacitatea este 1%, fereastra rămâne invizibilă în continuare, însă recunoaște click-
urile de mouse.
O a doua proprietate care poate determina transparența unei ferestre este TransparencyKey.
Această proprietate reprezintă o culoare care indică mediului care parte a ferestrei trebuie
să fie complet transparentă. La afișarea ferestrei, suprafețele care au ca fundal această
culoare nu vor fi desenate.
Figura 6.2 prezintă o fereastră cu proprietatea TransparencyKey setată la culoarea de fundal a
ferestrei. Atât fereastra cât și eticheta cu textul „Spațiu gol” au același fundal, astfel că vor fi
transparente la afișare. Evenimentul Paint al ferestrei desenează o elipsă în interiorul
ferestrei.
Figura 6.2. Proprietatea TransparencyKey a unei ferestre permite crearea unor zone complet transparente.
117
Medii și Tehnologii de Programare – curs
Figura 6.3 prezintă o fereastră de forma unui smiley. Handler-ul evenimentului Paint al
ferestrei desenează imaginea dintr-un fișier bitmap. În acest fel puteți construi de exemplu
splash screen-uri1 sau alte ferestre dialog interesante.
Figura 6.3. Proprietatea TransparencyKey permite crearea unor ferestre de diverse forme, precum aceasta.
Această fereastră nu prezintă nici margini, nici bară de titlu și nici butoane sistem, astfel că
utilizatorul nu o poate muta, redimensiona, maximiza sau închide (se setează proprietatea
FormBorderStyle a formularului la None). Pentru utilizarea acestei ferestre ca splash screen,
adăugați un control Timer pentru a face ca fereastra să dispară după câteva secunde. Pentru
utilizarea ferestrei ca o fereastră obișnuită, adăugați pe suprafața ei un buton de închidere.
Dacă utilizați împreună proprietățile Opacity și TransparencyKey, pixelii care corespund cu
TransparencyKey nu sunt afișați, iar ceilalți pixeli sunt afișați corespunzător cu valoarea setată
de proprietatea Opacity.
1 O fereastră de tip splash screen este afișată în timp ce o aplicație inițializează sau încarcă datele necesare,
pregătindu-se de lucru. Aplicația va închide fereastra splash screen după ce inițializarea este completă, sau după
trecerea unui număr de secunde.
118
Controale
Aplicațiile MDI oferă de obicei unelte pentru gestionarea ferestrelor copil pe care acestea le
conțin. Aceste unelte permit utilizatorului minimizarea ferestrelor copil, aranjarea acestora
în cadrul ferestrei părinte, ș.a.m.d. Visual Studio este o aplicație MDI deoarece poate afișa în
cadrul ferestrei principale mai multe ferestre copil (designere de formulare, editoare de cod,
editoare de bitmap, ș.a.m.d.).
Figura 6.5. O aplicație MDI afișează documentele în ferestre copil conținute de fereastra părinte
119
Medii și Tehnologii de Programare – curs
fereastră copil astfel încât acesta să depășească marginile ferestrei părinte, fereastra părinte
va afișa în mod automat bare de derulare pentru a putea vizualiza fereastra copil.
Programul va afișa o pictogramă în taskbar și Task Manager pentru fereastra părinte, însă nu
și pentru ferestrele copil. Dacă minimizați containerul MDI, toate ferestrele pe care le
conține vor fi ascunse împreună cu acesta. Dacă minimizați însă o fereastră copil, pictograma
acesteia va fi afișată în interiorul containerului, iar nu separat în taskbar. În cazul în care
maximizați o fereastră copil MDI, aceasta va umple suprafața ferestrei părinte.
Un container MDI oferă de asemenea unele metode pentru aranjarea ferestrelor copil. Codul
de mai jos ilustrează modul în care, din cadrul containerului MDI, pot fi aranjate ferestrele
copil în diverse configurații:
private void CascadeToolStripMenuItem_Click(object sender, EventArgs e)
{
LayoutMdi(MdiLayout.Cascade);
}
Alte comenzi utile pe care le puteți adăuga unei aplicații MDI sunt: Minimize All, Restore All,
Maximize All și Close All. Puteți implementa aceste comenzi prin parcurgerea colecției
MdiChildren asociate containerului MDI, precum se poate observa în continuare:
private void CloseAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.Close();
}
}
private void minimizeAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.WindowState = FormWindowState.Minimized;
}
}
private void maximizeAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.WindowState = FormWindowState.Maximized;
}
}
private void restoreAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.WindowState = FormWindowState.Normal;
}
}
120
Controale
Multe aplicații MDI includ un meniu „Windows” care afișează o listă a ferestrelor copil
deschise. Apăsarea uneia dintre aceste comenzi de meniu permite mutarea ferestrei copil
deasupra tuturor celorlalte ferestre conținute de containerul MDI.
Construirea unei liste de ferestre copil este o sarcină ușoară în Visual C#. Selectați controlul
principal MenuStrip, iar în fereastra de proprietăți a acestuia setați proprietatea
MdiWindowListItem la meniul care doriți să conțină lista de ferestre copil. După fiecare
operație de deschidere sau închiderea unei ferestre copil, Visual C# va actualiza automat
această listă.
Figura 6.6 arată un meniu care afișează o listă de ferestre copil MDI. Fereastra cu titlul
„Program.cs” are focalizarea, astfel că lista afișează o bifă în dreptul comenzii de meniu
asociate ferestrei.
Figura 6.6. Proprietatea MdiWindowListItem asociată controlului MenuStrip determină care element de meniu
va afișa lista cu ferestrele copil MDI.
Majoritatea aplicațiilor Visual C# utilizează SDI, iar la crearea unei noi aplicații, interfața
acesteia va fi implicit SDI. Pentru a avea o aplicație MDI, creați întâi o aplicație nouă, apoi
setați proprietatea IsMdiContainer a formularului de start pe true. În Form Designer, acest
formular își va schimba înfățișarea, astfel încât va fi evident că este un formular părinte MDI.
Ca metodă alternativă puteți selecta din meniul Project comanda „Add Windows Form”. În
fereastra dialog ce se va deschide selectați „MDI Parent Form” și dați ferestrei un nume
rezonabil. Visual C# va adăuga un nou formular părinte MDI având un control meniu care va
include meniuri standard (File, Edit, View, ș.a.m.d.) și o bară de unelte cu unelte standard
(New, Open, Save, ș.a.m.d.).
În faza de design, un formular copil MDI are aceeași înfățișare cu a unui formular standard.
Pentru a face ca formularul copil să fie afișat în interiorul unui container MDI, trebuie să îi
setați acestuia în timpul rulării proprietatea MdiParent la containerul MDI.
Puteți vedea mai jos secvențele de cod adăugate automat la comanda de deschidere a unei
noi ferestre copil din fereastra părinte MDI. Ferestrele copil nou create vor fi automat afișate
în interiorul containerului MDI și vor fi adăugate în lista de ferestre copil deschise.
private void OpenFile(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = Application.StartupPath;
openFileDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
121
Medii și Tehnologii de Programare – curs
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
string FileName = openFileDialog.FileName;
// Aici adaugarea codului pentru afisarea continutului fisierului
// ...
}
}
122
Controale
Dacă utilizatorul apasă butonul „Cancel” sau închide formularul din meniul sistem, atunci
formularul setează automat proprietatea DialogResult la Cancel și se închide. Dacă
utilizatorul apasă alt buton, handlerul de eveniment va seta DialogResult la o valoare
corespunzătoare. Setarea acestei valori va duce la închiderea automată a formularului.
123