Grafica Gdi a noii generații

Grafica Gdi a noii generații

Obiecte grafice

Pentru ieșirea primitivelor, sunt necesare anumite setări: setarea culorii și grosimea liniilor ("stilou"), tipul de umplere a zonelor solide ("perii"), dimensiunile și contururile fonturilor ș.amd. De regulă, diferite interfețe de programe grafice stochează astfel de setări sub forma propriilor structuri de date - obiecte grafice. Acest lucru este valabil atât pentru GDI, cât și pentru GDI +, dar utilizarea obiectelor este diferită. Luați în considerare aceste diferențe pe exemplul unei mici sarcini - desenarea unui pătrat.

Model de stat în GDI

GDI utilizează un model de software numit modelul statal. Aceasta înseamnă că setările efectuate pentru dispozitivul de ieșire sunt memorate și există un concept al obiectului selectat în prezent. Înainte de a emite primitive, trebuie selectat obiectul grafic dorit în dispozitivul de ieșire (utilizând funcția SelectObject). Astfel, setând, de exemplu, o grosime a liniei de 3 pixeli, se pot obține mai multe segmente ale grosimii selectate:

Această abordare are avantajele sale - odată ce ați instalat pixul selectat (HPEN), nu este necesar să îl transferați la funcția de ieșire de fiecare dată. Cu toate acestea, simplitatea sa transformat adesea în probleme serioase - o scurgere notorie de resurse.

Uită-te la linia evidențiată. De ce a fost necesar să ne amintim și să restaurăm stiloul vechi în context, dacă nu a fost folosit pentru desen? Problema este că obiectul grafic selectat în context nu poate fi șters - o astfel de arhitectură a fost aleasă la crearea GDI. Prin urmare, fără această linie, apelul către DeleteObject va eșua și creionul creat va rămâne "agățat" în GDI Heap. Din moment ce mesajul WM_PAINT ajunge destul de des la fereastră, pe sistemele Windows 9x (unde dimensiunea GDI este limitată la 64 KB), acest lucru va duce rapid la epuizarea resurselor grafice ale sistemului. După aceea, toate programele se vor comporta foarte ciudat: nu redrafli unele elemente de meniu și pictograme, desenați text cu fonturi suspecte etc. Sistemele de pe platforma NT vor rămâne pe linia de plutire pentru un pic mai mult, deoarece grămada lor grafică poate crește după cum este necesar, dar există o limită a numărului de simultan create în procesul de obiecte grafice - 12.000.

O altă problemă este că programatorii C ++ sunt obișnuiți să curețe automat resursele folosite folosind clase cu destructori și "pointeri inteligenți". În acest caz, este ușor să uiți de necesitatea de a șterge ceva în mod explicit. Cu toate acestea, bibliotecile existente în GDI wrapper nu pot rezolva problema ștergerii obiectului selectat în contextul programatorului. Acest lucru are ca rezultat, de asemenea, scurgeri de resurse GDI.

Modelul fără stat în GDI +

O caracteristică distinctivă a programatorului GDI + este modificarea modelului de software în lucrul cu dispozitivele de ieșire. Conceptul obiectului grafic selectat în prezent în dispozitiv este eliminat ca ineficient și depășit. În locul setării secvențiale a parametrilor de context (Grafic), se utilizează o enumerare a atributelor de fiecare dată când se invocă metoda grafică. Dispozitivul de ieșire nu pare să aibă starea, ci obține informațiile necesare prin intermediul parametrilor. Acest model este numit model fără stat.

Desigur, o astfel de clasificare este condiționată. Există, de asemenea, acești parametri (de exemplu, setările de anti-aliasing curente, sistemul de coordonate selectat etc.), care sunt stocate în clasa Graphics și în structurile aferente. Dar starea primitivelor GDI + nu este stocată în contextul mapării.

Acum, fiecare metodă care utilizează un obiect grafic pentru ieșire necesită specificarea explicită a acestui obiect ca parametru:

Utilizând parametrul callbackData, puteți, de exemplu, să transmiteți un pointer metafile la procedura metaCallback (versiunea pentru C ++), ale cărei intrări sunt listate în acest moment. Apoi puteți folosi metoda Metafile :: PlayRecord pentru a executa comenzile grafice:

Parametrul recordType pentru fiecare apel invers are o valoare din enum EmfPlusRecordType. care conține cel mult 253 de elemente (cea mai mare enumerare GDI +). Toate aceste elemente corespund fie direct comenzilor GDI / GDI +, fie desemnează înregistrări de servicii ale metafilelor. Când apelați PlayRecord, puteți să înlocuiți acest parametru cu valorile pentru a efectua comenzi GDI + complet diferite în metoda PlayRecord. Dar pentru aceasta este necesar să cunoaștem cu fermitate semnificația parametrilor nedocumentați corespunzători recordData și dataSize (și să transmitem, respectiv, valorile modificate în ele).

Enumerarea înregistrărilor: specificitatea .NET

Documentația WinForms specifică faptul că mediul .NET oferă propria versiune a delegatului pentru executarea comenzilor metafile corespunzătoare în corpul nostru de handler de apel invers. Această versiune este transmisă parametrului de apel callbackData. Pentru a executa comanda, este suficient să apelați delegatul primit (exemplu copiat din documentație):

Atenție vă rog! Aceasta este o eroare evidentă în documentația .NET Framework (oh, pentru a unsprezecea oară!) Exemplul de mai sus se va compila, dar executarea sa va duce la nimic bun. Același lucru este spus în cartea lui Petzold [3].

Experimentele au arătat că în parametrul callbackData, o valoare zero este întotdeauna trecută, indiferent de faza lunii. Chemarea unui astfel de "delegat" se va încheia cu excepția NullReferenceException.

Cu toate acestea, este posibil să creați o versiune de lucru a metodei EnumerateMetafile pentru .NET. Pentru a face acest lucru, va trebui să ne jucăm puțin mai repede cu metoda Metafile.PlayRecord. De fapt, este necesar ca matricea de octeți să fie parametrul de date:

Da, pentru a atinge obiectivul râvnit (sortarea prin fișierele metafile în WinForms), trebuia să lucrăm puțin. Dar aceste dificultăți sunt mai mult decât plătite de o altă calitate remarcabilă. NET - reflecție. Orice element de enumerare (chiar și un astfel de gigant ca EmfPlusRecordType) "știe" numele de șir, ceea ce face ușor să creeze o versiune de aplicație care să includă înregistrările metafilei selectate după nume. Iată un fragment al programului demo:

Simplu, nu-i așa? Metoda ToString va returna numele șirului elementului de enumerare, salvând programatorul de la codarea obositoare a constantelor șirului de 253. Iată rezultatul acestei metode:

Grafica Gdi a noii generații

Textul complet al aplicației (vă permite să executați numai comenzile metafile selectate de utilizator) este pe CD-ROM în jurnal. Există, de asemenea, o versiune compilată, care poate fi utilizată pentru a studia conținutul diferitelor metafile (de exemplu, incluse în livrarea Microsoft Visual Studio):

Grafica Gdi a noii generații

Mult noroc în munca de cercetare!

Resurse utile

Articole similare