Tutorial Csharp Forms
Tutorial Csharp Forms
1
Din fereastra de start alegem Create a new project și apoi fixăm în cele trei căsuțe
derulante limbajul C#, sistemul de operare Windows și tipul proiectului Dektop, și apoi alegem
itemul C# Windows Forms App(.NET Framework) .
2
Prima noastră grijă: schimbăm numele fisierului Form1.cs în MainForm.cs.
Aceasta este o chestiune de stil: într-o astfel de aplicație pot fi folosite mai multe forme,
caz în care una trebuie să fie desemnată formă principală și denumită corespunzător.
Pentru redenumirea fișierului Form1.cs alegem itemul Rename F2 din meniul contextual
atașat (clic-dreapta cu mausul pe numele fișierului în fereastra Solution Explorer), tastăm noul
nume, apăsăm Enter și răspundem cu Yes la întrebarea din ferestra de dialog care apare, astfel
încât toate referințele la Form1 să fie înlocuite cu MainForm. Astfel Visual Studio-ul va schimba
în mod automat în MainForm și numele clasei pe care vrem să o definim în acest proiect.
Verificăm schimbarea deschizând pentru scriere fișierul MainForm.cs cu View code
(F7) din meniul contextual atașat:
Proiectarea unei aplicații de tip Windows Forms are loc în două etape. Etapa întâi este o
etapă de proiectare, de design, în care lucrăm în mod vizual : dimensionăm, de exemplu, forma
cu mausul și poziționăm pe ea cu drag and drop componentele sale, apoi sta-bilim proprietățile
acestor componente și evenimentele la care răspund, alegându-le dintr-un meniu pus la dispoziție
de Visual Studio. Etapa a doua este o etapă de scriere de cod, în care programăm răspunsul
aplicației la evenimentele selectate, completând cu instrucțiunui C# șabloanele handler-elor de
evenimente.
In prima etapă suntem asistați de un program, designerul, care scrie în locul nostru codul
C# corespunzător alegerilor făcute, cod scris în principal în fișierul MainForm.Designer.cs. Este
bine să studiem acest cod, dar să nu îl modificăm în nici un fel.
3
Cele două etape pot fi folosite alternativ, trecerea la etapa de design se face prin deschi-
derea fișierului MainForm.cs cu View designer (shift + F7) din meniul contextual atașat,
iar trecerea la etapa de scriere a codului cu View code (F7), după cum am văzut deja.
În sfârșit, al treilea fișier de cod este Program.cs, gata editat de Visual Studio, în care gă-
sim clasa Program , dotată doar cu metoda Main() :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TutorialWinForms
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
4
De interes pentru noi este numai ultima instrucțiune, în care este apelată metoda statică
Run a clasei Application, care lansează în funcțiune forma primită ca argument, în acest caz un
obiect de tip MainForm.
I.1. Setarea proprietăților. Lansăm aplicația, cu Start Without Debugging, Ctrl + F5, și
pe monitor apare o formă
care nu face nimic, deocamdată, dar care simte și răspunde la următoarele evenimente generate
cu mausul : minimizare, maximizare, modificarea dimensiunilor, schimbarea poziției pe ecran și
închiderea formei.
Observăm că nu am scăpat total de cuvântul Form1, care a mai rămas scris în cod doar în
corpul metodei InitializeComponent() din fișierul MainForm.Designer.cs :
private void InitializeComponent()
{
this.SuspendLayout();
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(337, 203);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
După cum am mai spus, nu este indicat să modificăm manual codul scris de designer, avem voie
totuși să înlocuim comentariul1 // Form1 cu // MainForm. Proprietățile Name și Text ale clasei
MainForm le vom modifica cu designerul, după cum urmează.
1 Comentariile cu trei slash-uri ///sunt folosite de Visual Studio pentru crearea unei documentații XML a proiec-
tului, nu trebuie modificate
5
Deschidem MainForm.cs[design] și selectăm șablonul formei, apoi din meniul View,
alegem itemul Properties Windows, F4.
In fereastra care apare sunt listate toate2 proprietățile și toate evenimentele componentei
selectate, acum MainForm, derivată din System.Windows.Forms.Form
În continuare, vom seta din fereastra Properties alte câteva proprietăți ale formei, cele
nemodificate de noi rămânând cu valorile inițializate de constructorul clasei bază.
2 Dacă în fereastra Properties nu apare nimic în listă, se închide fisierul MainForm.cs[design] din editor și se
deschide din nou cu dublu-clic pe MainForm.cs în Solution Explorer .
6
Mai precis, setăm FormBorderStyle la FixedDialog și MaximizeBox la false, ca să in-
terzicem modificarea la rulare a dimensiunilor formei, pe care le setăm apoi la 600 x 600 pixeli,
cu Size.Width și Size.Height:
7
Adăugăm al doilea buton, tot cu dublu-clic pe itemul Button din fereastra Toolbox,
iarăși apare pe formă un dreptunghi pe care scrie tot button1. Lui îi setăm următoarele
proprietăți: Name – btnStop, Text – Stop, Location.X – 380, Location.Y – 500,
Size.Width – 80 și Size.Height – 30.
Verificăm ce am făcut până acum: rulăm aplicația, observăm că pe formă au apărut două
butoane care nu fac nimic deocamdată, închidem forma și inspectăm MainForm.Designer.cs
namespace TutorialWinForms
{
partial class MainForm
{
...
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStart = new System.Windows.Forms.Button();
this.btnStop = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(120, 500);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(80, 30);
this.btnStart.TabIndex = 0;
this.btnStart.Text = "Start";
8
this.btnStart.UseVisualStyleBackColor = true;
//
// btnStop
//
this.btnStop.Location = new System.Drawing.Point(380, 500);
this.btnStop.Name = "btnStop";
this.btnStop.Size = new System.Drawing.Size(80, 30);
this.btnStop.TabIndex = 1;
this.btnStop.Text = "Stop";
this.btnStop.UseVisualStyleBackColor = true;
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(584, 561);
this.Controls.Add(this.btnStop);
this.Controls.Add(this.btnStart);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.Name = "MainForm";
this.Text = "Desenator";
this.ResumeLayout(false);
#endregion
În ultimele două linii de cod observăm că acum clasa MainForm este dotată cu două
câmpuri private, btnStart și btnStop, ambele de tip System.Windows.Forms.Button. Atenție:
butoanele nu sunt forme, clasa Button este definită în spațiul de nume System.Windows.Forms,
în care este definită și clasa Form, în acest spațiu de nume sunt incluse multe alte clase utilizate la
derivarea clasei Form.
I.2. Setarea evenimentelor. În continuare vom alege, tot cu ajutorul designerului, evenimentele
la care trebuie să modificăm răspunsul implicit al formei și al butoanelor sale.
Începem cu forma: în editor deschidem mainform.cs[design] și selectăm forma, iar în
fereastra properties selectăm tab-ul events (pictograma fulger).
Rularea aplicației începe cu încărcarea formei principale pe ecran, și noi dorim ca la acel
moment să aibă loc unele acțiuni descrie mai tarziu în codul sursă, prin urmare acum doar selec-
tam evenimentul Load și executăm un dublu-clic pe itemul corespunzător.
9
Se deschide automat fișierul MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TutorialWinForms
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
}
}
}
în care observăm că MainForm a fost dotată cu metoda MainForm_Load(), iar dacă deschidem
fișierul în MainForm.Designer.cs vedem că în corpul metodei InitializeComponent() a
apărut instrucțiunea
10
care adaugă metoda MainForm_Load în lista acțiunilor executate la încărcarea formei pe ecran.
Altfel spus, MainForm_Load() este un handler de eveniment pentru MainForm.Load. Vom reveni
cu detalii într-un tutorial viitor.
Codul metodei MainForm_Load() va fi completat manual în etapa a II-a, acum revenim la
MainForm.cs[Design] și în fereastra Properties adăugăm, tot cu dublu-clic, un handler pentru
evenimentul FormClosing:
11
Verificăm ce am realizat până acum: în MainForm.cs completăm provizoriu metodele
private void btnStart_Click(object sender, EventArgs e)
{
MessageBox.Show("Salut!\nsender=" + sender + " this=" + this);
}
Ca regulă generală: expeditorul unui mesaj provocat de maus, sender-ul, este componenta
asupra căreia a acționat mausul, și tot ea trebuie să furnizeze răspunsul la mesaj, folosind even-
tual informațiile atașate evenimentului în parametrul EventArgs e.
II. Scrierea codului. Am ajuns la etapa în care implementăm comportamentul dorit al butoane-
lor: Start lansează desenarea iar Stop o oprește.
Pentru început vom completa MainForm.cs cu codul de mai jos, apoi vom rula programul
și la final vom da explicațiile necesare. Tastăm:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TutorialWinForms
{
public partial class MainForm : Form
{
Graphics dc; //Device Context
Pen pen1, pen2; //pentru tras linii colorate
bool seLucreaza; //semafor
12
public MainForm()
{
InitializeComponent();
seLucreaza = false;
pen1 = new Pen(Color.Gold, 1);
pen2 = new Pen(this.BackColor, 1);
13
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
seLucreaza = false;
}
}
}
Am construit o aplicație condusă de evenimente, o event-driven application, la rulare ea
afișează pe ecrean o formă care stă și așteaptă să se producă un eveniment care să o vizeze. După
ce răspunde la eveniment, revine în starea de așteptare, starea idle.
Observăm că la prima afișare focusul este deținut de butonul Start, care poate fi actionat
astfel și cu tasta space. Această setare inițială este scrisă în MainForm_Load().
Apăsarea butonului Start, tratată în btnStart_Click(), mută focusul pe butonul Stop,
lansează desenarea cu apelul metodei Deseneaza(), și la terminarea acestui apel, care are loc
numai după apăsarea butonului Stop, își trage focusul înapoi.
Pentru a stopa desenarea am folosit un semafor logic, câmpul bool seLucreaza, dese-
narea are loc atât timp cât acesta are valoarea true, la false se oprește. Prin urmare, apăsarea
butonului Stop setează seLucreaza la false, iar apăsarea butonului Start îl setează la true,
înaintea apelului metodei Deseneaza().
Deoarece oprirea ciclării din for-ul din Deseneaza() are loc numai prin setarea la false
a semaforului, dacă vom închide forma în timpul desenării aceasta va fi doar ascunsă, devenind
invizibilă, dar aplicația va rămâne în execuție în fundal, consumând pe ascuns resursele sistemu-
lui, și va putea fi oprită numai din Task Manager. Ca să prevenim acest bug dezastruos utilizăm
evenimentul FormClosing, care se produce când este apăsat cu mausul căsuța X din colțul din
dreapta sus al formei. În MainForm_FormClosing() setăm seLucreaza = false, oprim astfel
desenarea dacă este în desfășurare, iar aplicația iese din rulare odată cu închiderea formei.
Ca să desenăm direct pe suprafața formei avem nevoie de un “context de dispozitiv”, un
device context, o interfață între sistemul de operare și placa grafică. În C# acesta este obținut prin
utilizarea unui obiect din clasa System.Drawing.Graphics, pe care este bine să nu îl instanțiem
în constructorul clasei, ci la încărcarea formei, prin apelul metodei CreateGraphics(). Astfel
suntem siguri că interfața grafică va funcționa corect.
Desenul este format din linii trasate cu metoda clasei System.Drawing.Graphics
void DrawLine(System.Drawing.Pen pen, float x1, float y1, float x2, float y2);
și pentru aceasta folosim două penițe, pen1 și pen2, inițializate în constructor. Metoda unește
punctele (x1,y1) și (x2,y2) cu o linie de culoare și grosime setată în penița folosită. Coordonatele
sunt relative la suprafața client a formei, cea de sub bara de titlu, originea este în colțul de stânga
sus, x crește de la stânga la dreapta, iar y de sus în jos.
În metoda Deseneaza() fixăm punctul (x0,y0) în centrul suprafeței client a formei și par-
curgem cercul cu centrul în (x0,y0) și cu raza de 200 pixeli folosind binecunoscutele ecuații pa-
rametrice ale cercului:
{ x (t)=x 0 +r cos t
y (t)= y 0+ r sint
14
O importanță deosebită o are apelul Application.DoEvents() din interiorul ciclului for,
care obligă aplicația să întrerupă desenarea și să proceseze evenimentele care s-au produs între
timp, de la precedentul apel, actualizând astfel valoarea semaforului seLucreaza dacă a fost
apasat butonul Stop. Fără acest apel ciclul for ar deveni o buclă infinită cu efect dezastruos la
rulare. La prima apăsare a butonului Start forma ar îngheața, aplicația nu ar mai răspunde la
mesaje și ar putea fi oprită numai din Task Manger. Încercați!
3 Prin bitmap se înțelege, în general, o matrice de întregi, elementul c(i,j) fiind culoarea pixelului de coordonate
(i,j) codificată într-un număr întreg. Aici prin bitmap înțelegem un obiect din clasa System.Drawing.Bitmap.
15