Butonul nu trebuie să aibă un aspect standard (deși personal nu găsesc aspectul butonului standard plictisitor sau "simplu"). Cu toate acestea, pentru mulți dezvoltatori și utilizatori, butoanele cu aspect non-standard arată mai atractivă. Prin urmare, pentru a oferi un stil interfeței propriilor programe, puteți utiliza butoanele care afișează un bitmap (bitmap).
Windows are mecanisme integrate și API-uri care sprijină crearea de butoane (precum și alte controale) care au un aspect nestandard. Metoda de a face apariția controlului depinde de stilul său. În acest caz, stilul de care avem nevoie este BS_OWNERDRAW. Din numele său se vede că redarea tipului de buton execută codul de utilizator plasat în funcția fereastră (dialog) a proprietarului ferestrei de control.
Să luăm în considerare etapele de bază ale redării unui control care are stil xx_OWNERDRAW.
- Fereastra părinte a mesajului este WM_MEASUREITEM. în care un indicator pentru structura MEASUREITEMSTRUCT este trecut prin parametrul lParam. Operatorul de mesaje trebuie să stabilească câmpurile itemWidth și itemHeight ale structurii astfel încât să conțină lățimea și înălțimea respectivului element de control. Dacă am procesat mesajul, manipulatorul trebuie să returneze TRUE din procedura ferestrei. Acest mesaj vine la proprietar o dată când creați controlul.
- De fiecare dată, dacă este necesar, redeschiderea controlului către proprietar vine cu mesajul WM_DRAWITEM. Parametrul lParam al mesajului conține un indicator pentru structura DRAWITEMSTRUCT. pregătite de sistem. Sarcina acestui mesaj este să furnizeze contextul în care va fi redat controlul. Mânerul contextului însoțește informații suplimentare despre starea internă a comenzii, necesară (posibil) pentru a schimba aspectul acesteia, precum și informații despre tipul de acțiune efectuată în prezent cu comanda. În continuare vom vedea cum pot fi folosite aceste informații pentru a schimba aspectul butonului. Și, din nou, dacă procesăm acest mesaj, manipulatorul trebuie să returneze TRUE din procedura ferestrei.
După cum ne dăm seama, deși în mod independent, pot desena, dar încă butonul, ar fi frumos dacă acesta a fost comportamentul butoanelor convenționale - margine în starea normală ar trebui să simuleze un control convex, atunci când deprimat - deprimat, în timpul unui buton de focalizare ar trebui să fie pe imaginați un dreptunghi realizat de linia întreruptă, iar în starea inactivă butonul trebuie să difere brusc în culori (fie fundalul, inscripția, fie ambele).
Este ușor de observat că, dacă doriți să implementați pe deplin comportamentul standard al butonului, va trebui să pregătim un set suficient de mare de imagini raster:- convex fără focalizare și accelerator
- Convex cu focalizare fără accelerator
- convex fără focalizare cu acceleratorul
- Convex cu focalizare și accelerator
- fără focalizare și accelerator
- Impact cu focalizare fără accelerator
- deprimat fără focalizare cu acceleratorul
- Impact cu focalizare și accelerator
- inactiv
Sunteți, ca dezvoltator, aveți dreptul de a decide cât de corect veți urma această tehnică (de exemplu, în aplicația demo am oprit la o opțiune fără acceleratori :)).
Îndeplinirea acestor cerințe, ne putem pregăti cinci bitmap-uri (convexe / un încastrat, cu un accent / nu de focalizare, inactivă), punerea în aplicare aspectul fiecăruia dintre statele din buton, și trage momentul potrivit (asta în cazul în care este necesar să se cunoască starea actuală a butonului), unul dintre ele. În acest caz, noi înșine controlăm complet aspectul butonului din fiecare stat. Impresia pe care o veți avea asupra utilizatorului va depinde în întregime de gustul dvs. și de capacitatea de a crea imagini raster.
În ceea ce privește codul care implementează logica necesară funcționării, poate arăta astfel:
După cum puteți vedea, nimic complicat. Codul este împărțit în două părți: prima, pe baza informațiilor cu privire la acțiunile efectuate (itemAction) și starea curentă a butonului (itemState) selectează bitmap dorit, în a doua parte are loc în producția de context butoane bitmap selectat.
Versiunea anterioară a codului de mai sus conține următorul fragment în loc de a apela DrawState ().
În opinia mea, ambele opțiuni sunt echivalente în termeni de funcționalitate, dar încă în fragmentul cu BitBlt () există mai multe oportunități de a face o greșeală, ceea ce duce la o scurgere de resurse.
Codul este încadrat prin verificarea identificatorului de control necesar, deoarece există mai multe controale în programul de lucru.
Cititorul atent este gata să pună o întrebare cu privire la faptul că, la început, nu numai mecanismele menționate (puse în aplicare, așa cum am descoperit, prin posturi WM_MEASUREITEM și WM_DRAWITEM), dar API?
Într-adevăr, există mai multe funcții care facilitează vizualizarea standard a comenzilor OWNERDRAW. Developer pregătește nostru bitmap principal pentru butonul, și pentru a trage limitele și stările buton (inactive și în afara focalizării) utilizează funcții WinAPI - DrawEdge () (controlul frontierelor - pentru „convexe / deprimat“), DrawState () (starea „activ / inactiv“) și DrawFocusRect () (starea "în focalizare"). În acest caz, codul de mai sus va arăta astfel:
Câștigul unei astfel de abordări constă în utilizarea redusă a resurselor pregătite în mod independent și reducerea consumului în timpul funcționării programului. Pentru dezavantaje (și foarte vizibil, în opinia mea) este că există o pierdere de control asupra apariției butonului în diferitele sale stări. Cu toate acestea, activitatea acestor funcții vizează menținerea aspectului standard al comenzilor, astfel încât rezultatul nu este foarte expresiv. În opinia mea, această tehnică este mai potrivită pentru punerea în aplicare a butoanelor care au în principiu un aspect standard, dar sunt dotate cu mici imagini în vecinătatea textului butonului.
Trebuie remarcat faptul că, în cazul în care este necesar, este posibil (și, uneori, este necesar) de a utiliza o combinație a metodelor de mai sus, să presupunem că pentru a utiliza pentru a desena patru (sau mai multe) din bitmap, dar pentru a trage funcția de frontieră DrawEdge ().