În momentul în care o parte a ferestrei este ascunsă, pixelii ascunși sunt pierduți, deoarece Windows eliberează memoria pe care o ocupă. Cu toate acestea, ea amintește că o parte a ferestrei a fost ascunsă, iar când constată că această parte a ferestrei din nou deschisă, aplicația solicită fereastra care deține redesena conținutul său. Există câteva excepții de la această regulă - de obicei, atunci când vine vorba de acoperirea o foarte mică parte a ferestrelor pentru o perioadă scurtă de timp (un bun exemplu este alegerea element din meniul principal atunci când cade din submeniul temporar, acoperind o parte a ferestrei). De obicei, vă puteți aștepta ca dacă o parte a ferestrei să fie ascunsă, aplicația dvs. ar trebui să o redeschidă.
Aceasta este cauza problemei cu aplicația noastră de probă. Am pus codul de desen în constructorul Form1, care se numește o singură dată când aplicația este pornită, iar noi nu mai putem apela acest constructor din nou pentru a ne redresa formele atunci când este necesar mai târziu.
Când lucrați cu controalele Windows Forms, nu este nevoie să știți nimic despre modul în care rezolvă această problemă. Adevărul este că controalele standard sunt destul de complexe și știu cum ar trebui să se redreseze în orice moment când le cere Windows despre ele. Acest lucru explică de ce elementele de control ale programării, nu trebuie să ne facem griji cu privire la procesul real de desenare. Dacă ne asumăm responsabilitatea pentru afișarea ecranului aplicației noastre, trebuie, de asemenea, să ne asigurăm că aplicația răspunde corect la cererile Windows referitoare la redesenarea tuturor părților ferestrei sale. În secțiunea următoare, vom face modificările necesare pentru a face acest lucru.
Desenarea conturului folosind funcția OnPaint ()
Nu vă faceți griji dacă explicațiile anterioare au creat impresia că desenarea propriei interfețe de utilizator pare a fi îngrozitor de dificilă. Efectuarea unei aplicații redesenate, când este necesar, este de fapt destul de simplă.
Windows notifică aplicația că este necesară o redirecționare, declanșând evenimentul Paint. Interesant, clasa Forma are deja un handler pentru acest eveniment, deci nu trebuie să-l adăugăm pe noi înșine. Handlerul Form1 pentru evenimentul Paint este conținut în metoda virtuală OnPaint (). care este trecut printr-un singur parametru PaintEventArgs. Aceasta înseamnă că tot ce trebuie să facem este să ignorăm OnPaint (). astfel încât să facă desenul necesar.
În această secțiune, creați o nouă aplicație Windows numită DrwShapes. Ca și înainte, setați culoarea de fundal la alb, utilizând fereastra de proprietăți. În plus, schimbați textul ferestrei în Proba DrawShapes. După aceea, adăugați fragmentul următor la codul generat de clasă Form1.
protejat override void OnPaint (PaintEventArgs e)
Grafica dc = e.Grafica;
Pen albastruPen = stilou nou (Culoare albastru, 3);
Pen redPen = Pen nou (culoarea roșie, 2);
dc.DrawEllipse (redPen, 0, 50, 80, 60);
Rețineți că metoda OnPaint () este declarată protejată, deoarece este folosită în mod normal în interiorul clasei, astfel încât nu există niciun motiv pentru ca orice cod din afara clasei să știe despre existența sa.
PaintEventArgs este succesorul clasei EventArgs, care este utilizat în mod obișnuit pentru a trimite informații despre evenimente. PaintEventArgs are două proprietăți suplimentare, dintre care cea mai importantă este instanța Graphics, deja pregătită și optimizată pentru desenarea zonei dorite a ferestrei. Aceasta înseamnă că nu trebuie să apelăm CreateGraphics () în metoda OnPaint () pentru a obține DC - am primit deja. A doua proprietate suplimentară va fi, de asemenea, luată în considerare în curând; Acesta conține informații mai detaliate despre ce zonă de ferestre trebuie într-adevăr să fie reproiectată.
În implementarea noastră OnPaint (), primul lucru pe care îl primim este o referință la obiectul Graphics din PaintEventArgs, apoi desenați formele noastre exact așa cum am făcut înainte. Și la sfârșit numim metoda OnPaint () a clasei de bază. Acest pas este important. Am redefinit funcția OnPaint () pentru a realiza propriul desen, dar este posibil ca Windows să aibă ceva de făcut în timpul procesului de desenare - toate aceste lucruri se vor face în metoda OnPaint () a uneia dintre clasele de bază .NET.
În acest exemplu, dacă eliminați funcția OnPaint () a clasei de bază, nu vom vedea niciun efect special. Cu toate acestea, nu trebuie să cedăm tentației de a renunța la această provocare. Acest lucru poate perturba funcționarea normală a Windows, iar rezultatele pot fi imprevizibile.
Metoda OnPaint () este de asemenea apelată atunci când aplicația este inițializată atunci când fereastra noastră este afișată pentru prima dată pe ecran. În acest caz, nu este nevoie să duplicați codul de desen în constructor.
Fig. 33.2. Rezultatul exempluului DrawShapes când forma este suprapusă de o altă fereastră
Rularea acestui cod va produce inițial același rezultat ca și exemplul anterior, cu excepția faptului că aplicația noastră se comportă corect atunci când fereastra este minimizată sau partea ei este ascunsă.
Utilizând regiunea de tăiere
Aplicația de exemplu DrawShapes din secțiunea anterioară ilustrează principiile principale referitoare la desenarea ferestrelor, deși nu este foarte eficientă. Motivul este legat de o încercare de a atrage totul în fereastră, indiferent de câte elemente trebuie de fapt redesenate. În Fig. Figura 33.2 arată ieșirea din exemplul DrawShapes și apoi deschide o altă fereastră și o deplasează peste forma DrawShapes, astfel încât o parte din ea să se suprapună.
Până acum, atât de bine. Cu toate acestea, atunci când mutăm fereastra care se suprapune astfel încât fereastra DrawShapes să fie din nou pe deplin vizibilă, Windows va trimite, ca de obicei, formularul nostru un eveniment Paint, solicitând redesenarea lui. Dreptunghiul și elipsa sunt în colțul din stânga sus al zonei clientului și, prin urmare, au rămas vizibile tot timpul. Astfel, de fapt, nu mai era nevoie să le redreseze tot timpul, pe lângă redactarea fundalului alb al ferestrei. Cu toate acestea, Windows nu știe despre acest lucru și, prin urmare, crede că ar trebui să genereze un eveniment Paint, ceea ce duce la apelul implementării noastre OnPaint (). Iar această implementare realizează o redesenare completă a unui dreptunghi și a unei elipse.
Ca urmare a acestei cereri la o instanță de grafică a efectua unele desen în afara zonei invalidat va duce aproape sigur la o pierdere de timp CPU și încetini aplicația. Într-o aplicație bine proiectată, codul ar trebui să ajute contextul dispozitivului prin efectuarea câtorva verificări simple pentru a vă asigura că nu există o încercare excesivă de a apela metodele instanței Graphics. În această secțiune, vom codifica un nou exemplu de DrawShapesWithClipping, modificând formatele de afișare anterioare. În codul OnPaint () controale simple, vor fi efectuate pentru a se asigura că zona invalidă se suprapune cu zona în care doriți să atragă, și numai dacă acesta este cazul, se efectuează desen.
În primul rând, trebuie să obținem informații despre regiunea de tăiere. Pentru aceasta, avem nevoie de noua proprietate ClipRectangle a clasei PaintEventArgs. Proprietatea ClipRectangle conține coordonatele zonei redesenate, care este reprezentată ca o instanță a structurii System.Drawing.Rectangle. Aceasta este o structură destul de simplă - conține patru proprietăți care ne interesează: Top, Bottom,