Sunteți pe pagina 1din 65

Visual C++

Scurt descriere
VisualC++ poate fi utilizat pentru a dezvolta programe pentru trei platforme Win32: Windows NT (pe
procesoare multiple), Windows 95/98 , XP si Win32s.
Windows NT este un SO multifir (multithreaded ) pe 32 biti cu mediu grafic integrat si posibilitati de server
avansate. A fost dezvoltat pentru a maximiza portabilitatea, stabilitatea si securitatea.
Subsistemul Win32s este un alt nivel pentru Windows 3.1; acesta implementeaza un subset al sistemului
Win32 care permite executia aplicatiilor pe 32 biti.

Windows i Mesajele
Windows este referit adesea ca un sistem de operare bazat pe mesaje. Fiecare eveniment (apasarea unei
taste, clic de mouse, etc.) este transformat ntr-un mesaj. In mod obinuit aplicaiile sunt construite n jurul unei
bucle de mesaje care regsete aceste mesaje i apeleaz funcia potrivit pentru a trata mesajul.
Mesajele, dei sunt trimise aplicaiilor, nu se adreseaz acestora, ci unei alte componente fundamentale a SO,
fereastra (windows). O fereastra este mai mult dect o zon dreptunghiular afiat pe ecran; aceasta reprezint o
entitate abstract cu ajutorul creia utilizatorul i aplicaia interacioneaz reciproc.

Aplicaii, Fire i Ferestre


O aplicaie Win32 const din unul sau mai multe fire (threads), care sunt ci paralele de execuie. Gndim firele ca
fiind multatsking-ul din cadrul unei aplicaii.
Observaie: Sub Win32s, poate rula o aplicaie cu un singur fir de execuie.
O fereastr este totdeauna gestionat de un fir; un fir poate fi proprietarul uneia sau mai multor ferestre sau pentru
nici una. In final, ferestrele sunt ntr-o relaie ierarhic; unele sunt la nivelul cel mai de sus, altele sunt subordonate
prinilor lor, sunt ferestre descendente.

Procese, fire i ferestre

Exista mai multe tipuri de ferestre in Windows; cele mai obinuite sunt asociate cu o aplicaie. Boxele de dialog din
cadrul unei ferestre sunt de asemenea ferestre. Acelai lucru pentru butoane, controale de editatre, listbox-uri,
icoane, etc.

Clase Window
Comportarea unei ferestre este definita de clasa fereastr (window class). Clasa fereastr menine
informaii despre modul de afiare iniial, icoana implicit, cursor, resursele meniu i cel mai important lucru adresa
funciei ataat ferestrei procedura fereastr window procedure. Cnd o aplicaie proceseaz mesaje, aceasta se
face n mod obinuit prin apelul funciei Windows DispatchMessage pentru fiecare mesaj primit;
DispatchMessage la rndul ei apeleaz procedura fereastr corespunztoare, identificnd iniial crei ferestre i este
trimis mesajul. n continuare procedura fereastr va trata mesajul.
Exist mai multe clase fereastr standard furnizate de Windows. Aceste clase sistem globale implementeaz
n general funcionalitatea controalelor comune. Orice aplicaie poate folosi aceste controale, de exemplu orice
aplicaie poate implementa controale de editare, utiliznd clasa fereastra Edit.
Aplicaiile pot de asemeni s-i defineasc propriile clase fereastr cu ajutorul funciei RegisterClass. Acest
lucru se ntmpl n mod obinuit pentru fereastra principal a aplicaiei (icoana, resurse, etc.).
Windows permite de asemeni subclasarea sau superclasarea unei ferestre existente.
Subclasarea substituie procedura fereastr pentru o clas ferestr cu o alt procedur. Subclasarea se
realizeaz prin schimbarea adresei procedurii fereastr cu ajutorul funciei SetWindowLong (instance subclassing)
sau SetClassLong (subclasare global).
Instance subclassing nseamn c se schimb numai comportarea ferestrei specificate.
Global subclassing nseamn c se schimb comportarea tuturor ferestrelor de tipul specificat.
Observaie: Global subclassing se comport diferit in Win32 i n Windows pe 16 bii (Win32s). In cazul Win32,
aceasta afecteaz numai fereastra care este sub controlul aplicaiei ce face subclasarea; n windows pe 16 bii, efectul
este global, se afecteaz ferestrele fiecrei aplicaii.
Superclasarea creaz o nou clas bazat pe o clas existent, reinnd numai procedura fereastr.
Pentru a superclasa o clas fereastr, o aplicaie regsete informaiile despre clasa fereastr utiliznd funcia
GetClassInfo, modific structura WNDCLASS astfel recepionat i folosete structura modificat ntr-un apel al
funciei RegisterClass. GetClassInfo ntoarce de asemenea i adresa procedurii fereastr. Mesajele pe care
noua fereastr nu le trateaz trebuie trecute acestei proceduri.

Tipuri de mesaje
Mesajele reprezint n fapt evenimente la diferite nivele ale aplicaiei. Exist o clasificare a acestor mesaje (din
pcate nu prea exact): mesaje fereastr, mesaje de notificare i mesaje de comand, dar deocamdat nu ne
intereseaz acest lucru.
Mesajele windows constau din mai multe pri, descrise de structura MSG.
typedef struct tagMSG {
HWND
hwnd;
UINT
message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
Descriere:

hwnd identific n mod unic fereastra la care a fost transmis acest mesaj. Fiecare fereastr n Windows are un
asemenea identificator.
message reprezint identificatorul mesajului. Identificatorii mesajului sunt referii n mod obinuit cu ajutorul
constantelor simbolice dect prin valoarea lor numeric care o au n sistem. Aceast descriere se gsete n
windows.h.
Urmtoarele elemente pot fi privite ca parametrii ai mesajului, care au valori specifice funcie de fiecare mesaj n
parte.
Marea majoritate a mesajelor ncep cu WM_. De exemplu WM_LBUTTONDOWN, WM_MOUSEMOVE,
WM_LBUTTONUP, etc.
Aplicaiile pot s-i defineasc propriile mesaje. Cerina major este ca identificatorul mesajului s fie unic. Pentru a
defini un mesaj n sistem folosim funcia RegisterWindowMessage.

Mesaje i multitasking
In Windows 3.1, bucla de mesaje are rol important n interaciunea dintre aplicaii i SO. Funcionarea corect a unui
SO Windows 3.1 depinde de cooperarea dintre aplicaii. Aplicaiile sunt cele care permit SO s preia controlul. Acest
neajuns este nlturat n Windows 95/98, NT, 2000. SO este cel care realizeaz programarea aplicaiilor pentru
cuantele de timp necesare pe procesor. Dei aceast planificare a execuiei este diferit pe Windows 95/98 fa de
NT, rolul primordial revine SO.

Cozi de mesaje
n Windows pe 16 bii, SO menine o singur coad de mesaje. Cnd o aplicaie ncearc s gseasc urmtorul
mesaj din coada de mesaje prin funciile GetMessage sau PeekMessage, SO poate efectua un context switch i
poate activa o alt aplicaie pentru care mesajele ateapt n coad. Mesajul din vrful cozii este extras i returnat
aplicaiei via structura MSG. Dac aplicaia eueaz n apelul lui GetMessage, PeekMessage sau Yield,
aceasta blocheaz sistemul. Coada de mesaje poate deveni plin...
n Win32 (95/98, NT, 2000) mecanismul cozii de mesaje este mult mai complicat. O singur coad de mesaje nu
mai rezolv problema. Aici sistemul de operare d controlul unei aplicaii i tot SO permite multitasking-ul. Dou
sau mai multe fire pot accesa coada de mesaje n acelai timp i nu exist nici o garanie c mesajele extrase sunt ale
lor.
Acesta este unul motivele pentru care coada de mesaje a fost separat n cozi de mesaje individuale pentru fiecare
fir din sistem.

Procese i Fire
ntr-un SO non-multifir, de exemplu UNIX, unitatea cea mai mic de execuie este task-ul sau procesul .
Mecanismul de planificare (aparine SO) al task-urilor va comuta ntre acestea; multitasking-ul se realizeaz ntre
dou sau mai multe procese (task-uri). Dac o aplicaie are nevoie s execute mai multe funcii simultan, atunci
aceasta se va divide n mai multe task-uri. Din aceast tehnic decurg anumite neajunsuri, consum de resurse, timp
de lansare a unui nou task, spaii de adrese diferite, probleme de sincronizare, etc.
n contrast, ntr-un sistem multifir (multifilar, multithreaded) unitatea cea mai mic de execuie este firul,
nu procesul. Un proces sau task poate conine mai multe fire, dintre care unul singur este firul principal, firul primar.
Lansarea n execuie a unui nou fir cere mai puine resurse din partea SO, firul ruleaz n cadrul aceluiai proces,
problemele de sincronizare sunt i nu sunt complicate. Oricum apar dou sincronizri: sincronizare ntre procese i
sincronizare ntre fire.

Fire i Mesaje
Dup cum am mai spus proprietarul ferestrei este firul de execuie. Fiecare fir are coada proprie, privat, de
mesaje n care SO depoziteaz mesajele adresate ferestrei. Aceasta nu nseamn c un fir trebuie neaprat s aib o
fereastr proprie i o coad proprie de mesaje. Pot exista fire i fr fereastr i fr bucl de mesaje.
n MFC, aceste fire se numesc worker threads (nu au ataat o fereastr, nu prezint interfa ctre utilizator), iar
celelalte se numesc user-interface threads.

Apeluri de funcii Windows


Windows ofer un mare numr de funcii pentru a executa o mare varietate de task-uri, controlul proceselor,
gestionarea ferestrelor, fiierelor, memoriei, servicii grafice, comunicaii, etc.
Apelurile sistem pot fi organizate n trei categorii:
1. servicii nucleu (apeluri sistem pentru controlul proceselor, firelor, gestiunea memoriei, etc.);
2. servicii utilizator (gestiunea elementelor de interfa ale utilizatorului cum ar fi ferestre, controale, dialoguri,
etc.);
3. servicii GDI (Graphics Device Interface) (ieirea grafic independent de dispozitiv).
Sistemul Windows include de asemenea funcii API pentru alte funcionaliti MAPI (Messaging API), TAPI
(Telephony API) sau ODBC (Open Database Connectivity).

Servicii Nucleu
Serviciile nucleu cuprind de obicei: getionarea fiierelor, memoriei, proceselor, firelor, resurselor.
Gestionarea fiierelor nu ar trebui s se mai fac cu funcii din bibliotecile C sau prin iostream-urile din
C++. Aplicaiile ar trebui s utilizeze conceptul Win32 de obiect fisier file object i funciile asociate cu acesta.
De exemplu exist fiiere mapate n memorie care asigura comunicarea ntre task-uri.
Referitor la gestionarea memoriei pe lng funciile cunoscute, SO Windows ofer funcii care pot
manipula spaii de adrese de sute de MB alocndu-le dar nefcnd commiting.
Cea mai important faet a proceselor i firelor este gestiunea sincronizrii. Problema este complet nou
i nu a fost ntlnit n Windows 3.1. n Win32, sincronizarea se face cu ajutorul unor obiecte de sincronizare, pe
care firele le pot utiliza pentru a informa alte fire despre starea lor, de a proteja zone senzitive de cod sau de a obtine
informatii despre alte fire sau starea altor obiecte.
In Win32 multe resurse nucleu sunt reprezentate ca obiecte obiecte nucleu: fiiere, fire, procese, obiecte
de sincronizare, etc. Obiectele sunt referite prin manipulatori, identificatori (handlers); exist funcii pentru
manipularea generic a obiectelor, pentru manipularea obiectelor de un anumit tip. Sub NT, obiectele au ataate
proprieti de securitate. De exemplu, un fir nu poate accesa un obiect fiier dac nu are drepturile necesare care s
coincid cu proprietile de securitate.
Modulul nucleu furnizezz de asemeni funcii pentru gestionarea resurselor interfa-utilizator. Aceste
resurse includ icoane, cursoare, abloane de dialog, resurse string, tabele de acceleratori, bitmap-uri, etc.
Nucleul NT furnizeaz printre altele: atribute de securitate pentru obiectele nucleu, backup, funcionalitatea
aplicaiilor de tip consol care pot utiliza funcii pentru memoria virtual sau pot utiliza mai multe fire de execuie.

Servicii utilizator
Modulul utilizator furnizeaz apeluri sistem care gestioneaz aspecte i elemente ale interfeei
utilizatorului; sunt incluse funcii care manipuleaz ferestre, dialoguri, meniuri, controale, clipboard, etc. Se
exemplific tipurile de operaii pentru fiecare resurs n parte (n general creare, modificare, tergere, mutare,
redimensionare, etc.).

Modulul utilizator furnizeaz funcii pentru managementul mesajelor i cozilor de mesaje. Aplicaiile pot
utiliza aceste apeluri pentru a controla coninutul cozii de mesaje proprii, a regsi i a procesa mesajele, a crea noi
mesaje. Noile mesaje pot fi trimise (sent) sau plasate (posted) la orice fereastr. Un mesaj plasat pentru o fereastr
funcia PostMessage - nseamn pur i simplu intrarea acestuia n coada de mesaje nu i procesarea imediat a
acestuia. Trimiterea unui mesaj (sent) implic tratarea lui imediat sau mai corect spus funcia SendMessage nu-i
termin execuia pn cnd mesajul nu a fost tratat.

Servicii GDI
Funciile din GDI sunt utilizate n mod obinuit pentru a executa operaii grafice primitive independente de
dispozitiv pe contexte de dispozitiv. Un context de dispozitiv este o interfa la un periferic grafic specific (n fapt
este o structur de date pstrat n memorie). Contextul de dispozitiv poate fi utilizat pentru a obine informaii
despre periferic i pentru a executa ieirile grafice pe acest periferic. Informaiile care pot fi obinute printr-un
context de dispozitiv, descriu n detaliu acest periferic.
Ieirea grafic este executat printr-un context de dispozitiv prin pasarea (trecerea) unui
manipulator (identificator) al contextului de dispozitiv funciilor grafice din GDI.
Contextele de dispozitiv pot descrie o varietate mare de periferice. Contextele de dispozitiv obinuite
includ: contexte de dispozitiv display, contexte de dispozitiv memorie (pentru ieirea unui bitmap memorat n
memorie) sau contexte de dispozitiv printer.
Un context de dispozitiv foarte special este contextul de dispozitiv metafile care permite aplicaiilor de a nregistra
permanent apelurile din GDI (fiierul pstreaz o serie de primitive grafice) care sunt independente de dispozitiv.
Metafiierele joac un rol crucial n reperzentarea independent de dispozitiv a obiectelor OLE nglobate.
Desenarea ntr-un context de dispozitiv se face cu ajutorul coordonatelor logice. Coordonatele logice
descriu obiectele utiliznd msurtori reale independente de dispozitiv, de exemplu, un dreptunghi poate fi descris ca
fiind lat de 2 inch i nalt de 1 inch. GDI furnizeaz funcionalitatea necesar pentru maparea coordonatelor
logice n coordonate fizice.
Diferene semnificative exist n modul cum aceast mapare are loc n Win32s, Windows 95 i Windows
NT.
Win32s i Windows 95 folosesc reprezentarea coordonatelor pe 16 biti.
Windows NT poate manipula coordonate pe 32 bii.
Toatre cele trei sisteme suport mapri (transformri) din coordonate logice n coordonate fizice. Aceste transformri
sunt determinate (influenate) de valorile ce specific originea coordonatelor i (signed extent) extensia cu semn a
spaiului logic i al celui fizic.
Originea coordonatelor specific deplasarea pe orizontal i vertical, iar extensia (extent) determina orientarea i
scara obiectelor dup mapare (transformare).
n plus, Windows NT ofer ceea ce se numete world transformation functions. Prin aceste funcii, orice
transformare liniar poate fi folosit pentru transformarea spaiului de coordonate logice n spaiul de coordonate
fizice; n plus pentru translaii i scalare ieirile pot fi rotite sau sheared.
Exemple de funcii grafice: Rectangle, Ellipse, Polygon, TextOut, etc.
Alte funcii de interes deosebit (bit blit functions: PatBlt, BitBlt, StechBlt) sunt cele legate de desenarea
i copierea bitmap-urilor.
Contextele de dispozitiv pot fi create i distruse, starea lor poate fi salvat i rencrcat.
Un alt grup de funcii gestioneaz transformrile de coordonate. Funcii comune tuturor platformelor pot fi utilizate
pentru a seta sau regsi originea i extent-ul unei ferestre (spaiul de coordonate logic) i viewport-ului (spaiul de
coordonate al perifericului destinaie).
NT posed funcii specifice pentru transformri matriceale.
Funciile GDI pot fi folosite de asemenea pentru gestionarea paletelor, aceasta nseamn c prin gestionarea paletei
de culori, aplicaiile pot selecta o mulime de culori care se potrivesc cel mai bine cu culorile din imaginea (gif, pcx.)
care trebuie afiat. Gestionarea paletei poate fi utilizat i n tehnici de animaie.

O alt trstur a GDI-ului este crearea i gestionarea obiectelor GDI (pensoane, penie, fonturi, bitmap-uri, palete)
precum i a regiunilor i a clipping-ului.

Alte API-uri

Funcii pentru controale comune;


Funcii pentru dialoguri comune;
MAPI, (Messaging Applications Programming Interface);
MCI (Multimedia Control Interface);
OLE API;
TAPI (Telephony API).

Raportarea erorilor
Majoritatea funciilor Windows folosesc un mecanism pentru evidenierea erorilor. Cnd apare o eroare, aceste
funcii seteaz o valoare a erorii pentru firul respectiv, valoare care poate fi regsit cu funcia GetLastError.
Valoarile pe 32 bii, returnate de aceast funcie sunt definite in winerror.h sau n fiierul header al bibliotecii
specifice.
Valoarea erorii poate fi setat i din cadrul aplicaiei cu ajutorul funciei SetLastError. Codurile de eroare
trebuie s aib setat bitul 29.

Folosirea funciilor din biblioteca C/C++


Aplicaiile Win32 pot folosi setul standard al funciilor din biblioteca C/C++ cu anumite restricii. Aplicaiile
Windows nu au acces n mod normal la stream-urile stdin, stdout, stderr sau obiectele iostream din C++. Numai
aplicaiile consol pot utiliza aceste stream-uri.
Funciile relative la fiiere pot fi folosite, dar acestea nu suport toate facilitile oferite de SO Windows securitate,
drepturi de acces.
n locul funciilor din familia exec se va folosi CreateProcess.
n ceeea ce privete gestionarea memoriei se folosesc cu succes funciile din C sau C++. Funciile din biblioteca
matematic, pentru gestionarea stringurilor, a bufferelor, a caracterelor, a conversiilor de date pot fi de asemenea
folosite.
Aplicaiile Win32 nu trebuie s foloseasc ntreruperea 21 sau funcii IBM PC BIOS.

Crearea unei aplicaii Windows


VC++ nu compileaz numai cod ci i genereaz cod. Pentru generarea unei aplicaii se folosete AppWizard.
n primul rnd aici se lucreaz cu proiecte. Un proiect poate conine mai multe aplicaii.
Pentru a crea un proiect vom folosi comenzile File->New->Projects. Din lista prezentat n pagina (tab-ul) Projects
vom selecta MFC AppWizard (EXE), selectm locul unde va fi memorat pe HDD i apoi completm numele
proiectului. Dup acest lucru va trebui s completm o serie de informaii grupate pe etape.

Etapa 1. Tip aplicaie


n etapa 1 (pas 1) vom selecta tipul aplicaiei (se alege interfaa cu utilizatorul). Avem urmtoarele posibiliti:

O aplicaie single document interface (SDI), are numai un document deschis la un moment dat. Cnd
selectm File->Open, fiierul existent i care este deschis va fi nchis nainte ca s se deschid noul
document.
O aplicaie multiple document interface (MDI), cum ar fi Excel sau Word, poate deschide mai multe
documente odat. Dac dorim vizualizri multiple pentru un document va trebui s construim o aplicaie
MDI.
O aplicaie dialog-based, cum ar fi utilitarul Character Map. Aplicaiile nu au meniu.

OBSERVAIE:: Aplicaiile bazate pe dialog sunt diferite de cele de tip SDI sau MDI.
Vor fi tratate n mod separat.
Mai exist un checkbox care ne d posibilitatea de a indica dac dorim suport pentru arhitectura Document/View.
Opiunea se folosete n special pentru portarea aplicaiilor dintr-un alt sistem de dezvoltare. Nu o vom folosi.

Etapa 2. Baze de date


n aceast etap vom alege nivelul pentru suportul bazelor de date.
Exist patru posibiliti:
Pentru aplicaii fr baze de date vom selecta None.

Dac dorim s avem acces la baze de date dar nu dorim s derivm vizualizarea din CFormView sau s nu
avem meniu Record vom selecta Header Files Only.
Dac dorim s derivm vizualizarea din CFormView i s avem meniul Record dar nu dorim s
serializm documentul, vom selecta Database View Without File Support.
Dac dorim suport pentru baze de date i n plus dorim i salvarea documentului vom selecta Database
View With File Support.

Dac selectm ultima opiune, va trebui s indicm sursa de date butonul Data Source.

Etapa 3. Suport pentru documente compuse


Tehnologia ActiveX i OLE este referit ca fiind tehnologia documentului compus (compound document
technology).
n aceast etap exist cinci posibiliti:
Dac nu scriem o aplicaie ActiveX, alegem None.

Dac dorim o aplicaie care s conin obiecte ActiveX nglobate sau legate, cum ar fi aplicaia Word,
alegem Container.
Dac dorim ca aplicaia noastr s furnizeze obiecte, care pot fi nglobate, pentru alte aplicaii, dar aplicaia
s nu poat fi executat separat (stand alone), vom alege Mini Server.
Dac dorim ca aplicaia noastr s furnizeze obiecte, care pot fi nglobate, pentru alte aplicaii, i aplicaia
s poat fi executat separat (stand alone), vom alege Full Server.
Dac dorim ca aplicaia s ncorporeze opiunile 3 i 4 vom selecta Both Container and Server.

Dac alegem suport pentru documentele compuse vom avea i suport pentru fiiere compuse (compound files).
Fiierele compuse conin unul sau mai multe obiecte ActiveX i sunt salvate ntr-un mod special astfel nct un
obiect poate fi modificat fr a rescrie ntregul fiier. Pentru acest lucru facem o selecie pe unul din butoanele radio
Yes, Please, sau No, Thank You.
Tot n aceast pagin ne hotrm dac aplicaia suport automatizare sau va folosi controale ActiveX.

OBSERVAIE: Dac dorim ca aplicaia s fie un control ActiveX, nu trebuie s crem o


aplicaie .exe obinuit. Crearea controlului ActiveX se face selectnd o alt opiune din
Projects.

Etapa 4. Opiuni pentru interfa. Alte Opiuni


Urmtoarele opiuni afecteaz modul de afiare al interfeei:
Docking Toolbar. AppWizard pregtete un toolbar. Acesta poate fi editat (adugare, modificare, tergere).
Initial Status Bar. AppWizard creaz o bar de stare care afieaz mesajele ataate comenzilor din meniu
sau alte mesaje specifice aplicaiei.

Printing and Print Preview. Aplicaia va avea opiunile Print i Print Preview din meniul File, i o parte
din codul necesar va fi generat de AppWizard.

Context-Sensitive Help. Meniul Help va avea opiunile Index i Using Help, i o parte din codul necesar
pentru a fi implementat Help va fi generat de AppWizard. Aceast decizie este dificil de luat mai trziu
pentru c pri din cod sunt generate n diverse locuri din cadrul aplicaiei.

3D Controls. Aplicaia va arta ca o aplicaie obinuit Windows 95. Dac nu selectm aceast opiune,
boxele de dialog vor avea background alb i nu vor fi umbre n jurul boxelor de editare, checkbox-urilor i
alte controale.

MAPI(Messaging API). Aplicaia va avea posibilitatea de trimite fax-uri, email-uri i alte mesaje.

Windows Sockets. Aplicaia va putea accesa Internet-ul n mod direct, folosind protocoale ca FTP i HTTP
(protocolul World Wide Web).
Putem seta de asemenea numrul fiierelor din lista MRU. Implicit acest numr este 4.
Butonul Advanced activeaz dou tab-uri (Document Template Strings, Window Styles) unde putem schimba
numele aplicaiei, titlul ferestrei cadru, extensia fiierelor folosite n File->Open, etc.
Prporpietile care pot fi setate pentru ferestrele cadru:
Thick Frame. Dac nu o selectm se previne redimensionarea.

Minimize Box.
Maximize Box.
System Menu.
Minimized. Cadrul este minimizat cnd aplicaia este lansat n execuie. Pentru aplicaiile SDI, aceast
opiune va fi ignorat cnd aplicaia ruleaz sub Windows 95.

Maximized. The frame is maximized when the application starts. For SDI applications, this option will be
ignored when the application is running under Windows 95.

Alte Opiuni
Dorim biblioteca MFC s fie legat ca un DLL partajabil sau n mod static? Un DLL este o colecie de funcii
utilizate de diferite aplicaii. Folosirea DLL-urilor face ca programul s fie mai mic dar mai greu de instalat. Dac
legtura este static crete mrimea programului dar nu mai sunt probleme deosebite cu instalarea.

Etapa 6. Numele fiierelor i al claselor


Ultima etap stabilete numele claselor i fiierelor create de AppWizard. Putem schimba aceste nume. Dac
aplicaia include o clas pentru vizualizare, care n mod obinuit este derivat din CView, putem schimba clasa de
baz, de exemplu CScollView sau CEditView care ofer o funcionalitate sporit vizualizrii.
Vom apsa butonul Finish pentru terminarea generrii aplicaiei.

Urmeaz exemple de creare aplicaii pentru fiecare tip n parte.

Crearea DLL-urilor, Aplicaiilor de tip Consol


Alte opiuni ce se regsesc n tab-ul Projects:
ATL COM AppWizard

Custom AppWizard
Database Project
DevStudio Add-In Wizard
Extended Stored Procedure AppWizard
ISAPI Extension Wizard
Makefile
MFC ActiveX ControlWizard
MFC AppWizard (dll)
Utility Project
Win32 Application
Win32 Console Application
Win32 Dynamic Link Library
Win32 Static Library

ATL COM AppWizard


ATL este Active Template Library, i este utilizat pentru a scrie un mic control AciteX.

Custom AppWizard
Se folosete n general pentru a crea noi proiecte din altele existente (se copie cod, help, etc.).

Database Project
Dac avem instalat Enterprise Edition of Visual C++, putem crea un proiect de baze de date.

DevStudio Add-In Wizard


Add-ins lucreaz exact ca macro-urile care automatizeaz Developer Studio, dar acestea sunt scrise n C++ sau alt
limbaj de programare; macro-urile sunt scrise n VBScript. Acestea folosesc automatizarea pentru a manipula
Developer Studio.

ISAPI Extension Wizard


ISAPI este pentru Internet Server API i se refer la funcii pe care le putem apela pentru a interaciona cu un server
Microsoft Internet Information Server.

Makefile
Dac dorim s crem un proiect care este utilizat cu un alt utilitar make diferit de Developer Studio, vom selecta
aceast opiune. Nu se genereaz cod.

MFC ActiveX ControlWizard


ActiveX controls sunt controale pe care lescriem pentru a fi utilizate ntr-un dialog din VC++, o form din VB sau
chiar o pagin Web. Aceste controale nlocuiesc controalele VBX.

MFC AppWizard (DLL)


Dac dorim s colectm un numr de funcii ntr-un DLL, i aceste funcii folosesc clase din MFC, vom selecta
aceast opiune. Dac funciile nu folosesc MFC alegem Win32 Dynamic Link Library.

Win32 Application
Se creaz o aplicaie obinuit n C++.

Win32 Console Application


O aplicaie consol arat ca o aplicaie obinuit DOS.

Win32 Dynamic Link Library


Dac dorim s colectm un numr de funcii ntr-un DLL, i aceste funcii folosesc clase din MFC, vom selecta
aceast opiune. Dac funciile nu folosesc MFC alegem Win32 Dynamic Link Library.

Win32 Static Library


Aplicaia va ncorpora funciile pe care folosete dintr-un DLL.

Bucla de mesaje ascuns


#include <windows.h>
int WINAPI WinMain(HINSTANCE d1, HINSTANCE d2, LPSTR d3, int d4)
{
MessageBox(NULL, "Hello, World!", "", MB_OK);
}
Bucla de mesaje i procedura fereastr sunt ascunse. MessageBox afieaz o box de dialog care conine
procedura fereastr i deoarece boxa de dialog este modal (nu poate fi prsit fr a se da clic pe ...) practic se
cicleaz pe bucla de mesaje.

Bucla de mesaje exist


Un program windows obinuit, n timpul iniializrii, nregistreaz mai nti clasa fereastr apoi creaz fereastra
principal utiliznd noua clas nregistrat. n exemplul ce urmeaz folosim deja clasa nregistrat, BUTTON.
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE d2, LPSTR d3, int d4)
{
MSG msg;
HWND hwnd;
hwnd = CreateWindow("BUTTON", "Hello, World!",
WS_VISIBLE | BS_CENTER, 100, 100, 100, 80,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_LBUTTONUP)
{

DestroyWindow(hwnd);
PostQuitMessage(0);
}
DispatchMessage(&msg);
}
return msg.wParam;
}
Explicaii: Dup ce se creeaz fereastra, programul intr n bucla while, unde se apeleaz GetMessage. Cnd
aplicaia primete un mesaj, GetMessage ntoarce acel mesaj; valoarea ntoars este FALSE numai dac mesajul
primit a fost WM_QUIT.
La tratarea mesajului WM_LBUTTONDOWN se distruge fereastra aplicaiei i apoi se pune n coda de mesaje,
mesajul WM_QUIT, pentru a se realiza terminarea buclei while.
Orice alt mesaj diferit de WM_LBUTTONDOWN nu este tratat de aplicaie, este preluat de DispatchMessage care
va apela procedura fereastr a clasei BUTTON. n marea majoritate a cazurilor procedura nu execut nimic special,
unul din rolurile ei fiind acela de a goli coada de mesaje a aplicaiei i de a respecta principiul n Windows nici un
mesaj nu se pierde.
n afar de GetMessage, mai existi funcia PeekMessage care se utilizeaz de obicei cnd aplicaia dorete s
execute anumite aciuni i nu are nici un mesaj de procesat.

Proceduri fereastr
#include <windows.h>
// ---------------- Apelata pe mesajul WM_PAINT
void DrawHello(HWND hwnd)
{
HDC hDC;
PAINTSTRUCT paintStruct;
RECT clientRect;
hDC = BeginPaint(hwnd, &paintStruct);
if (hDC != NULL)
{
GetClientRect(hwnd, &clientRect);
DPtoLP(hDC, (LPPOINT)&clientRect, 2);
DrawText(hDC, "Hello, World!", -1, &clientRect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint(hwnd, &paintStruct);
}
}
// --------------------------- Procedura fereastra
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_PAINT:
DrawHello(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0; // trebuie sa intoarca totdeauna 0 (zero)
}
// --------------- Programul principal
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR d3, int nCmdShow)
{
MSG msg;
HWND hwnd;
WNDCLASS wndClass;
if (hPrevInstance == NULL) // valabil numai pentru Windows 3.1
{
memset(&wndClass, 0, sizeof(wndClass));
// stiluri de fereastra
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc; // procedura fereastra
wndClass.hInstance = hInstance; // instanta aplicatiei
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // resursa cursor
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
// resursa penson
wndClass.lpszClassName = "HELLO"; // nume fereastra
// inregistrare fereastra
if (!RegisterClass(&wndClass)) return FALSE;
}
// terminat if
hwnd = CreateWindow("HELLO", "HELLO",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
DispatchMessage(&msg);
return msg.wParam;
}
Explicaii:
se creaz fereastra prin completarea structurii WNDCLASS;
se nregistreaz fereastra RegisterClass(&wndClass);
se creaz fereastra CreateWindow;
se stabileste modul de afiare al ferestrei ShowWindow(hwnd, nCmdShow);
se afieaz fereastra propriu zis UpdateWindow(hwnd);
urmeaz bucla de mesaje.
Codul ce trebuie urmrit este cel din WndProc, procedura fereastr.
Ce mesaje sunt tratate? Care sunt rspunsurile aplicaiei la aceste mesaje?
WndProc trateaz dou mesaje: WM_PAINT i WM_DESTROY. Alte mesaje dect cele indicate sunt tratate de
ctre DefWindowProc.
La mesajul WM_DESTROY se plaseaz n coada de mesaje, mesajul WM_QUIT care are ca efect terminarea
buclei de mesaje, i deci terminarea aplicaiei.

La mesajul WM_PAINT se apeleaz funcia DrawHello.


Dar cnd este trimis mesajul WM_PAINT i de cine?
Mesajul WM_PAINT este trimis prima dat de funcia UpdateWindow, adic atunci cnd fereastra devine vizibil
prima dat. ncercai opiunile Size i Move din meniul sistem. Ce se ntmpl? Trebuie reinut urmtorul lucru:
dac n coada de mesaje apar mai multe mesaje WM_PAINT, sistemul va trata numai ultimul mesaj. n fapt ultima
redesenare a ferestrei rmne vizibil, restul afirilor ar fi consumatoare de timp i n plus ar crea i un efect
neplcut datorat rdesenrilor succesive.
S explicm codul din DrawHello.
hDC = BeginPaint(hwnd, &paintStruct);
BeginPaint ncearc s completeze variabila paintStruct i ca rspuns obine un context de dispozitiv care
va trebui folosit de funciile din GDI. Ieirile grafice au nevoie de acest context de dispozitiv.
GetClientRect(hwnd, &clientRect);
Se obin dimensiunile zonei client, completate n clientRect. Observai parametrii funciei: hwnd va indica
pentru ce fereastr se dorete acest lucru.
DPtoLP(hDC, (LPPOINT)&clientRect, 2);
Coordonatele fizice sunt transformate n coordonate logice. Primul parametru, hDC, indic pentru ce context de
dispozitiv se face acest lucru.
DrawText(hDC, "Hello, World!", -1, &clientRect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
Se afieaz n zona client, Hello, World!, folosind contextul de dispozitiv obiunut de BeginPaint.
EndPaint(hwnd, &paintStruct);
Se termin desenarea, i se distrug informaiile din paintStruct.
La terminarea funciei, hDC se distruge, fiind local. n fapt dup EndPaint hDC-ul nu mai este valid.
Procedura fereastr nu este nimic altceva dect o structura mare switch.

Mai multe bucle de mesaje i proceduri fereastr


Aplicaiile pot avea cte bucle de mesaje doresc. De exemplu o aplicaie care are propria bucl de mesaje i
face apel la MessageBox va avea cel puin dou bucle de mesaje.
Pentru exemplificare vom considera cazul desenrii libere realizat cu o captur a mouse-lui. Aplicaia trebuie s fie
n stare s trateze mesajele WM_LBUTTONDOWN, WM_LBUTTONUP i WM_MOUSEMOVE pentru a realiza
aceast desenare. Vom avea tot timpul n minte faptul c un eveniment de mouse, n zona client, va genera un mesaj
care va fi nsoit de coordonatele punctului unde acesta a avut loc.
Logica aplicaiei este urmtoarea: bucla de mesaje va trata mesajul WM_LBUTTONDOWN. n cadrul funciei ce
trateaz acest mesaj se va realiza capturarea mouse-lui, astfel aplicaia este informat de orice micare a mouse-lui
prin tratarea mesajelor WM_MOUSEMOVE i WM_LBUTTONUP. Ieirea din cea de-a doua bucl de mesaje se

face la tratarea mesajului WM_LBUTTONUP, caz n care i capturarea mouse-lui nceteaz. De reinut c n cadrul
acestei a doua bucle de mesaje controlm mereu dac mouse-ul este capturat pentru zona client. Acest lucru
nseamn c dac facem clic stnga n afara zonei client i inem butonul stng al mouse-lui apsat i ne micam prin
zona client nu se va desena nimic. Mouse-ul nu a fost capturat de aceast fereastr.
Funcii noi n acest cod.
GetMessagePos() = obine coordonatele punctului unde se afl mouse-ul, coordonate relative la ecran.
Coordonatele sunt obinute ntr-un DWORD, care conine n primii doi octeti valoarea lui x, iar n ultimii doi octei
valoarea lui y. (Numrtoarea octeilor se face de la stnga la dreapta.)
Macro-ul MAKEPOINTS transform valoarea unui DWORD ntr-o structur de tip POINTS.
Cum zona client (fereastra) este plasat n cadrul ecranului, va trebui s translatm aceste coordonate n zona client.
ScreenToClient() = transform coordonate ecran n zona client.
DPtoLP() = transform coordonatele fizice de dispozitiv n coordonate logice, necesare pentru a desena n zona
client.
LineTo() = deseneaz un segment de la origine (sau punctul stabilit cu MoveTo, MoveToEx) pn la punctul curent.
GetCapture() = testeaz dac mouse-ul a fost capturat de fereastra aplicaiei.
SetCapture(HWND ) = realizeaz capturarea mouse-ului pentru fereastra cu handler-ul specificat
ReleaseCapture() = elibereaz capturarea mouse-ului.
GetDC() = obine un context de dispozitiv pentru a desena n fereastr (zona client).
ReleaseDC() = elibereaz contextul de dispozitiv obinut cu GetDC.
#include <windows.h>
void AddSegmentAtMessagePos(HDC hDC, HWND hwnd, BOOL bDraw)
{
DWORD dwPos;
POINTS points;
POINT point;
dwPos = GetMessagePos();
points = MAKEPOINTS(dwPos);
point.x = points.x;
point.y = points.y;
ScreenToClient(hwnd, &point);
DPtoLP(hDC, &point, 1);
if (bDraw) LineTo(hDC, point.x, point.y);
else MoveToEx(hDC, point.x, point.y, NULL);
}
void DrawHello(HWND hwnd)
{
HDC hDC;
MSG msg;
if (GetCapture() != NULL) return;
hDC = GetDC(hwnd);
if (hDC != NULL)
{
SetCapture(hwnd);
AddSegmentAtMessagePos(hDC, hwnd, FALSE);
while(GetMessage(&msg, NULL, 0, 0))
{
if (GetCapture() != hwnd) break;
switch (msg.message)
{
case WM_MOUSEMOVE:
AddSegmentAtMessagePos(hDC, hwnd, TRUE);
break;
case WM_LBUTTONUP:

goto ExitLoop;
default:
DispatchMessage(&msg);
}
}
ExitLoop:
ReleaseCapture();
ReleaseDC(hwnd, hDC);
}
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_LBUTTONDOWN:
DrawHello(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR d3, int nCmdShow)
{
MSG msg;
HWND hwnd;
WNDCLASS wndClass;
if (hPrevInstance == NULL)
{
memset(&wndClass, 0, sizeof(wndClass));
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.hInstance = hInstance;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndClass.lpszClassName = "HELLO";
if (!RegisterClass(&wndClass)) return FALSE;
}
hwnd = CreateWindow("HELLO", "HELLO",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
DispatchMessage(&msg);
return msg.wParam;
}

Observaie. Mesajul WM_MOUSEMOVE poate fi tratat i n bucla de mesaje din WinMain, dar pentru a realiza
aceeai funcionalitate codul i logica aplicaiei trebuiesc schimbate.

Concluzii

Fiecare aplicaie Windows este construit n jurul unei bucle de mesaje . O bucl de mesaje
face apeluri repetate la funciile GetMessage sau PeekMessage i regsete mesajele pe care le
dispecereaz procedurilor fereastr prin funcia DispatchMessage.
Procedurile fereastr sunt definite pentru clasele fereastr n momemntul cnd clasa fereastr a fost nregistrat
prin RegisterClass.
Mesajele adresate aplicaiei sunt tratate de procedura fereastr sau sunt trimise procedurii implicite
DefWindowProc sau DefDlgProc n situaia cnd nu sunt tratate de procedura fereastr.
Orice mesaj windows trebuie tratat, nu trebuie pierdut.
Mesajele pot fi plasate sau trimise unei aplicaii. Mesajele plasate sunt depozitate n coada de unde sunt regsite
cu GetMessage sau PeekMessage. Fa de un mesaj plasat, un mesaj trimis (SendMessage) implic
imediat un apel al procedurii fereastr. Cu alte cuvinte nu se termin execuia funciei SendMessage pn
cnd mesajul nu a fost tratat.
O aplicaie poate avea mai multe bucle de mesaje.

Citirea hrii de mesaje


Hrile de mesaje sunt pri ale modelului MFC de programare Windows. n loc de a scrie
funcia WinMain() care trimite mesaje la procedura fereastr (funcia) WindProc() i apoi s
controlm ce mesaj a fost trimis pentru a activa funcia corespunztoare, vom scrie doar funcia
care trateaz mesajul i vom aduga mesajul la harta de mesaje a clasei. Cadrul de lucru va face
operaiunile necesare pentru a ruta acest mesaj n mod corect.
Construirea hrii de mesaje
Hrile de mesaje se construiesc n dou etape. Declaraia hrtii de mesaje (macro
DECLARE_MESSAGE_MAP()) se face n fiierul .h al clasei, iar implementarea se face in
fiierul .cpp al clasei (BEGIN_MESSAGE_MAP() ... END_MESSAGE_MAP()).
Exemplu
//{{AFX_MSG(CShowStringApp)
afx_msg void OnAppAbout();
// NOTE - the ClassWizard will add and remove member
functions here.
// DO NOT EDIT what you see in these blocks of generated
code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
Se declar funcia OnAppAbout() care este prefixat cu afx_msg ce constituie un comentariu
pentru compilatorul de C++, dar care indic vizual c aceast funcie trateaz un mesaj. Aceast

funcie o vom gsi i n cadrul macro-ului BEGIN_MESSAGE_MAP(), ca un parametru al


macro-ului ON_COMMAND(). Primul parametru al acestui din urm macro este ID-ul
mesajului (comenzii n acest caz), iar al doilea numele funciei ce trateaz acest mesaj.
Cod in .cpp
BEGIN_MESSAGE_MAP(CShowStringApp, CWinApp)
//{{AFX_MSG_MAP(CShowStringApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping
macros here.
//
DO NOT EDIT what you see in these blocks of
generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
Macro-ul DECLARE_MESSAGE_MAP() adaug date mebru i funcii la clasa respectiv.
Practic se declar o tabel cu un numr de intrri variabil (sfritul tabelei este marcat
(completat) de END_MESSAGE_MAP()) i funcii care opereaz cu acest elementele acestui
tabel.
Macro-uri pentru harta de mesaje
BEGIN_MESSAGE_MAP i END_MESSAGE_MAP sunt macro-uri care ca i macro-ul
DECLARE_MESSAGE_MAP din fiierul .h, declar anumite variabile membru i funcii pe
care cadrul de lucru le va utiliza pentru a naviga prin hrile de mesaje ale tuturor obiectelor din
sistem Printre macro-urile folosite n hrile de mesaje, enumerm:
DECLARE_MESSAGE_MAPfolosit n fiierul .h pentru a declara c va exista o
hartesaje in .cpp
BEGIN_MESSAGE_MAPMarcheaz nceputul hrii de mesaje n fiierul surs.
END_MESSAGE_MAPMarcheaz sfritul hrii de mesaje n fiierul surs.
ON_COMMANDFolosit pentru a face legtura ntre comenzi i funciile care trateaz
aceste comenzi.
ON_COMMAND_RANGEFolosit pentru a face legtura ntre un grup de comenzi i
funcia care le trateaz.
ON_CONTROLFolosit pentru a face legtura ntre un mesaj de notificare al unui
control i funcia ce-l trateaz.
ON_CONTROL_RANGEFolosit pentru a face legtura ntre un grup de mesaje de
notificare al unui control i funcia corespunztoare.
ON_MESSAGEFolosit pentru a realiza legtura ntre un mesaj definit de utilizator i
funcia care-l trateaz.

ON_REGISTERED_MESSAGEFolosit pentru a realiza legtura ntre un mesaj defint


de utilizator, dar nregistrat i funcia care-l trateaz.
ON_UPDATE_COMMAND_UIFolosit pentru a indica funcia care va face
actualizarea pentru o comand specific.
ON_COMMAND_UPDATE_UI_RANGECa mai sus, dar pentru un grup de comenzi.
ON_NOTIFYFolosit pentru a indica funcia ce va aduga informaii suplimentare,
pentru un mesaj de notificare al unui control.
ON_NOTIFY_RANGECa mai sus, dar pentru un grup de mesaje de notificare al unui
control. ON_NOTIFY_EXCa la ON_NOTIFY, dar funcia va ntoarce TRUE sau
FALSE pentru a indica dac notificarea poate fi trecut altui obiect pentru tratri
suplimentare.
ON_NOTIFY_EX_RANGECa mai sus, dar se refer la un grup de comenzi de
notificare.

n plus la ceste macro-uri, exist peste 100 de macro-uri, unul pentru fiecare din cele mai
comune mesaje. De exemplu macro-ul ON_CREATE pentru mesajul WM_CREATE, etc. n mod
obinuit aceste macro-uri sunt adugate la clas de ctre Class Wizard.
Cum lucreaz harta de mesaje
Fiecare aplicaie are un obiect motenit din clasa CWinApp i o funcie membru Run().
Aceast funcie apeleaz funcia CWinThread::Run(), care apeleaz GetMessage(),
TranslateMessage() i DispatchMessage().
Funcia fereastr (n SDK) tie handler-ul ferestrei pentru care este trimis mesajul. Fiecare obiect
fereastr folosete acelai stil al clasei Windows i aceeai funcie WindProc, numit
AfxWndProc(). MFC menine ceva asemntor, numit handle map, o tabel cu handler-ii
ferestrelor i pointeri la obiecte, i framework-ul folosete aceasta pentru a trimite un pointer la
obiectul C++, un CWnd*. n continuare el apeleaz WindowProc(), o funcie virtual a
acestui obiect. Datorit polimorfismului, indiferent c este vorba de un Button sau o vizualizare
se va apela funcia corect.
WindowProc() apeleaz OnCmdMsg(), funcia C++ care efectiv manipuleaz mesajul.
Mai nti caut dac acesta este un mesaj, o comand sau o notificare. Presupunnd c este un
mesaj. caut n harta de mesage a clasei, folosind funciile i variabilele membru adugate la
clas de DECLARE_MESSAGE_MAP, BEGIN_MESSAGE_MAP i END_MESSAGE_MAP.
Modul de organizare al acestei tabele permite cutarea mesajului, dac este nevoie, n toat
arborescena clasei.
AfxWndProc()->WindowProc()->OnCmdMsg()
Se va explica cum se adaug un mesaj la o clas i funcia corespunztoare acestuia, care clas
trateaz mesajul, cum se scrie cod n funcie, etc.
Recunoaterea mesajelor
Exist aproximativ 900 mesaje Windows.

Prefixele mesajului Windows i Tipuri fereastr


Prefix
ABM, ABN
ACM, ACN
BM, BN
CB, CBN
CDM, CDN
CPL
DBT
DL
DM
EM, EN
FM, FMEVENT
HDM, HDN
HKM
IMC, IMN
LB, LBN
LVM, LVN
NM
PBM
PBT
PSM, PSN
SB
SBM
STM, STN
TB, TBN
TBM
TCM, TCN
TTM, TTN
TVM, TVN
UDM
WM

Window Type
Appbar
Animation control
Button
Combo box
Common dialog box
Control Panel application
Any application (device change message)
Drag list box
Dialog box
Edit box
File Manager
Header control
HotKey control
IME window
List box
List view
Any parent window (notification message)
Progress bar
Any application (battery power broadcast)
Property sheet
Status bar
Scrollbar
Static control
Toolbar
Track bar
Tab control
ToolTip
Tree view
Up Down control
Generic window

Care e diferena ntre mesajele care se termin n M i cele care se termin n N? Primul este un
mesaj la control (am apsat butonul, de exemplu), al doilea este un mesaj de notificare de la
control la fereastra proprietar a controlului, care are semnificaia de am fost apsat, s-a
ntmplat ceva n control....
Exist i mesaje care nu se termin n M (CB_) dar acioneaz la fel.
nelegerea comenzilor
O comand este un tip special de mesaj. Windows genereaz comenzi cnd utilizatorul
alege un articol de meniu, apas un buton, sau altfel spune sistemului s fac ceva. Pentru un

articol de meniu se primete mesajul WM_COMMAND iar pentru notificarea unui control
WM_NOTIFY, cum ar fi selectarea dintr-un list box.
Comenzile i notificrile sunt trecute prin SO ca orice alt mesaj, pn cnd acestea ajung
la OnWndMsg(). n acest punct pasarea mesajului windows nceteaz i se starteaz rutarea
comenzilor n MFC.
Mesajele de comand au ca prim parametru, ID-ul articolului din meniu care a fost selectat sau a butonului care a
fost apsat.

Rutarea comenzilor este mecanismul pe care OnWndMsg() l folosete pentru a trimite comanda
(sau notificarea) la obiectele care pot trata acest mesaj. Numai obiectele care sunt motenite
din CWnd pot primi mesaje, dar toate obiectele care sunt motenite din CCmdTarget,
incluznd CWnd i CDocument, pot primi comenzi sau notificri. Aceasta nseman c o
clas motenit din CDocument poate avea o hart de mesaje. Pot s nu existe mesaje n
aceast hart ci numai pentru comenzi i notificri, dar tot hart de mesaje se numete.
Comenzile i notificrile ajung la clas prin mecanismul de rutare al comenzilor.
OnWndMsg() apeleaz CWnd::OnCommand() sau CWnd::OnNotify().
OnCommand() apeleaz OnCmdMsg(). OnNotify() apeleaz de asemenea
OnCmdMsg(). Bineneles c ambele funcii efectueaz anumite controale nainte de a face
aceste apeluri.
OnCmdMsg() este virtual, ceea ce nseamn c diferite comenzi au implementri diferite.
Implementarea pentru fereastra cadru trimite comanda vizualizrilor i documentelor pe care le
conine.
Comanda pentru actualizri
Folosit n special pentru actualizarea articolelor din meniu. De exemplu cnd se
selecteaz text in vizualizare i opiunile de Copy, Cut, Paste, Undo sunt implementate aceste
articole de menu vor fi afiate n starea enable sau disable (funcie de logica programului).
Exist dou posibiliti de a face acest lucru: continuous update approach i update-on-demand
approach.
Continuous update approach presupune existena unei tabele mari ce conine cte o intrare
pentru fiecare meniu i un flag care va indica dac opiunea este disponibil sau nu.
Cea de-a doua posibilitate presupune controlarea tuturor condiiilor asupra unui articol de meniu
nainte ca meniul s fie afiat. n acest caz obiectul care are meniul va ti mai multe despre
acesta, n schimb nu toat aplicaia va avea acces la aceste informaii.
Tehinca MFC-ului este de a utiliza un obiect numit CCmdUI, o comand a interfeei
utilizatorului, i de a da acest obiect cnd se trimite mesajul CN_UPDATE_COMMAND_UI. n
harta de mesaje va aprea macro-ul ON_UPDATE_COMMAND_UI.
Ce se ntmpl in realitate?
SO trimite mesajul WM_INITMENUPOPUP; clasa CFrameWnd va construi un obiect
CCmdUI, seteaz variabilele membru ce corespund primului articol din meniu i apeleaz funcia
membru DoUpdate(). DoUpdate() trimite mesajul CN_COMMAND_UPDATE_UI la ea

nsi, cu un pointer la obiectul CCmdUI. Se vor seta variabilele membru ale obiectului CCmdUI
cu articolul doi din meniu i procesul continu pn cnd este parcurs tot meniul. Obiectul
CCmdUI este folosit pentru a valida (enable) sau invalida (disable) [gray(disable) sau
ungray(enable) ] articolele din meniu sau butoane.
CCmdUI are urmtoarele funcii membru:
Enable() Are un parametru care poate lua valorile TRUE sau FALSE (implicit
TRUE).
SetCheck() Marcheaz sau demarcheaz articolul.
SetRadio() Seteaz sau nu unul din butoanele radio al unui grup.
SetText()Seteaz textul unui meniu sau buton.
DoUpdate()Genereaz mesajul.
Exemplu:
BEGIN_MESSAGE_MAP(CWhoisView, CFormView)
...
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
...
END_MESSAGE_MAP()
void CWhoisView::OnUpdateEditPaste(CCmdUI* pCmdUI)
{
pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
}

Tiprire i Previzualizare
Bazele tipririi i previzualizrii n MFC
Cerine pentru acest curs:

Contextul de dispozitiv;
Arhitectura Document/View, aplicaii tip SDI;
Tratarea mesajelor simple de mouse;
defilarea orizontal i/sau vertical (opional).

Obiective:
determinarea obiectelor folosite de ctre MFC pentru tiprire i previzualizare;

determinarea ordinii de apel al funciilor implicate n tiprire i previzualizare;


determinarea elementelor ce identific pagina de tiprit, etc.
Lecia se va desfura n laborator. Drept exerciiu independent: s se adauge codul necesar pentru a realiza
defilarea orizontal i/sau vertical.
Pentru nvarea manevrrii contextului de dispozitiv se poate propune construirea unei aplicaii care s
deseneze graficul unei funcii. Se vor avea n vedere toate situaiile posibile unde poate fi desenat graficul funciei
astfel nct s fie ocupat ct mai bine zona client (pentru un grafic ce apare numai n cadranul IV se va desena
numai acest cadran i graficul, etc.).
Vom exemplifica tiprirea i vizualizarea pe baza unui exemplu.
Se creaz o aplicaie cu arhitectura Document/View i tip SDI (restul setrilor rmnnd cele implicite) i cu
suport pentru print/preview.
Numele proiectului este Print1.
Prima modificare.
n funcia CPrint1View::OnDraw() adugm:
pDC->Rectangle(20, 20, 220, 220);
Se va desena un dreptunghi (cu mrimile msurate n pixeli). (20,20) reprezint colul din stnga sus al
dreptunghiului, iar (220,220) reprezint colul din dreapta jos al dreptunghiului. Deci mrimea laturilor
dreptunghiului este 200 pe 200 pixeli.
Colul din stnga sus al zonei client are coordonatele (0,0), axa Ox este pe orizontal, axa Oy este pe vertical.
Aceast aplicaie poate produce vizualizarea i tiprirea documentului.

Scalarea
Documentul listat i cel afiat pe ecran nu are aceeai dimensiune (nu arat la fel) pentru c imprimanta folosete
unitatea de msur, dots, iar pe ecran se folosete pixelul, i acestea au mrimi diferite (200 dots # 200 pixeli).
Acest lucru este descris de modul de mapare (implicit MM_TEXT).
Dac dorim s scalm imaginea tiprit la o anumit dimensiune, trebuie s alegem diferite moduri de mapare.

Moduri de mapare
Mode
MM_HIENGLISH
MM_HIMETRIC
MM_ISOTROPIC
MM_LOENGLISH
MM_LOMETRIC
MM_TEXT
MM_TWIPS

Unit
0.001 inch
0.01 millimeter
User-defined
0.01 inch
0.1 millimeter
Device pixel
1/1440 inch

X
Increases right
Increases right
User-defined
Increases right
Increases right
Increases right
Increases right

Y
Increases up
Increases up
User-defined
Increases up
Increases up
Increases down
Increases up

Lucrul cu grafice n modul MM_TEXT devine o problem cnd imprimantele i ecranele au un numr diferit de
dots/pixeli pe pagin.
Un mod de mapare mai bun pentru lucrul cu grafice este MM_LOENGLISH, care folosete ca unitate de msur a
suta parte dintr-un inch. Pentru a folosi acest mod de mapare, folosim funcia SetMapMode():
pDC->SetMapMode(MM_LOENGLISH);
pDC->Rectangle(20, -20, 220, -220);

Atentie la originea axelor i la sensul acestora (creterea luix i a lui y) Cnd vom tipri documentul de mai sus vom
obine un dreptunghi cu laturile exact de 2 inch.

Tiprirea mai multor pagini


MFC trateaz tiprirea documentului (mai puin bitmap-uri). Funcia OnDraw() din clasa pentru vizualizare
realizeaz desenarea pe ecran ct i tiprirea la imprimant. Lucrurile se complic cnd documentul are mai multe
pagini sau alte tratri speciale (informaii de nceput i de sfrit de pagin).
Exemplificare:
Vom modifica aplicaia astfel nct s desenm mai multe dreptunghiuri care s nu ncap pe o pagin.
Adugm o variabil membru (int m_numrects) la clasa document care va memora numrul de dreptunghiuri
care se vor desena i pe care o iniializm n constructor.
Pe mesajul WM_LBUTTONDOWN vom incrementa aceast variabil, iar pe mesajul WM_RBUTTONDOWN
vom decrementa aceast variabil. Codul pentru cele dou funcii este dat mai jos:

print1View.cpp --CPrint1View::OnLButtonDown()
void CPrint1View::OnLButtonDown(UINT nFlags, CPoint point)
{
CPrint1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->m_numRects++;
Invalidate();
CView::OnLButtonDown(nFlags, point);
}

print1View.cpp --CPrint1View::OnRButtonDown()
void CPrint1View::OnRButtonDown(UINT nFlags, CPoint point)
{
CPrint1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (pDoc->m_numRects > 0)
{
pDoc->m_numRects--;
Invalidate();
}
CView::OnRButtonDown(nFlags, point);
}

Rescriem funcia OnDraw() astfel:


print1View.cpp --CPrint1View::OnDraw()
void CPrint1View::OnDraw(CDC* pDC)
{
CPrint1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->SetMapMode(MM_LOENGLISH);
char s[10];
wsprintf(s, "%d", pDoc->m_numRects);
pDC->TextOut(300, -100, s);
for (int x=0; x<pDoc->m_numRects; ++x)
{
pDC->Rectangle(20, -(20+x*200),

200, -(200+x*200));

}
Vedem ce se ntmpl n PrintPreview. Codul din PrintPreview (n acest moment) nu tie cum s afieze mai multe
pagini.
Determinarea numrului de pagini se face n funcia OnBeginPrinting().

print1View.cpp --CPrint1View::OnBeginPrinting()
void CPrint1View::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
CPrint1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
int pageHeight = pDC->GetDeviceCaps(VERTRES);
int logPixelsY = pDC->GetDeviceCaps(LOGPIXELSY);
int rectHeight = (int)(2.2 * logPixelsY);
int numPages = pDoc->m_numRects * rectHeight / pageHeight + 1;
pInfo->SetMaxPage(numPages);
}
OnBeginPrinting() are doi parametri: un pointer la un context de dispoztiv al imprmantei i un pointer la un
obiect CPrintInfo. Pentru c versiunea implicit nu se refer la aceti doi pointeri, numele parametrilor sunt
comentai pentru a preveni mesajele de avertizare la compilare.
void CPrint1View::OnBeginPrinting(CDC* /*pDC*/ , CPrintInfo* /*pInfo*/)
Pentru a seta numrul paginii, trebuie s accesm ambele obiecte CDC* i CPrintInfo, deci va trebui s scoatem
comentariile de la ceti doi parametri.
Trebuie s avem urmtoarele informaii:
1. nlimea paginii;
2. numrul de dots pe inch.
nlimea paginii o obinem printr-un apel al funciei GetDviceCaps(), care furnizeaz informaii despre
posibilitile contextului de dispozitiv. Avem nevoie de rezoluia vertical (numrul de dots tipribili de la nceputul
paginii pn la sfritul ei), deci vom furniza ca parametru constanta VERTRES, n funcia GetDeviceCaps().
Constanta HORZRES n aceeai funcie ne furnizeaz rezoluia orizontal.
GetDeviceCaps() accept un numr de 29 de constante diferite (a se vedea help-ul).
n exemplul nostru, pentru a ti cte dreptunghiuri ncap pe o pagin, trebuie s tim nlimea dreptunghiului n
dots, deci va trebui s mprim dots pe pagin la dots pe dreptunghi.
tim c fiecare dreptunghi este nalt de 2 inch cu un spaiu de 20/100 ntre fiecare dreptunghi. Distana total de la
nceputul desenrii unui dreptunghi pn la urmtorul este de 2.2 inch.
Apelul GetDeviceCaps(LOGPIXELSY) ne d numrul de dots pe inch pentru imprimant (care este ataat la
sistem)., care nmulit cu 2.2 ne d dots pe dreptunghi.
Rulnd aplicaia vom observa c dei n previzualizare avem dou pagini, la listare vom obine pagina 1 de dou ori.
Trecerea de la o pagin la alta este urmtorul pas.

Setarea originii
Va trebui s furnizm informaia privitoare la nceputul unei noi pagini. Pentru acest lucru, vom rescrie funcia
OnPrepareDC().
Adugm aceaceast funcie la clasa de vizualizare cu ClassWizard. Codul este:

print1View.cpp --CPrint1View::OnPrepareDC()
void CPrint1View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
if (pDC->IsPrinting())
{
int pageHeight = pDC->GetDeviceCaps(VERTRES);
int originY = pageHeight * (pInfo->m_nCurPage - 1);
pDC->SetViewportOrg(0, -originY);
}
CView::OnPrepareDC(pDC, pInfo);
}
Cadrul de lucru MFC, apeleaz aceast funcie nainte de afia datele pe ecran sau a le scrie la imprimant. Acelai
cod realizeaz previzualizarea ct i tiprirea datelor. Dac aplicaia previzualizeaz datele nu este nevoie s
schimbm procesarea efectuat de OnPrepareDC(). Cod necesar este numai pentru tiprire, de aceea folosim
funcia IsPrinting() pentru a determina dac aciunea este de tiprire sau nu.
Dac tiprim documentul, trebuie s determinm care pagin trebuie tiprit, adic s stabilim pagina curent.
Pentru aceasta avem nevoie de nlimea n dots a paginii de tiprit, deci un nou apel al funciei GetDeviceCaps().
n continuare trebuie s detrerminm originea noului viewport (poziia coordonatelor (0,0)) pentru afiare.
Schimbnd originea, dm informaia necesar cadrului de lucru MFC, pentru a ti de unde s nceap tiprirea
datelor.
Pentru prima pagin originea este (0,0); pentru pagina a doua, originea este mutat n jos cu numrul de dots pe
pagin. n general, componenta vertical este mrimea paginii nmulit cu pagina curent minus 1. Numrul
paginii este meninut ntr-o variabil membru a clasei CPrintInfo.
Dup ce calculm noua origine, vom seta aceasta n cadrul contextului de dispozitiv apelnd funcia
SetViewportOrg().
Se va rula aplicaia cu aceste ultime modificri efectuate.

MFC i Tiprirea
Alte funcii importante n procesul de tiprire sunt:

Printing Functions of a View Class


Function
OnBeginPrinting()
OnDraw()
OnEndPrinting()
OnPrepareDC()
OnPreparePrinting()
OnPrint()

Description
Override this function to create resources, such as fonts, that you need for printing the
document. You also set the maximum page count here.
This function serves triple duty, displaying data in a frame window, a print preview window,
or on the printer, depending on the device context sent as the function's parameter.
Override this function to release resources created in OnBeginPrinting().
Override this function to modify the device context used to display or print the document.
You can, for example, handle pagination here.
Override this function to provide a maximum page count for the document. If you don't set
the page count here, you should set it in OnBeginPrinting().
Override this function to provide additional printing services, such as printing headers and
footers, not provided in OnDraw().

Pentru a tipri documentul se apeleaz mai nti OnPreparePrinting() care apeleaz


DoPreparePrinting() care la rndul ei este responsabil pentru afiarea boxei de dialog Print i creaz
contextul de dispozitiv pentru imprimanta selectat.

print1View.cpp --CPrint1View::OnPreparePrinting() as Generated by AppWizard


BOOL CPrint1View::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);

}
Folosind pointerul la obiectul CPrintInfo, putem face aici diverse iniializri. Trebuie cercetat clasa CPrintInfo.

Members of the CPrintInfo Class


Member
SetMaxPage()
SetMinPage()
GetFromPage()
GetMaxPage()
GetMinPage()
GetToPage()
m_bContinuePrinting
m_bDirect
m_bPreview
m_nCurPage
m_nNumPreviewPages
m_pPD
m_rectDraw
m_strPageDesc

Description
Sets the document's maximum page number.
Sets the document's minimum page number.
Gets the number of the first page that users selected for printing.
Gets the document's maximum page number, which may be changed in
OnBeginPrinting().
Gets the document's minimum page number, which may be changed in
OnBeginPrinting().
Gets the number of the last page users selected for printing.
Controls the printing process. Setting the flag to FALSE ends the print job.
Indicates whether the document is being directly printed.
Indicates whether the document is in print preview.
Holds the current number of the page being printed.
Holds the number of pages (1 or 2) being displayed in print preview.
Holds a pointer to the print job's CPrintDialog object.
Holds a rectangle that defines the usable area for the current page.
Holds a page-number format string.

Cnd funcia DoPreparePrinting() afieaz boxa de dialog Print, utilizatorul poate seta o parte din datele membru ale
clasei CPrintInfo. n mod obinuit, ultimul apel trebuie fcut pentru SetMaxPage() nainte ca DoPreparePrinting() s
afieze boxa de dialog Print. Dac nu putem determina numrul de pagini pn cnd nu avem un DC pentru
imprimanta selectat, trebuie s ateptm pn cnd obinem acest context de dispozitiv. n mod normal contextul de
dispozitiv al imprimantei se creaz la selecia acesteia n cadrul acestei boxe de dialog.
Dup OnPreparePrinting(CDC*, CPrintInfo*), MFC apeleaz OnBeginPrinting(), care este un alt loc potrivit pentru
a seta numrul maxim de pagini, dar i locul pentru a crea resurse, cum ar fi fonturi, necesare pentru a completa jobul de tiprire.
n continuare, MFC apeleaz OnPrepareDC() pentru prima pagin a documentului. Aceasta constituie nceputul
buclei care se execut o dat pentru fiecare pagin a documentului. In OnPrepareDC() putem controla care parte din
ntreg documentul se tiprete, ca fiind pagina curent. Aici vom seta originea viewportului pentru document.
Dup OnPrepareDC(), MFC apeleaz OnPrint() pentru a tipri pagina curent. n mod normal, OnPrint() apeleaz
OnDraw() cu un parametru pointer la CDC, care automat redirecteaz ieirea spre imprimant. Putem rescrie
OnPrint() pentru a controla modul cum documentul este tiprit. Putem tipri headers i footers n OnPrint() i apoi s
apelm versiunea de baz a lui OnDraw() pentru a tipri pagina curent. Pentru a preveni vesriunea din clasa de baz
ca s nu rescrie headers i footers, restricionm zona tipribil prin setarea variabilei m_rectDraw din obiectul
CPrintInfo la un dreptunghi care nu acopr headers i footers.

Versiune posibil OnPrint() cu Headers i Footers


void CPrint1View::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
// Call local functions to print a header and footer.
PrintHeader();
PrintFooter();
CView::OnPrint(pDC, pInfo);
}
Se poate renuna la apelul lui OnDraw() n OnPrint(), creind cod suplimentar, ca n exemplul de mai jos.

Versiune posibil OnPrint() fr OnDraw()


void CPrint1View::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
// Call local functions to print a header and footer.
PrintHeader();
PrintFooter();
// Call a local function to print the body of the document.
PrintDocument();
}
Dup ce MFC a terminat de tiprit ultima pagin, apeleaz funcia OnEndPrinting(), unde putem distruge orice
resurs de care nu mai avem nevoie.

Meniuri
Se vor descrie mai intai elementele aplicatiei (bara de titlu, meniul, etc.).
W furnizeaza suport aplicatiilor care utilizeaza meniuri: afisarea barei de meniu, derularea unui meniu popup cind
acesta este selectat, notifica aplicatia cind o comanda de meniu a fost selectata.

Definire termeni:
Bara de meniu care apare in partea cea mai de sus a ferestrei se numeste top-level menu, iar
comenzile se numesc top-level menu items. Meniul care apare cind un articol de meniu este
selectat se numeste drop down menu, iar articolele din acest meniu se numesc articole meniu
(menu items). Articolele de meniu sunt identificate prin valori intregi, numite ID-ul art. de meniu
sau ID-ul comenzii. W suporta meniurile popup care sunt asemanatoare cu cele drop down cu
deosebirea ca pot fi afisate oriunde pe ecran. Meniurile de context (right click) sunt meniuri
popup.
Meniul sistem cuprinde czi pt. redimensionare, mutare, minimizare, maximizare, inchidere
fereastra.
Act. legate de meniuri le gasim in clasa CMenu din MFC. CMenu contine o data membru
publica HMENU m_hMenu ce pastreaza un handle la meniu, si mai multe functii ce constituie
in fapt apeluri ale fct din API (CMenu::TrackPopupMenu, CMenu::EnableMenu, etc. CMenu
contine doua fct virt DrawItem si MeasureItem care pot fi rescrise daca dorim sa cream articole
de meniu stilizate ce contin bitmap-uri si alte elemente grafice.
Crearea unui meniu in MFC. Modalitati:
1. in mod programabil, CreateMenu, InsertMenu, etc;
2. initializind o serie de structuri de date ce descriu continutul unui meniu si apoi apelam
CMenu::LoadMenuIndirect;
3. cream o resursa de meniu si incarcam meniul rezultat in aplicatie in timpul executiei.

Crearea unui meniu


Metoda cea mai usoara este de a adauga un template de meniu la fis. de resurse al aplicatiei. Un fisier de resurse
este un fis. text care are ext rc, si care instructiuni ce definesc meniul. Acest fis. de res este compilat si legat la
aplicatie cu un utilitar numit rc.exe (in MS VC++). O resursa este un obiect binar ca de ex. un meniu, o icoana,
stringuri, bitmap-uri. Fiecare resursa este identificata printr-un ID intreg sau string (MyMenu sau
IDR_MYMENU). ID-urile sunt definite cu #define. O data ce o resursa este compilata si legata la o aplicatie ea
poate fi incarcata printr-un simplu apel de functie. Un fis de resurse contine: ID resusrsa, numele art de meniu, IDurile art de meniu, atribute ale meniului.

IDR_MAINFRAME MENU PRELOAD DISCARDABLE


BEGIN
POPUP &File
BEGIN
MENUITEM &New\tCtrl+N,
ID_FILE_NEW
...
MENUITEM SEPARATOR
END
POPUP &View
BEGIN
...
END
END
Indicatii:
O elipsa in descrierea meniului inseamna ca sunt necesare inf suplimentare dupa ce art este
selectat, ! inseamna ca se executa imediat o comanda (Exit!).
Afxres.h defineste valorile ID-urile pt. comenzile uzuale. Valori valide pt. ID-uri in intervalul 10xEFFF sau mai exact 0x8000 0xF000 cf. Nota Teh. 20 din MFC.
Textul ce urmeaza car. TAB \t identifica un accelerator. Un accelerator este o tasta sau o
combinatie de taste (Ctrl+C, Ctrl+V, etc.) care cind sunt apasate au acelasi efect ca selectarea art
din meniu.
Cind definim art de meniu, putem sa-i indicam starea initiala, de ex GRAYED, ceea ce-l face
disable, CHECKED.

Incarcarea si afisarea unui meniu


In timpul exec. o res. de meniu tr. incarcata si atasata la fereastra. Cind fer este afisata, meniul va
fi afisat de asemenea.
Metoda 1: apel la fct CFrameWnd::Create
Create(NULL,
_T(Nume
aplicatie),
MAKEINTRESOURCE(IDR_MAINFRAME));

WS_OVERLAPPEDWINDOW,

rectDefault,

NULL,

Param. 6 indica resursa de meniu. MAKEINTRESOURCE transforma un intreg intr-o data de


tip LPSTR.

Metoda 2: apel la fct CFrameWnd::LoadFrame, care creaza o fereastra cadru si ataseaza un


meniu la ac.
LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW, NULL, NULL);
LoadFrame este asemenatoare cu Create, dar poate incarca si icoane si alte resurse ceea ce nu
face Create (in spate este CreateWindow , CreateWindowEx).
Metoda 3: construim un ob de tip meniu, clasa CMenu, si-l incarcam CMenu::LoadMenu si apoi
il atasam la fer. CWnd::SetMenu:
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();
CMenu::Detach() va detasa meniul din ob CMenu a.i. meniul nu va fi distrus prematur cind on
menu va fi distrus.
Regula gen. Un meniu incarcat cu LoadMenu ar trebui sa fie distrus cu DestroyMenu
inainte ca aplicatia sa se termine.
Metoda 3 este folosita in programe care au mai mult de un meniu. Ex. de aplicatie cu doua
meniuri:
Create(NULL, _T(aplicatie));
m_menuLong.LoadMenu(IDR_LONGMENU);
m_menuShort.LoadMenu(IDR_SHORTMENU);
SetMenu(m_bShortMenu ? &m_menuShort, &m_menuLong);
Comutarea intre cele doua meniuri se face astfel (ca raspuns la o comanda a utilizatorului) de la
meniul lung la cel scurt:
m_bShortMenu = TRUE;
SetMenu(&m_menuShort);
DrawMenuBar();
de la m.s la m.l
m_bShortMenu = FALSE;
SetMenu(&m_menuLong);
DrawMenuBar();
Fct. CWnd::DrawMenuBar() redeseneaza bara meniu pt. a reflecta schimbarile facute in meniu. Daca
m_menuLong si m_menuShort sunt var. membru ale clasei fereastra cadru (derivata din CWnd), destructorii pt.
meniuri se vor apela cind fer. cadru va fi distrusa, deci in acest caz nu mai e nevoie de DestroyMenu.

Raspunsul la comenzile meniului


Cind utilizatorul selecteaza un art. de meniu (bara de meniuri) fer primeste o serie de mesaje:
WM_INITMENU ce notifica fer ca un articol al meniului superior (top-level menu item) a fost
selectat. Inainte ca meniul sa fie afisat fer primeste mesajul WM_INITMENUPOPUP, locul unde
ar putea fi actualizate (enable, disable, checked, etc.) articolele meniului, meniul inca nu este
afisat. Cind parcurgem art. unui meniu drop down (popup), fer primeste mesajul
WM_MENUSELECT, mesaj ce poate fi tratat, in special in SDK, prin afisarea unui text in bara
de stare (scurt help). Dar cel mai important mesaj este WM_COMMAND trimis cind util.
selecteaza un art de meniu.
Cuv inferior al param. wParam pastreaza ID-ul comenzii (art. din meniul popup) si in SDK se face practic switch
pe LOWORD(wParam) pentru a identifica care comanda a fost selectata. In MFC se adauga in harta de mesaje a
clasei respective macroul ON_COMMAND care trateaza mesajul WM_COMMAND. ON_COMMAND are doi
parametri, primul indica ID_ul comenzii, iar al doilea indica handlerul comenzii (functia ce va fi apelata la selectia
acestei comenzi). Ex.

ON_COMMAND(ID_FILE_SAVE, OnFileSave);
Functiile ce trateaza comenzile de meniu nu au parametri si nu intorc nimic.

Intervale pentru comenzi


Sunt folosite pentru a trata un grup de art. meniu cu o singura functie. Functia va avea codul necesar pentru a
identifica corect care comanda a fost selectata. De exemplu tratam culorile penitei si construim un meniu cu
comenzile: Rosu, Verde, Albastru. Pentru a manevra mai usor interfata, comenzile acestui meniu vor fi inserate in
harta de mesaje a clasei derivate din CView. Pp. ID-urile sunt: IDM_ROSU, IDM_VERDE, IDM_ALBASTRU iar
fct. corespunzatoare OnRosu, OnVerde, OnAlbastru, iar culoarea o pastram intr-un int, m_nCuloare, cu valorile
respective 0,1,2.

In harta de mesaje vom avea:


ON_COMMAND(IDM_ROSU, OnRosu);
ON_COMMAND(IDM_VERDE, OnVerde);
ON_COMMAND(IDM_ALBASTRU, OnAlbastru);
iar fctiile vor fi:
void CXView::OnRosu()
{ m_nCuloare = 0;}
void CXView::OnVerde()
{ m_nCuloare = 1;}
void CXView::OnAlbastru()
{ m_nCuloare = 2;}
Daca am avea mai multe culori? Cum procedam?
Grupam aceste comenzi si vom extrage ID-ul comenzii cu CWnd:;GetCurrentMessage, iar harta
de mesaje va fi:
ON_COMMAND(IDM_ROSU, OnCuloare);

ON_COMMAND(IDM_VERDE, OnCuloare);
ON_COMMAND(IDM_ALBASTRU, OnCuloare);
void CXView::OnCuloare()
{
UNIT nID = (UINT) LOWORD(GetCurrentMessage()->wParam);
m_nCuloare = nID IDM_ROSU;
}
Indecsii meniului incep cu 0 (zero). Dar harta de mesaje este inca prea mare. Vom folosi macroul
ON_COMMAND_RANGE care trateaza o serie de comenzi care au ID-uri contigue (secventiale):

ON_COMMAND_RANGE(IDM_ROSU, IDM_ALBASTRU, OnCuloare);

Actualizarea art intr-un meniu


Metoda 1: actualizare in momentul cind art este selectat
void CXView::OnCuloare()
{
CMenu*
pMenu = GetMenu();
pMenu->CheckMenuItem(m_nCuloare + IDM_ROSU, MF_UNCHECKED);
pMenu->CheckMenuItem(nID, MF_CHECKED);
m_nCuloare = nID IDM_ROSU;
}
Metoda 2: mutam codul care actualizeaza meniul in tratarea mesajului WM_INITMENUPOPUP
iar fct este OnInitMenuPopup. Aici actualizarea se face inainte ca meniul sa fie afisat. Aceasta
functie are trei parametri: un pointer de tip CMenu ce pointeaza la submeniul care va fi afisat,
un UINT valoare ce da indexul art din submeniu si o var. BOOL care este # 0 daca mesajul este
al meniului sistem si 0 altfel.
In harta de mesaje avem:
ON_WM_INITMENUPOPUP()
iar fct: (COLOR_MENU_INDEX este o variabila ce specifica pozitia meniului Color in bara de
meniu a aplicatiei)
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if (!bSysmenu && (nIndex == COLOR_MENU_INDEX)) {
pPopMenu->CheckMenuItem(IDM_ROSU, MF_UNCHECKED);
pPopMenu->CheckMenuItem(IDM_VERDE, MF_UNCHECKED);
pPopMenu->CheckMenuItem(IDM_ALBASTRU, MF_UNCHECKED);
pPopMenu->CheckMenuItem(m_nCuloare + IDM_ROSU, MF_CHECKED);
}

Un alt mecanism este tot la mesajul WM_INITMENUPOPUP si consta in a completa harta de mesaje cu fct
(handleri) pentru comenzi, handleri ce vor fi apelati inainte ca meniul sa fie vizibil si inaintea fiecarei selectii din
meniu. Fiecarui handler de actualizare ii este pasat un pointer la un obiect CCmdUI a carei functii membru pot fi
folosite pentru a modifica art de meniu. Si pt. ca aceasta clasa CCmdUI, nu este specifica unui tip particular al unui
element al interfetei utilizatorului, acesti handleri pot fi utilizati si pentru actualizarea butoanelor din toolbar si alte
obiecte ale interfetei UI.

Ex:
in harta de mesaje:
ON_COMMAND_UPDATE_UI(IDM_ROSU, OnUpdateRosu)
ON_COMMAND_UPDATE_UI(IDM_VERDE, OnUpdateVerde)
ON_COMMAND_UPDATE_UI(IDM_ALBASTRU, OnUpdateAlbastru)
void CMainFrame::OnUpdateRosu(CCmdUI* pCmdUI)
{ pCmdUI->SetCheck(m_nCuloare);}, etc.
Metode din CCmdUI: Enable, SetCheck, SetRadio (nu are echivalent in SDK), SetText

Keyboard Acceleratori Adaugare la aplicatie


Acceleratori: combinatii de taste pentru a selecta o comanda. Un accelerator produce mesajul
WM_COMMAND.
Se creaza o tabela de acceleratori in fis de resurse, o resursa speciala care coreleaza ID-ul art de
meniu cu tastele sau combinatiile de taste, si incarca resursa in program cu un apel de functie.
Resursa tabela de acceleratori este definita de un bloc ACCELERATORS in fis de resurse.
Format general:

ResurseID ACCELERATORS
BEGIN
...
END
In MFC tabela de acceleratori are structura:
IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE
BEGIN
N, ID_FILE_NEW,
VIRTKEY, CONTROL
...
VK_BACK, ID_EDIT_UNDO,
VIRTKEY, ALT
END
VIRTKEY = spune compilatorului de resurse ca prima intrare este un cod de cheie virtuala, iar urmatorul este
CONTROL, ALT sau SHIFT

Incarcarea acceleratorilor se face cu fct:


LoadAccelTable(MAKEINTRESOURCE(IDR_MAINFRAME));
De asemenea se poate face si cu LoadFrame. Daca doua resurse au acelasi nume, LoadFrame le
incarca pe amindoua la un singur apel de functie.
Pentru ca acceleratorii sa lucreze, bucla de mesaje trebuie sa includa un apel la functia API
::TranslateAccelerator
Crearea meniului programatic (at run time)
CMenu menuMain;
menuMain.CreateMenu();
Cmenu menuPopup;
menuPopup.CreatePopupMenu();
menuPopup.AppendMenu(MF_STRING, IDM_ROSU, &Rosu);
menuMain.AppendMenu(MF_POPUP, (UINT) menuPopup.Detach(), &Culori);
menuPopup.CreatePopupMenu();
menuPopup.AppendMenu(MF_STRING, IDM_EXIT, &Exit);
...
menuMain.AppendMenu(MF_POPUP, (UINT)menuPopup.Detach(), &Sesiune);
SetMenu(&menuMain);
menuMain.Detach();

Modificarea programatica
Functiile necesare pentru modificare sunt:
AppendMenu, InsertMenu, ModifyMenu, DeleteMenu, RemoveMenu
Inainte de a modifica un meniu, trebuie sa obtinem un pointer la acel meniu, CWnd::GetMenu.
In top-level menu, articolele sunt referite prin indici ce incep cu 0 (zero) cel mai din stinga.
CMenu* pMenu = GetMenu();
pMenu-DeleteMenu(1, MF_BYPOSITION); sau
pMenu->DeleteMenu(IDM_CULORI, MF_BYCOMMAND);
sau item-uri din meniuri
CMenu* pMenu = GetMenu()-GetSubMenu(1);
pMenu->DeleteMenu(IDM_VERDE, MF_BYCOMMAND);
sau echivalent:
CMenu* pMenu = GetMenu();
pMenu->DeleteMenu(IDM_VERDE, MF_BYCOMMAND); // merge bine

Cititi clasa CMenu.

Meniul system
CMenu* pSysMenu = GetSystemMenu(FALSE);
FALSE = inseamna ca dorim un pointer la o copie a meniului sistem pe care vrem sa-l
modificam. TRUE = reset system menu la starea sa implicita.
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysmenu->AppendMenu(MF_STRING, IDM_COMANDA_NOUA, _T(&Comanda
adaugata));
in harta de mesaje:
ON_WM_SYSCOMMAND()
void CMainFrame::OnSysCommand(UINT nID, LPARAM lPram)
{
if ((nID & 0xFFF0 ) == IDM_COMMANDA_NOUA)
{ // ceva }
CFrameWnd::OnSysCommand(nID, lParam);
}

Owner Draw Menus = Meniuri grafice


Metoda 1: se creaza bitmap-uri care se folosesc apoi in AppendMenu. Vezi clasa CBitmap.
Dzavantaj: bitmap-urile au marime fixa.
Metoda 2: articole meniu desenate de utilizator. Se trateaza mesajul WM_DRAWITEM. Art. de
meniu are atributul ca trebuie desenat de proprietar si nu de windows. Inainte ca meniul ce
contine un articol owner-draw sa fie afisat pentru prima data, W trimite un mesaj
WM_MEASUREITEM pentru a obtine informatii despre dimensiunile art. meniului. Pentru
fiecare articol owner-draw al meniului se transmite un asemenea mesaj.
Pas 1. Primul pas in implementarea unui asemenea meniu este de a seta atributul (stilul) meniului
cu MF_OWNERDRAW. Editorul de resurse nu suporta acest stil. Se poate apela la ModifyMenu
sau la modificarea manuala a resurselor.
Pas 2. se adauga fct OnMeasureItem la mesajul WM_MEASUREITEM
afx_msg OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpmis);
nIDCtl = ID controlului
typedef struct tagLP{

UINT CtlType;
// ODT_MENU
UINT CtlID;
UINT itemID;
// ID art meniu
UINT itemWidth; // lat. orizontala in pixeli
UINT itemHeight; // inalt in pixeli
UINT itemData;
} MEASUREITEMSTRUCT;
lpmis->itemWidth = ::GetSystemMetrics(SM_CYMENU) * 4;
lpmis->itemHeight = ::GetSystemMetrics(SM_CYMENU);
Pas 3. Se scrie fct OnDrawItem pentru mesajul WM_DRAWITEM
afx_msg OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis);
Are la baza urmatoarea structura DRAWITEMSTRUCT care contine:
UINT
CtlType;
UINT
CtlID;
UINT
itemID;
UINT
itemAction;
UINT
itemState;
HWND
hwndItem;
HDC
hDC;
RECT
rcItem;
DWORD
itemData;
Mai multe informatii in Help si J. Prossie

Procesare WM_MENUCHAR : OnMenuChar


O parte neplacuta a meniurilor owner-draw este aceea ca windows nu furnizeaza shortcut-uri
pentru acestea. Chiar daca folosim inainte un meniu text, apoi il modificam in owner-draw,
shortcut-ul de la text nu mai functioneaza. rezolvarea problemei consta in tratarea mesajului
WM_MENUCHAR, care este primit de fer. cind un meniu este afisat si o tasta care nu
corespunde unui articol de meniu este apasata. Prin procesarea acestui mesaj, putem adauga
shortcut-uri la meniurile owner-draw. Prototipul functiei CWnd::OnMenuChar este urmatorul:
afx_msg LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu)
nChar = contine codul ANSI al tastei;
nFlags = contine un flag MF_POPUP daca meniul la care mesajul vine este un submeniu;
pMenu = pointer la meniu;
Valoarea returnata:
HIWORD(LRESULT) trebuie sa contina una din urm. valori:

0 = daca W ar trebui sa ignore tasta;


1 = daca W ar trebui sa inchida meniul
2 = daca W ar trebui sa selecteze unul din art. afisate din meniu
In acest din urma caz LOWORD(LRESULT) contine ID-ul art. de meniu corespunzator.
Exista definit macroul MAKELRESULT care seteaza valoarea returnata:
LRESULT lResult = MAKELRESULT(IDM_ROSU, 2);
va seta high word pe 2 si low word cu IDM_ROSU,

Meniuri contextuale: WM_CONTEXTMENU


Se activeaza de obicei la clic dreapta mouse. Un meniu contextual nu este nimic altceva decit un submeniu care nu e
atasat la un top-level menu. Functia CMenu::TrackPopupMenu afiseaza un asemenea meniu. Prototipul fct. este:

BOOL TrackPopupMenu(UINT nFlags, int x, int y, CWnd* pWnd, LPRECT lpRect = NULL)
x, y = locatia pe ecran (coord. ecran) unde va apare meniul;
nFlags = inf. despre alianiamentul relativ la x (TPM_LEFTALIGN, TPM_CENTERALIGN,
TPM_RIGHTALIGN) si care buton este utilizat in continuare pt a fcae o selectie
(TPM_LEFTBUTTON, TPM_RIGHTBUTTON).
pWnd = identifica fereastra care va primi mesajul dupa selectia unei comenzi din meniu;
lpRect = dimensiunea unui dreptunghi (coord. ecran) in care utilizatorul poate face clic fara a
anula meniul afisat. Ex.
CMenu menu;
menu.LoadMenu(IDR_CONTEXTMENU);
CMenu* pContextMenu = menu.GetSubMenu(0);
pContextMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x, point.y,
AfxGetMainWnd());
Daca tratam mesajul WM_CONTEXTMENU in harta de mesaje avem macroul:
ON_WM_CONTEXTMENU si fct
afx_msg OnContextMenu(CWnd* pWnd, CPoint point);
pWnd = identifica fereastra in care s-a facut clic si point coordonatele punctului unde s-a facut
clic.
Procesarea comenzilor. Flagul TPM_RETURNCMD = folosit la obtinerea unui raspuns la apelul
unui meniu contextual.
int nCmd = (int) pContextMenu->TrackPopupMenu(TPM_RETURNCMD...
switch(nCmd)
{
case IDM_CONTEXT_1:
break;
...
}
Un meniu afisat in acest mod va genera mesaje WM_COMMAND cind un articol este selectat.

Dialoguri i Controale
Pentru fiecare box de dialog care apare pe ecran exist dou entiti pe care trebuie s le dezvoltm: o resurs box
de dialog i o clas box de dialog.
Resursa box de dialog este folosit pentru a desena boxa de dialog i controalele pe care le conine.
Clasa menine valorile din boxa de dialog i exist o funcie membru a acestei clase care este folosit pentru a activa
boxa de dialog. n general se construiete un meniu ce va conine o opiune pentru activarea acestui dialog.
Resursa box de dialog se construiete cu editorul de resurse. Pe baza acestei resurse Class Wizard va genera clasa
corespunztoare. n general boxele de dialog sunt derivate din CDialog.

Crearea unei resurse de dialog


Controalele uzuale din Windows pot fi folosite ntr-o box de dialog. Enumerm dintre acestea:
Static text. Folosit de alte controale pentru descriere.

Edit box. Folosit pentru a prelua anumite informaii (iruri de caractere, numere). Poate fi definit ca avnd
o singur linie sau mai multe linii.
Button. Fiecare box de dialog are implicit butoanele OK i Cancel care pot fi pstrate sau terse.
Check box. Permite selectare sau deselectare. Lucreaz independent.
Radio button. Permite selectare sau deselectare. Nu lucreaz independent.
List box. Conin o list de articole, din care utilizatorul poate selecta un articol la un moment dat. Nu
putem tasta text n cadrul acestui control.
Combo box. Este o combinaie ntre Edit box i List box.

Definirea boxei de dialod i ID-ul Controlului


Fiecare box de dialog are un ID unic (un identificator), iar controalele din cadrul boxei de dialog au de asemenea
ID-uri. Fiecare control din cadrul unei boxei de dialog este vzut ca o fereastr. Deci o parte din funcionalitatea
unei ferestre se va reflecta i asupra controlului. Clasa CDialog este derivat din clasa CWnd care descrie
funcioanlitatea unei ferestre. Dac avem un pointer la fereastr (GetDlgItem() pentru dialoguri) putem apela metode
specifice pentru aceasta. De exemplu putem ascunde o fereastr (ShowWindow()), o putem activa sau dezactiva
(EnableWindow()) sau i putem citi/modifica coninutul (GetWindowText(), SetWindowText()), etc. Pentru a ti ce
funcii se aplic va trebui s consultm clasa de baz i clasa derivat. Editorul de resurse definete implicit un ID
pentru boxa de dialog i ID-uri pentru controalele pe care le atam acesteia. Putem modifica aceste ID-uri
(Properties din meniul contextual disponibil pentru controlul selectat sau boxa de dialog) pentru a le da un sens
conform aplicaiei noastre. De obicei aceste ID-uri ncep cu IDD_ urmate de un text pentru boxele de dialod i cu
IDC_ pentru controalele din boxa de dialog. (Exemple: IDD_DIALOG1, IDC_STATIC1, IDC_EDIT1,
IDC_RADIO1, etc.).
Pentru controalele dintr-o box de dialog putem defini date membru (variabile) n cadrul clasei pentru a menine
starea acestora. Cu ajutorul Class Wizard-ului putem defini aceste variabile i le putem manevra ntr-o anumit
msur. De asemenea putem defini i implementa funciile necesare tratrii mesajelor de notificare pe care acestea le
suport.
Observaie: MFC utilizeaz tabele pentru a gestiona harta de mesaje precum i pentru a menine legtura dintre o
variabil i un control. A se vedea clasa CDataExchange i funcia DoDataExchange().
Exerciiu. Se va crea o box de dialog cu mai multe controale i se vor explica aceste lucruri pe codul rezultat.
Se vor urmri posibilitile de aliniere a controalelor, redimensionare, ordinea controalelor, stilurile, etc.
Tipuri de date pentru fiecare control:
Edit box. n mod obinuit un string, dar poate fi i un int, long, float.

Check box. int


Radio button. int

List box. String


Combo box. String
Scrollbar. int

Pentru a afia boxa de dialog va trebui s apelm funcia membru DoModal() n cazul boxelor de dialog modale.
Boxele de dialog amodale vor fi tratate separat, deoarece nu urmeaz aceeai construcie.

Exemplu de lansare n execuie a unei boxe de dialog


CSdiDialog dlg;
// se creaza obiectul pe stiva
dlg.m_check = TRUE;
// variabila atasata unui control check
dlg.m_edit = "hi there";
// variabila atasata unui control Edit
CString msg;
if (dlg.DoModal() == IDOK) // are loc afisarea dialogului
{
msg = "You clicked OK. ";
}
else
{
msg = "You cancelled. ";
}
msg += "Edit box is: ";
msg += dlg.m_edit;
AfxMessageBox (msg);

Tiprirea codului (Autocompletion: Tools->Options->Editor)


Cnd tastm codul avem posibilitatea de a vedea numele variabilelor membru i a
funciilor din clas. Dac tastm dlg. i apoi pauz, va aprea o fereastr, ce va lista
toate variabilel membru i funciile din clas, inclusiv cele motenite din clasa de baz. n
continuare vom folosi tastele sgei pentru selecie i apoi apsm tasta Space pentru a
trece selecia fcut n cadrul codului.

Ce se ascunde n spatele unei boxe de dialog?


Cel mai important lucru este nelegerea funciei care urmeaz.
void CSdiDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSdiDialog)
DDX_Control(pDX, IDC_LIST1, m_listbox);
DDX_Check(pDX, IDC_CHECK1, m_check);
DDX_Text(pDX, IDC_EDIT1, m_edit);
DDV_MaxChars(pDX, m_edit, 10);
DDX_Radio(pDX, IDC_RADIO1, m_radio);
//}}AFX_DATA_MAP
}
Trebuie s tim c ntre boxa de dialog afiat pe ecran i variabilele care menin starea anumitor controale este
definit un schimb bidirecional de date. Un rol important l joac aici funcia UpdateData() care stabilete
practic direcia de schimb ecran->variabile sau variabile->ecran.

Funciile care ncep cu DDX_ realizeaz schimbul de date. Exist 34 de funcii care ncep cu DDX, una pentru
fiecare tip de dat care poate fi schimbat ntre clas i dialog. Primul parametru arat direcia, al doilea este ID-ul
controlului iar al treilea parametru este numele variabilei. Codul este adgat de Class Wizard.

OBSERVAIE: Anumite funcii DDX nu sunt generate de Class Wizard. De exemplu,


cnd ne conectm la o valoare din List Box, singura alegere posibil pentru tip este
CString. Alegnd acest lucru, Class Wizard va genera un apel la DDX_LBString() care
conecteaz stringul selectat la variabila membru de tip CString. Exist situaii cnd un
index de tip int este mai bun. Pentru acest lucru exist funcia DDX_LBIndex() care
realizez acest schimb de informaii. O parte dintre funciile din List Box folosesc indeci
pentru a manevra articolele dintr-un list box. Putem aduga cod n DodataExchange(), dar
n afara comentariilor speciale introduse de Class Wizard. n acest caz vom aduga
singuri variabila membru la clas.
Funciile care ncep cu DDV realizeaz validarea datelor. Prametrul al doilea este numele variabilei, iar al treilea
specific limitele.

Utilizarea controlului List Box


Un control de acest tip nu poate fi iniializat dect atunci cnd boxa de dialog este afiat, deci este pe ecran. Din
acest motiv trebuie s fim ateni la momentul iniializrii. Nu putem apela funcii membru din aceast clas atta
timp ct dialogul nu este afiat. Acest lucru este valabil pentru orice control pe care l accesm ca un control i nu ca
o valoare.
O asemenea iniializare are loc n funcia OnInitialDialog() care este apelat de cadrul de lucru (frame work)
imediat ce dialogul a fost afiat pe ecran. Aceast funcie este apelat la trimiterea mesajului WM_INITDIALOG.
Cade n sarcina noastr s includem acest mesaj n tratare (se face cu Class Wizard). Se va explica n mod concret
cum se folosete Class Wizard pentru a aduga noi mesaje tratate de clasa respectiv. De asemenea tot cu Class
Wizard se ataeaz variabile pentru controalele dintr-o box de dialog.

Un exemplu pentru OnInitDialog()


BOOL CSdiDialog::OnInitDialog()
{
CDialog::OnInitDialog();
m_listbox.AddString("First String");
m_listbox.AddString("Second String");
m_listbox.AddString("Yet Another String");
m_listbox.AddString("String Number Four");
m_listbox.SetCurSel(2);
return TRUE;

// return TRUE unless you set the focus to a control


// EXCEPTION: OCX Property Pages should return FALSE

}
Aceast funcie apeleaz mai nti OnInitDialog() din clasa de baz, iar n continuare se execut codul din cadrul
funciei. Stringurile vor fi afiate n ordinea n care au fost introduse (adugate) cu funcia AddString().
n final se apeleaz funcia SetCurSel(), funcie care are drept parametru un index ce identific articolele din List
Box. Indexul pentru primul articol are valoarea 0 (zero).

OBSERVAIE: n mod obinuit, articolele n list box sunt adugate dintr-un vector sau
o list. Pentru acest lucru se folosesc clasele colecie din MFC (CStringArray, CList,
etc.).
Pentru a menine (memora) articolul (string-ul) selectat n list box, vom aduga o variabil membru de tip CString la
aceast clas. Aceast variabil va fi privat, i deci vom aduga funcii membru publice la clas pentru a manevra
aceast variabil pentru a pstra stilul de programare impus de POO.
Pentru selecie se va trata mesajul de notificare BN_CLICKED, care are semnificaia c utilizatorul a fcut o selecie
n list box. Funcia care trateaz acest mesaj se va aduga tot cu Class Wizard. n codul care urmeaz se exemplific
preluarea stringului din list box la apsarea butonului OK.
void CSdiDialog::OnOK()
{
int index = m_listbox.GetCurSel();
if (index != LB_ERR)
{
m_listbox.GetText(index, m_selected);
}
else
{
m_selected = "";
}
CDialog::OnOK();
}
Explicaii. Funcia GetCurSel() ntoarce indexul la articolul selectat. Dac acesta este valid (index != LB_ERR) se
obine valoarea acestui articol n variabila m_selected care este de tip CString folosind funcia GetText al crei prim
parametru este indexul articolului.. n final se apeleaz funcia OnOK() din clasa de baz pentru a executa alte
procesri necesare. n cele ce urmeaz vom observa apeluri la funciile din clasa de baz. Aceste apeluri sunt
generate de Class Wizard. Exist i excepii cnd aceste apeluri trebuiesc invalidae (comentate). Ca un exemplu vom
vedea la mprtirea zonei client n mai multe ferestre (splitting window) la apelul funciei OnCreateClient().

Folosirea butoanelor radio


La afiarea unei boxe de dialog care conine butoane radio vom vedea c nici un buton nu este selectat. Pentru a
realiza o selecie implicit adugm n OnInitDialog() urmtoarele linii de cod.
m_radio = 1;
UpdateData(FALSE);
Variabila m_radio este ataat unui grup de butoane radio i reprezint indexul butonului n acest grup. Primul buton
are indexul 0 (zero). Funcia UpdateData(FALSE) stabilete direcia de actualizare, care n acest caz este de la
variabil la ecran i n final are loc un refresh al boxei de dialog.
Un grup de butoane radio poate fi accesat dup ce boxa de dialog nu mai este pe ecran, deci nu trebuie s tratm
OnOK() sau ONCancel().

Controale clasice
W pune la dispozitie 6 (sase) controale clasice. Un control nu este altceva decit o fereastra cu stiluri speciale.
Trebuie retinut faptul ca a lucra cu un asemea control este ca si cum am lucra cu o fereastra. Tipurile controalelor,
structurile WNDCLASS si clasele corespondente MFC sunt date in tabela urmatoare:

Controale clasice
Control Type
Buttons
List boxes
Edit controls
Combo boxes
Scroll bars
Static controls

WNDCLASS
"BUTTON"
"LISTBOX"
"EDIT"
"COMBOBOX"
"SCROLLBAR"
"STATIC"

MFC Class
CButton
CListBox
CEdit
CComboBox
CScrollBar
CStatic

Un control este creat prin instantierea clasei respective din MFC urmat apoi de apelul functiei Create din acea clasa.
MFC creaza un obiect in doi pasi. De descris avantajele si dezavantajele acestei metode.
Daca m_wndPushButton este un obiect CButton, instructiunea:
m_wndPushButton.Create (_T ("Start"), WS_CHILD WS_VISIBLE
BS_PUSHBUTTON, rect, this, IDC_BUTTON);
creaza un control push button ce contine textul Start.
Descriere parametrii pt. fct. Create:
primul parametru specifica textul controlului;
al doilea param. reprezinta stilul ferestrei, ce reprezinta o combinatie intre stilurile ferestrei si stiluri specifice
controlului.; Controlul creat este o fereastra descendent (copil) al ferestrei identificata de al patrulea parametru (in
SDK se furnizeaza un HWND la fereastra parinte);
al treilea parametru specifica marimea si pozitia (in pixeli) controlului, data printr-un obiect CRect; pozitia este
relativa la coltul din stg sus al ferestrei parinte;
ultimul parametru este ID-ul butonului (controlului - un intreg), folosit in diverse functii pentru a avea access la el;
acest ID trebuie sa aiba o valoare unica in interiorul ferestrei date pentru a putea identifica corect controlul si
functiile care trateaza mesajele de notificare.
Unele controale (ListBox, Edit) pentru a se alinia la noile stiluri, au o noua functie membru CreateEx. Stilurile
extinse se scriu numai in cadrul acestei functii (vezi CreateWindow si CreateWindowEx).
Daca m_wndListBox este un obiect CListBox, urmatoarea instructiune creaza un control list box cu stilulu extins
WS_EX_CLIENTEDGE:
m_wndListBox.CreateEx (WS_EX_CLIENTEDGE, _T ("LISTBOX"), NULL,
WS_CHILD | WS_VISIBLE | LBS_STANDARD, rect, this, IDC_LISTBOX);
Ca o alternativa, putem deriva clasa noastra din CListBox, si apoi rescriem functia PreCreateWindow in clasa
derivata, si aplicam stilul de fereastra WS_EX_CLIENTEDGE:
BOOL CMyListBox::PreCreateWindow (CREATESTRUCT& cs)
{
if (!CListBox::PreCreateWindow (cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;

return TRUE;

Un control trimite notificari parintelui sub forma de mesaje WM_COMMAND. Tipurile de notificari depind de
tipul controlului, dar in fiecare caz, informatia din parametrii mesajului, wParam si lParam, identifica controlul care
trimite mesajul si actiunea ceruta de mesaj.

De exemplu, cind un push button este apasat (clic), codul de notificare este BN_CLICKED in HIWORD(wParam) si
ID-ul controlului in LOWORD(wParam), iar handler-ul ferestrei controlului in lParam.
Cadrul de lucru MFC, insereaza in harta de mesaje acest mesaj de notificare, ascunzind detaliile de implementare
pentru tratarea mesajului WM_COMMAND (se face legatura intre ID-ul controlului si functia care trateaza mesajul
de notificare):
ON_BN_CLICKED (IDC_BUTTON, OnButtonClicked)
ON_BN_CLICKED este un macrou, si asemenea macro-uri exista pentru fiecare mesaj de notificare de la fiecare
control.
Exista un macro generic ON_CONTROL, care manipuleaza toate notificarile si toate tipurile de controale, si
ON_CONTROL_RANGE, care mapeaza notificari in mod identic de la doua sau mai multe controale la o functie
comuna. Comunicarea intre controale si parinti (proprietarii controlului) este in ambele directii. De ex. parintele
poate trimite mesajul BM_SETCHECK unui control check box cu parametrul wParam BST_CHECKED.
MFC simplifica interfata controlului bazata pe mesaje prin construirea de functii membru in clasa controlului care
wrap BM_SETCHECK si alte mesaje ale controlului. De exemplu:
m_wndCheckBox.SetCheck (BST_CHECKED);
plaseaza un check mark in interiorul check box-ului reprezentat de un obiect CButton, numit m_wndCheckBox.
Din cauza ca un control este o fereastra, anumite functii membru pe care controlul le mosteneste din CWnd sunt
folositoare pentru controlul programarii.
De exemplu aceeasi functie care modifica titlul unei ferestre, SetWindowText, modifica textul (eticheta) unui push
button, sau schimba continutul unui control de editare (box edit). Alte functii: GetWindowText, EnableWindow,
SetFont. Daca vrem sa facem ceva in control si nu gasim o functie corespunzatoare in clasa controlului va trebui sa
cautam o asemenea functie in clasa CWnd din care sunt derivate toate contraolele.

Clasa CButton
CButton reprezinta controale de tip button bazate pe clasa WNDCLASS "BUTTON". Controalele button exista in
patru variante: push buttons, check boxes, radio buttons, si group boxes. Se vor desena cele patru tipuri.
Cand cream un control buton, vom specifica tipul acestuia prin includerea unuia din urmatoarele flag-uri in stilul
ferestrei butonului:
Style
BS_PUSHBUTTON
BS_DEFPUSHBUTTON
BS_CHECKBOX
BS_AUTOCHECKBOX
BS_3STATE
BS_AUTO3STATE
BS_RADIOBUTTON
BS_AUTORADIOBUTTON
BS_GROUPBOX

Description
Creates a standard push button control
Creates a default push button; used in dialog boxes to identify the push
button that's clicked if Enter is pressed
Creates a check box control
Creates a check box control that checks and unchecks itself when clicked
Creates a three-state check box control
Creates a three-state check box control that cycles through three states
checked, unchecked, and indeterminatewhen clicked
Creates a radio button control
Creates a radio button control that, when clicked, checks itself and
unchecks other radio buttons in the group
Creates a group box control

In plus, putem adauga urmatoarele valori (OR pe biti) la stilul ferestrei controlului privitoare la linierea textului ce
insoteste controlul:

Style
BS_LEFTTEXT
BS_RIGHTBUTTON
BS_LEFT
BS_CENTER
BS_RIGHT
BS_TOP
BS_VCENTER
BS_BOTTOM
BS_MULTILINE

Description
Moves the text accompanying a radio button or check box control from the
button's right (the default) to its left
Same as BS_LEFTTEXT
Left justifies the button text in the control rectangle
Centers the button text in the control rectangle
Right justifies the button text in the control rectangle
Positions the button text at the top of the control rectangle
Positions the button text in the center of the control rectangle vertically
Positions the button text at the bottom of the control rectangle
Allows text too long to fit on one line to be broken into two or more lines

Exista si alte tipuri de stiluri de butoane, dar care sunt folosite mai putin. De ex., BS_NOTIFY, programeaza un
buton sa trimita notificarile BN_DOUBLECLICKED, BN_KILLFOCUS, si BN_SETFOCUS.
BS_OWNERDRAW creaza un buton owner-draw (desenat de proprietar programatorul va scrie cod pentru acest
lucru) infatisarea (aparenta) butonului este gestionata de parintele butonului.

Butoane Push
Un push button este un control buton creat cu stilul BS_PUSHBUTTON. Cind este apasat, controlul trimite
parintelui notificarea BN_CLICKED printr-un mesaj WM_COMMAND. In absenta stilului BS_NOTIFY, un
asemenea control nu trimite nici un alt tip de notificare.
Macroul ON_BN_CLICKED din MFC leaga notificarile BN_CLICKED de functia membru din clasa fereastra
parinte:
ON_BN_CLICKED(IDC_BUTTON, OnButtonClicked)
Functiile pentru BN_CLICKED nu au parametri si nu intorc valori.

Check Boxes
Check boxes sunt butoane create cu stilul BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE, sau
BS_AUTO3STATE. Stilurile BS_CHECKBOX si BS_AUTOCHECKBOX pot presupune doua stari: checked si
unchecked. Un check box trece in starea checked sau unchecked cu CButton::SetCheck:
m_wndCheckBox.SetCheck (BST_CHECKED);
// Check
m_wndCheckBox.SetCheck (BST_UNCHECKED); // Uncheck
Pentru a determina daca un check box este in starea checked, folosim CButton::GetCheck. O valoare de retur egala
cu BST_CHECKED inseamna ca chcek box-ul este in starea checked, iar BST_UNCHECKED este pt unchecked.
Check boxes trimit notificarile BN_CLICKED parintilor lor cind facem click in zona lor. Stilul
BS_AUTOCHECKBOX face ca acest control sa lucreze ca un switch on/off automatizat in raspuns la even. click
mouse. Stilul BS_CHECKBOX nu face acelasi lucru. Un exemplu de cod pentru un check box cu stilul
BS_CHECKBOX si ce trebuie sa facem la BN_CLICKED:
void CMainWindow::OnCheckBoxClicked ()
{
m_wndCheckBox.SetCheck (m_wndCheckBox.GetCheck () ==
BST_CHECKED ? BST_UNCHECKED : BST_CHECKED);
}
Stilurile BS_3STATE si BS_AUTO3STATE creaza un check box care presupune o a treia stare numita
nedeterminata (indeterminate), si controlul intra in aceasta stare cind facem clic pe un asemenea buton iar starea lui
curenta este checked sau cind apelam SetCheck cu parametrul BST_INDETERMINATE:
m_wndCheckBox.SetCheck (BST_INDETERMINATE);

Un check box in starea indeterminate contine a grayed check mark. Aici pare sa lucreze o logica trivalenta
partiala, in sensul ca starea nu poate fi sigura nici checked nici unchecked. (Ex. selectam text in bold si nebold.)

Butoane Radio
Un buton radio este un control de tip buton cu stilul BS_RADIOBUTTON sau BS_AUTORADIOBUTTON. In mod
normal butoanele radio lucreaza in grup, si reprezinta o lista de optiuni mutual exclusive. Cind selectam un buton
radio cu stilul BS_AUTORADIOBUTTON va ramine activ numai butonul selectat, celelalte butoane din grup
devenind inactive in mod automat. Daca folosim stilul BS_RADIOBUTTON, va trebui sa scriem noi cod pentru a
dezactiva celelalte butoane, folosind functia CButton::SetCheck.
Butoanele radio trimit notificarile BN_CLICKED parintilor lor, la fel ca mai sus.
Urmatorul cod trateaza BN_CLICKED:
void CMainWindow::OnRadioButton1Clicked ()
{
m_wndRadioButton1.SetCheck (BST_CHECKED);
m_wndRadioButton2.SetCheck (BST_UNCHECKED);
m_wndRadioButton3.SetCheck (BST_UNCHECKED);
m_wndRadioButton4.SetCheck (BST_UNCHECKED);
}
Deselectind (unchecking) celelalte butoane radio mentine exclusivitatea selectiei. Un handler (o fct.) pentru
BN_CLICKED nu este necesar pentru butoanele cu stilul BS_AUTORADIOBUTTON. Pentru butoane radio cu
stilul BS_AUTORADIOBUTTON pentru a deselecta corect alte butoane din grup, trebuie sa grupam butoanele in
momentul crearii, a.i. W sa stie care butoane apartin grupului. Pentru a crea un grup d ebutoane radio cu stilul
BS_AUTORADIOBUTTON urmam urmatoarea procedura (tehnica):
1. In codul aplicatiei, cream butoanele unul dupa altul fara a intercala intre acestea alte controale de alt tip.
2. Pentru a marca inceputul grupului, atribuim stilul WS_GROUP primului buton radio pe care il cream.
3. Daca cream controale aditionale dupa ultimul buton radio din grup, atribuim stilul WS_GROUP primului
control aditional pe care il cream.
Cream doua grupuri de cite 4 respectiv 3 butoane radio cu stilul BS_AUTORADIOBUTTON cu un control check
box intre ele:
m_wndRadioButton1.Create (_T ("COM1"), WS_CHILD
WS_GROUP BS_AUTORADIOBUTTON, rect1, this,
m_wndRadioButton2.Create (_T ("COM2"), WS_CHILD
BS_AUTORADIOBUTTON, rect2, this, IDC_COM2);
m_wndRadioButton3.Create (_T ("COM3"), WS_CHILD
BS_AUTORADIOBUTTON, rect3, this, IDC_COM3);
m_wndRadioButton4.Create (_T ("COM4"), WS_CHILD
BS_AUTORADIOBUTTON, rect4, this, IDC_COM4);
m_wndRadioButton1.SetCheck (BST_CHECKED);

WS_VISIBLE
IDC_COM1);
WS_VISIBLE
WS_VISIBLE
WS_VISIBLE

m_wndCheckBox.Create (_T ("Save settings on exit"),


WS_CHILD WS_VISIBLE WS_GROUP BS_AUTOCHECKBOX,
rectCheckBox, this, IDC_SAVESETTINGS);
m_wndRadioButton5.Create (_T ("9600"), WS_CHILD WS_VISIBLE
WS_GROUP BS_AUTORADIOBUTTON, rect5, this, IDC_9600);
m_wndRadioButton6.Create (_T ("14400"), WS_CHILD WS_VISIBLE
BS_AUTORADIOBUTTON, rect6, this, IDC_14400);

m_wndRadioButton7.Create (_T ("28800"), WS_CHILD WS_VISIBLE


BS_AUTORADIOBUTTON, rect7, this, IDC_28800);
m_wndRadioButton5.SetCheck (BST_CHECKED);
Butoanele radio nu sunt niciodata checked implicit. Este responsabilitatea programatorului.

Group Boxes
Un control group box este creat cu stilul BS_GROUPBOX. Acest control nu primeste si nici nu trimite mesaje.
Singurul rol al lor este de a grupa anumite controale in interfata destinata utilizatorului.

Clasa CListBox
Clasa CListBox din MFC incapsuleaza controalele list box, care afiseaza o lista de stringuri numite articole. Un list
box optional poate sorta articolele pe care le contine si are implementata navigarea verticala, optional si cea
orizontala.
Cind pe un item (articol) facem clic sau dublu clic , list box-urile (care au stilul LBS_NOTIFY) notifica parintilor
lor printr-un mesaj WM_COMMAND. MFC simplifica procesarea acestor mesaje furnizind macro-ul ON_LBN in
harta de mesaje, care ruteaza notificarile list box-ului la functii din clasa fereastra parinte..
Un list box standard afiseaza stringuri intr-o coloana verticala si permite ca un singur articol sa fie selectat la un
moment dat. Articolul curent selectat este afisat in video invers cu culoarea sistem COLOR_HIGHLIGHT. Windows
suporta un numar de variatii de la standardul initial, variatii ce permit selectii multiple, afisarea pe mai multe
coloane, list box-uri desenate de proprietar, afisare de imagini in locul textului.

Crearea unui List Box


Urmatoarea instructiune creaza un list box din obiectul CListBox numit m_wndListBox:
m_wndListBox.Create (WS_CHILD WS_VISIBLE LBS_STANDARD,
rect, this, IDC_LISTBOX);
LBS_STANDARD combina the stilurile WS_BORDER, WS_VSCROLL, LBS_NOTIFY, si LBS_SORT pentru a
crea un list box care are margini, o bara de scroll verticala, care notifica parintilor sai cind selectia s-a schimbat sau
s-a facut dublu clic pe un articol, si ca articolele vor fi sortate in ordine alfabetica. Implicit bara de scroll este
vizibila numai cind articolele nu pot fi afisate in intregime in fereastra controlului. Pentru a face ca bara de scroll sa
fie afisata tot timpul va trebui sa includem stilul LBS_DISABLENOSCROLL. A list box doesn't have a vertical
scroll bar unless the style WS_VSCROLL or LBS_STANDARD is included. Putem crea list box-uri care cuprind
toata zona client. List box-urile au incapsulata interfata cu tastatura (tastele sageti, page up, down, apasarea unui
caracter muta selectia pe articolul care incepe cu acel caracter. Apasarea barei de spatiu face sa avem selectie
multipla sau nu (on/off).
Putem programa interfata cu tastatura prin includerea stilului LBS_WANTKEYBOARDINPUT si procesarea
mesajelor WM_VKEYTOITEM si WM_CHARTOITEM. O aplicatie MFC poate mapa aceste mesaje cu fct.
OnVKeyToItem si OnCharToItem folosind macro-urile ON_WM_VKEYTOITEM si ON_WM_CHARTOITEM. O
clasa list box derivata poate manipula aceste mesaje singura prin suprascrierea functiilor virtuale
CListBox::VKeyToItem si CListBox::CharToItem. O utilizarae a acestei proprietati este de a crea clase list box-uri
self-contained list box class , care raspund la Ctrl-D prin stergerea articolului curent selectat.
List Box Styles
Style
LBS_STANDARD
LBS_SORT
LBS_NOSEL

Description
Creates a "standard" list box that has a border and a vertical scroll bar,
notifies its parent window when the selection changes or an item is
double-clicked, and sorts items alphabetically.
Sorts items that are added to the list box.
Creates a list box whose items can be viewed but not selected.

LBS_NOTIFY
LBS_DISABLENOSC ROLL
LBS_MULTIPLESEL
LBS_EXTENDEDSEL
LBS_MULTICOLUMN
LBS_OWNERDRAWVARIABLE
LBS_OWNERDRAWFIXED
LBS_USETABSTOPS
LBS_NOREDRAW
LBS_HASSTRINGS
LBS_WANTKEYBOARDINPUT
LBS_NOINTEGRALHEIGHT

Creates a list box that notifies its parent when the selection changes or
an item is double-clicked.
Disables the list box's scroll bar when it isn't needed. Without this style,
an unneeded scroll bar is hidden rather than disabled.
Creates a multiple-selection list box.
Adds extended selection support to a multiple-selection list box.
Creates a multicolumn list box.
Creates an owner-draw list box whose items can vary in height.
Creates an owner-draw list box whose items are the same height.
Configures the list box to expand tab characters in item text.
Creates a list box that doesn't automatically redraw itself when an item
is added or removed.
Creates a list box that "remembers" the strings added to it.
Conventional list boxes have this style by default; owner-draw list
boxes don't.
Creates a list box that sends its parent a WM_VKEYTOITEM or
WM_CHARTOITEM message when a key is pressed. This style is
used to customize the list box's response to keyboard input.
Allows a list box to assume any height. By default, Windows sets a list
box's height to a multiple of the item height to prevent items from being
partially clipped.

Pentru ca fontul implicit pe care W il foloseste pt list box-uri este proportional spatiat, virtual este imposibil de a
alinia coloanele prin spatii. O modalitate de a crea liste ce contin informatii pe mai multe coloane este sa folosim
SetFont pt a aplica un font fixed-pitch la un list box. O solutie mai buna este de a asigna list box0urilor stilul
LBS_USETABSTOPS si de a separa coloanele de informatii cu tab. Un list box cu stilul LBS_USETABSTOPS
trateaza caracterele tab ca un procesor de texte. Implicit tab este de marimea a 8 caractere pentru latime. Putem
schimba acest lucru cu fct. CListBox::SetTabStops. SetTabStops masoara distanta in unitati de dialog = o patrime din
latimea unui caracter in fontul sistem.
Instructiunea:
m_wndListBox.SetTabStops (64);
pune spatiul dintre tab-uri la 64 unitati de dialog , and
int nTabStops[] = { 32, 48, 64, 128 };
m_wndListBox.SetTabStops (4, nTabStops);
plaseaza stop tab-uri la 32, 48, 64, si 128 unitati de dialog fata de marginea din stinga.
Implicit un list box se redeseneaza singur cind este adaugat/sters un articol. Pentru a impiedica acest lucru putem
seta stilul LBS_NOREDRAW. O asemenea lista va fi redesenata cind zona ei client va fi invalidata.
O alta alternativa este de a inhiba procesul de actualizare cu LBS_NOREDRAW si a-l reactiva dupa ce ultimul
articol din list box a fost adaugat. Putem face redesenarea enable/disable prin trimiterea mesajului si nu mai este
necesar Invalidate()
m_wndListBox.SendMessage (WM_SETREDRAW, FALSE, 0); // Disable redraws.
m_wndListBox.SendMessage (WM_SETREDRAW, TRUE, 0); // Enable redraws.
Stilul LBS_MULTIPLESEL este folosit pentru selectii multiple. Cele mai multe list box-uri sunt create cu stilul
LBS_EXTENDEDSEL, care permite selectii extinse. Cu un asemenea stil se fac selectii cu ajutorul mouse-ului si a
tastei Ctrl (pe sarite) sau Shift (selectie contigua) (se poate combina Ctrl si Shift).
Stilul LBS_MULTICOLUMN creaza un list box cu mai multe coloane (implicit 16 car per art.), care in mod normal
au si stilul WS_HSCROLL pentru defilare orizontala. List Box-urile multicoloana nu pot avea bara verticala pentru
scroll. Latimea coloanei se ajusteaza cu functia CListBox::SetColumnWidth.

Adaugarea si Stergerea articolelor


Articolele sunt adaugate cu fct. CListBox::AddString si CListBox::InsertString. Instructiunea:
m_wndListBox.AddString (string);
adauga un ob. CString la list box. Daca stilul include LBS_SORT, at. art. e pozitionat corespunzator ordinii de
sortare alfabetice, altfel este adaugat la sfirsitul listei. InsertString adauga art. la o pozitie indicata de primul
parametru al fct. (zero-based index):
m_wndListBox.InsertString (3, string);
LBS_SORT nu are efect asupra stringurilor adaugate cu InsertString.
Ambele functii AddString si InsertString intorc pozitia stringului din list box. In caz de esec se returneaza
LB_ERRSPACE pentru a indica ca un list box este plin sau LB_ERR pt. a indica ca s-a intimplat altceva din diverse
motive. Capacitatea unui list box este limitata numai de memoria disponibila. Functia CListBox::GetCount
returneaza numarul art. dintr-un list box.
Fct. CListBox::DeleteString elimina un articol dintr-un list box, articol identificat prin indexul sau. Intoarce numarul
articolelor ramase in list box. Pentru a sterge toate art. fol. fct. CListBox::ResetContent.
Daca dorim sa asociem un pointer pe 32 biti sau o valoare DWORD cu un articol din list box putem folosi fct.
CListBox::SetItemDataPtr sau CListBox::SetItemData. Un pointer sau un DWORD asociat cu un art. poate fi regasit
cu fct. CListBox::GetItemDataPtr sau CListBox::GetItemData. O folosire a acestei trasaturi este de ex. de a asocia o
structura de date ce contine nr. de telefon pentru persoanele dintr-un list box. Din cauza ca GetItemDataPtr
intoarce un pointer la void trebuie facuta conversia.
O alta tehnica este de a asocia extra date in particular text cu art. dintr-un list box , s acream un list box cu stilul
LBS_USETABSTOPS, sa setam primul tab stop la o pozitie din afara marginii drepte a list box-ului si din a adauga
stringuri ce contin car tab urmate de extra data (text). Textul de la dreapta tab-ului va fi invizibil, dar
CListBox::GetText va returna intregul text, deci si cel extra.

Cautarea si regasirea articolelor


CListBox::GetCurSel intoarce indexul (0-based) al articolului care este selectat. Daca valoarea returnata este
LB_ERR inseamna ca nu s-a selectat nimic. GetCurSel este adesea apelata ca urmare a unei notificari ce semnifica
ca selectia s-a schimbat sau a fost facut dublu clic pe un articol. Un program poate seta selectia curenta cu
SetCurSel. Pasind valoarea 1 pt. SetCurSel vom deselecta toate articolele. Pentru a gasi daca un art particular este
selectat folosim CListBox::GetSel.
SetCurSel identifica un articol prin indexul sau, dar art. pot fi selectate si dupa continut cu fct.
CListBox::SelectString care realizeaza o singura selectie pentru un articol ce incepe cu textul specificat si selecteaza
art. daca se gaseste unul care satisface conditia. Instructiunea
m_wndListBox.SelectString (-1, _T ("Times"));
incepe cautarea cu primul art din list box si va selecta primul art care incepe cu Times. Cautarea nu este case
senzitive. Primul parametru indica indexul de unde incepe cautarea; -1 inseamna de la inceput. Indiferent de unde
incepe cautarea aceasta poate sa parcurga circular intreaga lista asociata list box-ului daca este necesar. Pentru a
cauta pentru un art. particular fara a schimba selectia vom folosi CListBox::FindString sau
CListBox::FindStringExact. FindString face cautare numai pe primele caractere din art. Daca se intoarce LB_ERR
inseamna ca nu s-a gasit acel art, altfel se intoarce indexul art. FindStringExact adauga in plus cautarea exacta. Cu
indexul obtinut anterior putem aobtine textul art. cu CListBox::GetText. Se copie textul art. in var. string.
CString string;
int nIndex = m_wndListBox.GetCurSel ();
if (nIndex != LB_ERR)
m_wndListBox.GetText (nIndex, string);

Al doilea parametru este un pointer la char. Putem folosi CListBox::GetTextLen pentru a determina marimea zonei
necesare pentru a primi textul art. inainte de a apela GetText.
Selectiile multiple sunt tratate diferit. GetCurSel, SetCurSel, si SelectString nu pot fi folosite in acest caz. Art. sunt
selectate (deselectate) cu fct. SetSel si SelItemRange. In continuare se selecteaza art. cu indecsii 0, 5, 6, 7, 8, si 9 si
deselecteaza art. 3:
m_wndListBox.SetSel (0);
m_wndListBox.SelItemRange (TRUE, 5, 9);
m_wndListBox.SetSel (3, FALSE);
Alte functii: GetSelCount pt. determinarea nr. art. selectate, GetSelItems pentru regasirea indecsilor art. selectate.
Intr-un list box cu selectie multipla, dreptunghiul ce reprezinta art. cu focus-ul asupra lui, poate fi mutat fara a
schimba selectia curenta. Dreptunghiul care are focusul poate fi mutat sau obtinut cu fct. SetCaretIndex si
GetCaretIndex. Multe din fct. ce lucreaza cu o singura selectie sunt disponibile si pentru list box-urile cu sele.
multipla: GetText, GetTextLength, FindString, si FindStringExact.

Notificarile List Box


Notificarile sunt trimise via mesajul WM_COMMAND. In app. MFC, notificarile list box-urilor sunt mapate la
functiile din clasa cu macro-ul ON_LBN.Vezi tabelul de mai jos.
Notificrile LBN_DBLCLK, LBN_SELCHANGE, si LBN_SELCANCEL sunt trimise numai daca list box-ul a fost
creat cu stilul LBS_NOTIFY sau LBS_STANDARD.
List Box Notifications
Notification
LBN_SETFOCUS
LBN_KILLFOCUS
LBN_ERRSPACE

Sent When

The list box gains the input focus.


The list box loses the input focus.
An operation failed because of
insufficient memory.
LBN_DBLCLK
An item is double-clicked.
LBN_SELCHANGE The selection changes.
LBN_SELCANCEL The selection is canceled.

Message-Map Macro
ON_LBN_SETFOCUS
ON_LBN_KILLFOCUS
ON_LBN_ERRSPACE

LBS_NOTIFY
Required?
No
No
No

ON_LBN_DBLCLK
ON_LBN_SELCHANGE
ON_LBN_SELCANCEL

Yes
Yes
Yes

Notificarile cele mai folosite sunt: LBN_DBLCLK si LBN_SELCHANGE. Pentru a determina indexul articolului
pe care s-a facut dublu clic intr-un list box cu o singura selectie folosim CListBox::GetCurSel. Vezi ex.
// In CMainWindow's message map
ON_LBN_DBLCLK (IDC_LISTBOX, OnItemDoubleClicked)
void CMainWindow::OnItemDoubleClicked ()
{
CString string;
int nIndex = m_wndListBox.GetCurSel ();
m_wndListBox.GetText (nIndex, string);
MessageBox (string);
}
Pentru un LB cu selectie multipla folosim GetCaretIndex in locul fct. GetCurSel pentru a determina articolul pe
care s-a facut dublu clic. Notificarea LBN_SELCHANGE este trimisa cind utilizatorul schimba selectia, dar nu si in
cazul cind selectia este schimbata automat prin program. Un LB cu selectie simpla trimite notificarea
LBN_SELCHANGE cind selectia se muta din cauza unui clic sau a apasarii unei taste. Intr-un LB cu sel. multipla
notificarea LBN_SELCHANGE este trimisa cind se face clic pe un art., cind starea selectiei art. este modificata
(on/off) si cind dreptunghiul care are focus-ul este mutat.

Clasa CStatic
CStatic, reprez. un control static creat din "STATIC" WNDCLASS.
Exista trei tipuri de CS: text (folosit pentru a eticheta alte controale), dreptunghiuri si imagini.
m_wndStatic.Create (_T ("Name"), WS_CHILD WS_VISIBLE SS_LEFT,
rect, this, IDC_STATIC);
SS_LEFT = aliniaza text in stinga. Daca textul nu incape se continua pe linia urmatoare. Pt. a preveni trecerea
textului pe linia urm. putem folosi stilul SS_LEFTNOWORDWRAP in locul lui SS_LEFT. Alte stiluri:
SS_CENTER sau SS_RIGHT. Stilul SS_SIMPLE este asemanator cu SS_LEFT dar creaza un control al carui text
poate fi modificat cu CWnd::SetWindowText.
Pt. a centra vertical textul facem OR pe flagul SS_CENTERIMAGE. (SS_SUNKEN pentru desenare)
CS pt. desenat dreptughiuri. Stilul poate fi ales din urmatoarele:
Style
SS_BLACKFRAME
SS_BLACKRECT
SS_ETCHEDFRAME
SS_ETCHEDHORZ
SS_ETCHEDVERT
SS_GRAYFRAME
SS_GRAYRECT
SS_WHITEFRAME
SS_WHITERECT

Description
Hollow rectangle painted in the system color COLOR_WINDOWFRAME
(default = black)
Solid rectangle painted in the system color COLOR_WINDOWFRAME (default
= black)
Hollow rectangle with etched borders
Hollow rectangle with etched top and bottom borders
Hollow rectangle with etched left and right borders
Hollow rectangle painted in the system color COLOR_BACKGROUND (default
= gray)
Solid rectangle painted in the system color COLOR_BACKGROUND (default =
gray)
Hollow rectangle painted in the system color COLOR_WINDOW (default =
white)
Solid rectangle painted in the system color COLOR_WINDOW (default = white)

Instructiunea:
m_wndStatic.Create (_T (""), WS_CHILD WS_VISIBLE SS_ETCHEDFRAME,
rect, this, IDC_STATIC);
creaza un CS asemanator cu grup box.
Un CS dreptunghi nu afiseaza text.
CS pt. imagini formate din bitmap-uri, icoane, cursoare sau metafisiere GDI. Stilurile folosie in acest caz sunt:
Style
SS_BITMAP
SS_ENHMETAFILE
SS_ICON

Description
A static control that displays a bitmap
A static control that displays a metafile
A static control that displays an icon or a cursor

Dupa ce se creaza un control static imagine, asociem bitmap, icoana sau cursor cu fct. SetBitmap, SetEnhMetaFile,
SetIcon sau SetCursor. Instructiunile:
m_wndStatic.Create (_T (""), WS_CHILD WS_VISIBLE SS_ICON,
rect, this, IDC_STATIC);
m_wndStatic.SetIcon (hIcon);

creaz un CS care afis. o icoana si ii atasam icoana cu SetIcon. Dreptughiul este marit automat pentru a cuprinde
imaginea. Exista o serie de falg-uri care pot fi folosite pentru a controla modul de afisare al imaginii in control
(SS_CENTERIMAGE = are ca cerinta majora, drept. de afisare tr. sa fie destul de mare pentru a cuprinde imaginea),
Implicit, un CS nu trimite mesaje de notificare. Daca se creaza CS cu stilul SS_NOTIFY, at. CS trimite urm.
notificari:
Static Control Notifications
Notification
Sent When
STN_CLICKED
The control is clicked.
STN_DBLCLK
The control is double-clicked.
STN_DISABLE
The control is disabled.
STN_ENABLE
The control is enabled.

Message-Map Macro
ON_STN_CLICKED
ON_STN_DBLCLK
ON_STN_DISABLE
ON_STN_ENABLE

Notificarile STN_CLICKED si STN_DBLCLK permit crearea de CS care raspund la clic-uri de mouse, ca in ex.:
// In CMainWindow's message map
ON_STN_CLICKED (IDC_STATIC, OnClicked)
// In CMainWindow::OnCreate
m_wndStatic.Create (_T ("Click me"), WS_CHILD WS_VISIBLE
SS_CENTER SS_CENTERIMAGE SS_NOTIFY SS_SUNKEN, rect,
this, IDC_STATIC);
void CMainWindow::OnClicked ()
{
m_wndStatic.PostMessage (WM_CLOSE, 0, 0);
}

Clasa CEdit (CE)


CEdit din MFC incapsuleaza functionalitatea unui control de editare folosit pt. a edita text: pe o singura linie sau pe
mai multe linii. Zona client din Notepad este un control de editare multilinie. Un control de editare este limitat la 60
KB text. Daca e nevoie de mai mult text vom folosi un control RICH EDIT (imbogatit).

Crearea unui control Edit


Daca m_wndEdit este un obiect CEdit instructiunea
m_wndEdit.Create (WS_CHILD WS_VISIBLE WS_BORDER
ES_AUTOHSCROLL, rect, this, IDC_EDIT);
creaza un control single line care face scroll orizontal automat, daca textul nu incape in zona de afisare. Incluzind
stilul ES_MULTILINE vom crea un CE multilinie:
m_wndEdit.Create (WS_CHILD WS_VISIBLE WS_BORDER
WS_HSCROLL WS_VSCROLL ES_MULTILINE, rect, this, IDC_EDIT);

WS_HSCROLL si WS_VSCROLL adauga barele de scroll vertical si orizontal. Putem folosi CEdit::SetRect sau
CEdit::SetRectNP pt. a defini zona editabila a controlului independent de marginile controlului. O utilizare pt. aceste
functii este de a defini marimea paginii care ramine constanta chiar daca controlul este redimensionat. Putem folosi
de asemenea CEdit::SetMargins pentru a specifica latimea (in pixeli) marginii stg si dreapta. Implicit latimile
marginilor sunt 0.
Cind este prima data creat, un CE va accepta numai 30,000 caractere. Putem modifica acest lucru cu
CEdit::LimitText sau CEdit::SetLimitText. Urmatoarea instructiune seteaza nr. max de car. la 32:
m_wndEdit.SetLimitText (32);
Cind folosim un CE multilinie, SetLimitText limiteaza cantitatea totala de text din control, deci nu lungimea fiecarei
linii. In acest caz putem controla lungimea liniei numai manual.
O metoda este de a folosi SetFont pt a comuta fontul CE la un font fixed-pitch si CEdit::SetRect pt a specifica
dreptunghiul de formatare a carui latime este un pic mai mare decit latimea caracterelor din font inmultita cu nr. de
caractere dorit a se afisa pe o linie.
Edit Control Styles
Style
ES_LEFT
ES_CENTER
ES_RIGHT
ES_AUTOHSCROLL
ES_AUTOVSCROLL
ES_MULTILINE
ES_LOWERCASE
ES_UPPERCASE
ES_PASSWORD
ES_READONLY
ES_NOHIDESEL
ES_OEMCONVERT
ES_WANTRETURN

Description
Left-aligns text in the control.
Centers text in the control.
Right-aligns text in the control.
Permits the edit control to scroll horizontally without a horizontal scroll bar. To
add a horizontal scroll bar, include the style WS_HSCROLL.
Permits the edit control to scroll vertically without a vertical scroll bar. To add a
vertical scroll bar, include the style WS_VSCROLL.
Creates a multiline edit control.
Displays all characters in lowercase.
Displays all characters in uppercase.
Displays asterisks instead of typed characters.
Creates an edit control whose text can't be edited.
Prevents the edit control from hiding the selection when the control loses the input
focus.
Performs an ANSI-to-OEM-to-ANSI conversion on all characters typed into the
control so that the application won't get unexpected results if it performs an ANSIto-OEM conversion of its own. Obsolete.
Programs the Enter key to insert line breaks instead of invoking the default push
button for multiline edit controls used in dialog boxes.

O alta functie folositoare pt a initializa un CE este CEdit::SetTabStops, care seteaza spatiile dintre tab_uri. Implicit
tab stopul este de 8 caractere. Ca si CListBox::SetTabStops, CEdit::SetTabStops masoara distanta in unitati de
dialog.

Inserarea si Regasirea Textului


Textul se insereaza cu SetWindowText si se regaseste cu GetWindowText. CEdit mosteneste ambele functii din clasa
de baza CWnd. Instructiunea
m_wndEdit.SetWindowText (_T ("Hello, MFC"));
insereaza textul "Hello, MFC" in controlul m_wndEdit, si
m_wndEdit.GetWindowText (string);
regaseste textul intr-un obiect CString numit string. GetWindowText si SetWindowText lucreaza cu ambele tipuri de
controale, single line si multiline. Textul inserat cu SetWindowText inlocuieste textul existent, iar GetWindowText

returneaza tot textul din control, chiar daca acesta este pe mai multe linii. Pt. a stegte textul apelam SetWindowText
cu un sir nul:
m_wndEdit.SetWindowText (_T (""));
Putem insera text fara a stege cel existent cu CEdit::ReplaceSel. Daca unul sau mai multe caractere sunt selectate
cind apelam ReplaceSel, textul care se insereaza inlocuieste textul selectat, in caz contrar textul este inserat la pozitia
curenta a cursorului (caret-ului).
Un control multiline insereaza line break automat. Daca dorim sa determinam line break-urile dintr-un text folosim
CEdit::FmtLines pt a face enable soft line breaks inainte de apelul lui GetWindowText:
m_wndEdit.FmtLines (TRUE);
Cu soft line breaks enabled, fiecare linie este delimitata cu doua CR (0x13) urmat de un LF (0x10). Pt. a invalida
soft line break folosim FmtLines( FALSE):
m_wndEdit.FmtLines (FALSE);
CR introdus in text la apasarea tastei <Enter> sunt semnificate de o pereche CR/LF. FmtLines nu afecteaza modul de
afisare al textului intr-un CE multilinie, ci afecteaza numai modul cum este memorat intern textul si formateaza
textul regasit cu GetWindowText.
Pentru a citi exact o linie de text dintr-un control multilinie folosim CEdit::GetLine. GetLine copie continutul unei
linii intr-un buffer pe care trebuie sa-l alocam si apoi furnizam functiei adresa acestuia. Linia este identificata de un
index 0-based. Instructiunea:
m_wndEdit.GetLine (0, pBuffer, nBufferSize);
copie prima linie din control in zona data de pBuffer, iar par. 3 indica dimensiunea buff. in bytes. GetLine returneaza
numarul de octeti copiati in buffer. Putem determina dinaninte marimea necesara a buff. cu fct. CEdit::LineLength,
iar numarul de linii din control il det. cu fct. CEdit::GetLineCount. GetLineCount nu returneaza niciodata 0, chiar
daca nu exista text valoarea returnata este 1.

Clear, Cut, Copy, Paste, and Undo


CEdit furnizeaza functii pentru operatiile enumerate mai sus. Instructiunea:
m_wndEdit.Clear ();
sterge textul selectat fara a afecta continutul clipboard-ului.Instructiunea:
m_wndEdit.Cut ();
sterge textul selectat si il copie in clipboard.Instructiunea:
m_wndEdit.Copy ();
copie textul selectat in clipboard fara a-l sterge.
Putem interoga CE pt. selectia curenta cu un apel al fct. CEdit::GetSel, care returneza o valoare DWORD ce contine
doi intregi pe 16 biti ce specifica indexul de inceput si indexul de sfarsit al selectiei. Daca indecsii sunt egali nu
exista text selectat. Exista o forma a fct. GetSel care copie indecsii in doi intregi ale caror adrese sunt pasate ca
parametrii prin referinta. Putem adauga urmatoare functie IsTextSelected, la clasa controlului de editare derivat din
CEdit pentru a determina daca exista sau nu text selectat in control:
BOOL CMyEdit::IsTextSelected ()
{
int nStart, nEnd;

GetSel (nStart, nEnd);


return (nStart != nEnd);
}
CEdit::Cut and CEdit::Copy nu fac nimic daca nu este text selectat. Textul poate fi selectat prin program cu
CEdit::SetSel. Instructiunea:
m_wndEdit.SetSel (100, 150);
selecteaza 50 de caractere incepind cu al 101-lea caracter si o face vizibila in view daca aceasta nu este vizibila (se
face scroll automat). Pt. a preveni defilarea (scrolling), vom folosi si al 3-lea param. al functiei cu valoarea TRUE.
Cind facem selectii prin program intr0un control multilinie, este necesar adesea sa convertim un numar de linie si
posibil un offset din interiorul acestei linii intr-un index pe care-l vom folosi in SetSel. Functia CEdit::LineIndex
accepta un numar de linie 0-based si returneaza indexul primului caracter din acea linie. In ex. care urmeaza se
determina index-ul primului caracter din linia 8 (LineIndex), apoi determinam lungimea liniei si selectam tot textul
care se gaseste in acea linie (SetSel):
int nStart = m_wndEdit.LineIndex (7);
int nLength = m_wndEdit.LineLength (nStart);
m_wndEdit.SetSel (nStart, nStart + nLength);
CEdit furnizeaza fct. LineFromChar pt. a calcula numarul liniei plecind de la index-ul unui caracter.
CEdit::Paste pastes text intr-un CE.
m_wndEdit.Paste ();
Daca clipboard-ul nu contine text, CEdit::Paste nu are efect. Daca nu exista text selectat cind se apeleaza Paste se
insereaza textul din clipboard la pozitia curenta a caret-ului. Daca exista o selectie, atunci textul din clipboard
inlocuieste selectia existenta. Putem determina din timp daca exista text in clipboard printr-un apel al fct.
::IsClipboardFormatAvailable. Instructiunea:
BOOL bCanPaste = ::IsClipboardFormatAvailable (CF_TEXT);
seteaza bCanPaste la o val. # 0 daca exista text in clipboard sau 0 in caz contrar. O alta trasatura a unui CE este
posibilitatea roll back-ului (undo). , reface ultima stergere:
m_wndEdit.Undo ();
Se poate determina din timp daca am putea apela Undo prinapelul fct. CEdit::CanUndo. O alta fct.,
CEdit::EmptyUndoBuffer, reseteaza manual flag-ul pentru undo, a.i., urmatoarele apeluri la Undo nu vor face nimic.

Notificarile Controlului de Editare


In app. MFC, notificarile sunt mapate cu macro-uri de forma ON_EN in harta de mesaje a clasei.
In ex. urm. se trateaza notificarea (mesaj) EN_CHANGE a unui CE. Un control de tip push buton
(m_wndPushButton) este facut enable/disable dupa cum exista/nu exista text in CE cu ID=IDC_EDIT si dat de ob.
(m_wndEdit) :
// In CMainWindow's message map
ON_EN_CHANGE (IDC_EDIT, OnUpdatePushButton)
void CMainWindow::OnUpdatePushButton ()
{
m_wndPushButton.EnableWindow (m_wndEdit.LineLength ());

}
Edit Control Notifications
Notification
Sent When
EN_UPDATE
The control's text is about to change.
EN_CHANGE
The control's text has changed.
EN_KILLFOCUS The edit control loses the input focus.
EN_SETFOCUS
The edit control receives the input focus.
EN_HSCROLL
The edit control is scrolled horizontally using a scroll bar.
EN_VSCROLL
The edit control is scrolled vertically using a scroll bar.
EN_MAXTEXT
A character can't be entered because the edit control
already contains the number of characters specified with
CEdit::LimitText or CEdit::SetLimitText. This notification
is also sent if a character can't be entered because the
caret is at the right or the bottom edge of the control's
formatting rectangle and the control doesn't support
scrolling.
EN_ERRSPACE
An operation fails because of insufficient memory.

Message-Map Macro
ON_EN_UPDATE
ON_EN_CHANGE
ON_EN_KILLFOCUS
ON_EN_SETFOCUS
ON_EN_HSCROLL
ON_EN_VSCROLL
ON_EN_MAXTEXT

ON_EN_ERRSPACE

Clasa CComboBox (control combo box)


Un CB este format dintr-un CE si un LB.
Tipuri de Combo box-uri: simple, drop-down, si drop-down list.
CB simple (stil CBS_SIMPLE) sunt cele mai putin folosite. Trasatura principala a acestora este ca sunt permanent
afisate. Cind un utilizator selecteaza un art din lista, ac. art. este automat copiat in CE. Utilizatorul poate tipari text
direct in CE. Daca textul se potriveste cu un art din lista, art este automat pus pe video invers si se executa scroll-ul .
Un CB drop-down (stil CBS_DROPDOWN) difera de un CB simplu prin aceea ca lista este afisata numai la
cererea utilizatorului si nu permite introducerea de text in CE asociat.
Un CB drop-down list (stil CBS_DROPDOWNLIST) are in plus fata de CB drop-down bara de navigare verticala.
Stilurile se dau in functia Create or CreateEx . Alte stiluri exista pentru cosmetizarea CB. Cind cream un CB
trebuie sa punem stilul WS_VSCROLL daca dorim scroll vertical . Daca m_wndComboBox este un obiect
CComboBox, instructiunea:
m_wndComboBox.Create (WS_CHILD WS_VISIBLE WS_BORDER
WS_VSCROLL CBS_DROPDOWNLIST CBS_SORT, rect, this,
IDC_COMBOBOX);
ceara un CB drop-down list care contine bara pt. scroll vertical. Dimensiunea controlului (dreptunghiul) trebuie sa
fie destul de mare pt. a afisa tot textul.
Combo Box Styles
Style
CBS_AUTOHSCROLL
CBS_DISABLENOSCROLL
CBS_DROPDOWN
CBS_DROPDOWNLIST

Description
Enables horizontal scrolling in the edit control portion of a combo
box.
Disables the combo box list box's scroll bar when it isn't needed.
Without this style, an unneeded scroll bar is hidden rather than
disabled.
Creates a drop-down combo box.
Creates a drop-down list combo box.

CBS_HASSTRINGS
CBS_LOWERCASE
CBS_NOINTEGRALHEIGHT
CBS_OEMCONVERT

CBS_OWNERDRAWFIXED
CBS_OWNERDRAWVARIABLE
CBS_SIMPLE
CBS_SORT
CBS_UPPERCASE

Creates a combo box that "remembers" the strings added to it.


Conventional combo boxes have this style by default; owner-draw
combo boxes don't.
Forces all text in the combo box to lowercase.
Prevents the combo box's list box height from having to be an exact
multiple of the item height.
A combo box whose edit control performs an ANSI-to-OEM-to-ANSI
conversion on all characters so that the application won't get
unexpected results if it performs an ANSI-to-OEM conversion of its
own. Obsolete.
Creates an owner-draw combo box whose items are all the same
height.
Creates an owner-draw combo box whose items can vary in height.
Creates a simple combo box.
Automatically sorts items as they are added.
Forces all text in the combo box to uppercase.

Exista asemanari intre fct din CE si LB.


Adaugare art se face cu CComboBox::AddString si CComboBox::InsertString.
Nr. max. de car. pt. CE al CB este setat cu CComboBox::LimitText. Fct. GetWindowText si SetWindowText lucreaza
pt. CE al CB.
Functii specifice: GetLBText, care regaseste textul unui art. identificat printr-un index 0-based.
GetLBTextLen, returneaza lung. unui art., in caractere;
ShowDropDown, afiseaza sau ascunde un CB drop-down list;
GetDroppedState, returneaza o valoare ce indica daca CB drop-down list este afisat.

Notificari Combo Box


Combo Box Notifications
Notification
CBN_DROPDOWN
Sent when the drop-down list is displayed.
CBN_CLOSEUP
Sent when the drop-down list is closed.
CBN_DBLCLK
Sent when an item is double-clicked.
CBN_SELCHANGE
Sent when the selection changes.
CBN_SELENDOK
Sent when a selection is made.
CBN_SELENDCANCEL
Sent when a selection is canceled.
CBN_EDITUPDATE
Sent when the text in the edit control is
about to change.
CBN_EDITCHANGE
Sent when the text in the edit control has
changed.
CBN_KILLFOCUS
Sent when the combo box loses the input
focus.
CBN_SETFOCUS
Sent when the combo box receives the
input focus.

Message-Macro Map

Sim
ple

ON_CBN_DROPDOWN

DropDown

Drop-Down
List

ON_CBN_CLOSEUP

ON_CBN_DBLCLK

ON_CBN_SELCHANGE

ON_CBN_SELENDOK

ON_CBN_SELENDCANCEL
N_CBN_EDITUPDATE

ON_CBN_EDITCHANGE

ON_CBN_KILLFOCUS

ON_CBN_SETFOCUS

CBN_ERRSPACE
Sent when an operation fails because of
insufficient memory.

ON_CBN_ERRSPACE

Nu toate notificarile se aplica la toate tipurile de CB.


Notificarile CBN_DROPDOWN si CBN_CLOSEUP nu sunt trimise la un CB simpla (CBS_SIMPLE) pt. ca un
asemenea CB este deschis tot timpul.
CB cu stilurile CBS_DROPDOWN si CBS_DROPDOWNLIST-nu primesc notificarea CBN_DBLCLK pt. ca pe
art. din lista nu se poate face dublu clic. (LB asociat CB se inchide dupa primul clic).
Notificarile CBN_EDITUPDATE si CBN_EDITCHANGE sunt echivalente cu EN_UPDATE si EN_CHANGE
trime de CE, si CBN_SELCHANGE este la fel cu LBN_SELCHANGE pt. LB.
Cind procesam notificarea CBN_SELCHANGE, CE asociat poate sa nu fie actualizat cu selectia din LB asociat. Va
trebui sa folosim GetLBText pentru a regasi noul text selectat in loc de GetWindowText.
Indexul art. selectat il gasim cu CComboBox::GetCurSel.

Clasa CScrollBar
Clasa CScrollBar incapsuleaza controlul scroll bar creat din "SCROLLBAR" WNDCLASS. Controalele scroll bar
sunt identice in cea mai mare parte cu ferestrele scroll bar. In timp ce ferestrele scroll bars sunt create cu stilurile
WS_VSCROLL si WS_HSCROLL, controalele scroll bar sunt create explicit cu CScrollBar::Create. Barele scroll
window sint lipite de fereastra principala, controalele scroll bar pot fi plasate oriunde in fereastra si pot fi setate la
orice latime si inaltime.
Stil SBS_VERT pentru CSB vertical si SBS_HORZ pentru orizontal. Daca m_wndVScrollBar si m_wndHScrollBar
sunt obiecte CScrollBar instructiunile:
m_wndVScrollBar.Create (WS_CHILD WS_VISIBLE WS_BORDER
SBS_VERT, rectVert, this, IDC_VSCROLLBAR);
m_wndHScrollBar.Create (WS_CHILD WS_VISIBLE WS_BORDER
SBS_HORZ, rectHorz, this, IDC_HSCROLLBAR);
creaza doua controale CSB, unul vertical si unul orizontal.
Obtinerea dim. standard folosite de W se obtin printr-un apel al fct. API ::GetSystemMetrics.
int nWidth = ::GetSystemMetrics (SM_CXVSCROLL);
int nHeight = ::GetSystemMetrics (SM_CYHSCROLL);

Status Bars i Toolbars


(Bara de stare i de instrumente)
Lucrul cu barele de instrumente (Toolbars)

Butoanele de pe toolbar corespund la comenzi, la fel ca articolele dintr-un meniu. n general butoanele din toolbar
sunt duplicate pentru comenzi din meniu (shortcut-uri). Bara de instrumente poate fi adugat cu AppWizard.
AppWizard creaz bara de instrumente pentru cele mai utilizate comenzi din File, Edit i Help. Rmne n sarcina
noastr s modificm bara de instrumente dup cum dorim.
Fiecare buton de pe bara de instrumente are un ID care-l identific. Pe baza acestui ID vom ataa o comand pentru
buton.

tergerea butoanelor din bara de instrumente


Vom exemplifica cele ce urmeaz pe baza unei aplicaii, numit Tool, cu arhitectura Document/View i de tip MDI.
AppWizard furnizeaz o bar de instrumente docking (bara de instrumente nu este fix, poate fi mutat oriunde n
zona client, arat ca o palet plutitoare) implicit pentru aceast aplicaie. Aceast funcionalitate este dat de
AppWizard i MFC.
Pentru a terge un buton din toolbar procedm n felul urmtor:
1. selectm pagina (tab) Resource View
2. expandm Tool Resources pentru a vedea resursele aplicaiei
3. selectm Toolbar
4. dublu clic pe IDR_MAINFRAME pentru a-l edita.
5. tergerea unui buton se face prin tragerea butonului respectiv din aceast list (clic pe buton, se ine butonul
stng al mouse-ului apsat i se trage butonul in afara toolbar-ului i apoi eliberarea butonului).

Adugarea de butoane la Toolbar


Adugarea se face n doi pai:
1. se deseneaz icoana butonului selectnd butonul alb (blank) din toolbar; desenarea se face folosind
instrumentele puse la dispoziie de mediul de programare.
2. se ataeaz o comand noului buton adugat; se selecteaz Properties pentru acest nou buton i vom indica Id-ul
acestui buton (ID_CIRCLE n acest caz).

Descriere i ToolTip
n continuare vom (defini) ataa descrierea butonului i a ToolTip-ului. Descrierea apare n bara de stare, iar
ToolTip-ul apare cnd mouse-ul rmne deasupra butonului pentru o secund sau dou. Aceste dou iruri de
caractere le vom introduce n boxa de editare Prompt: mai nti irul pentru descrierea butonului i apoi separat cu
newline (\n) irul pentru ToolTip.

Adugare comand pentru buton


Se disting dou situaii:
1. butonul din toolbar are un articol de meniu corespunztor, adic selectarea butonului sau a articolului de meniu
are acelai efect;
2. butonul din toolbar nu are un articol de meniu corespunztor.
n primul caz vom alege acelai ID pentru buton ca i pentru comanda din meniu. Se presupune c pentru comenzile
din meniu am scris codul.
n cel de-al doilea caz vom proceda n felul urmtor:

1. Selectm butonul pentru care dorim s crem tratarea mesajului i apoi deschidem
ClassWizard.

2. Din foia de proprieti care apare, cu ID-ul butonului selectat, selectm in boxa Class
Name, clasa la care vom aduga funcia, n mod obinuit clasa pentru vizualizare
(derivat din CView sau alte clase din aceast ierarhie).
3. Executm dublu clic pe COMMAND din boxa Messages.
4. Acceptm numele funciei propus de MFC i apoi editm codul.
Observaie: Dac nu se definete nici o comand pentru un buton din toolbar atunci
MFC l va face disabled n timpul execuiei. Acelai lucru este valabil i pentru o
comand din meniu.
Se va exersa acest lucru la calculator.
Un rspuns posibil pentru butonul cu ID-ul ID_CIRCLE.

Listing CToolView::OnCircle()
void CToolView::OnCircle()
{
CClientDC clientDC(this);
CBrush newBrush(RGB(255,0,0));
CBrush* oldBrush = clientDC.SelectObject(&newBrush);
clientDC.Ellipse(20, 20, 200, 200);
clientDC.SelectObject(oldBrush);
}
Recapitulare: Evidenierea folosirii pensoanelor (clasa CBrush). Ce nseamn contextul de dispozitiv? Cum se
folosete? Rolul funciei SelectObject(). Alte ntrebri legate de contextul de dispozitiv.

Funciile membre ale clasei CToolBar


Dac dorim s schimbm comportarea toolbar-ului sau forma sa de afiare, vom folosi funciile din clasa CToolBar.
Toolbar-ul este accesibil din clasa CMainFrame, acolo fiind definit i variabila m_wndToolBarde tip CToolBar. n
general schimbarea comportrii toolbar-ului se face n funcia CMainFrame::OnCreate().

Funciile membru ale clasei CToolBar


Function
CommandToIndex()
Create()
GetButtonInfo()
GetButtonStyle()
GetButtonText()
GetItemID()
GetItemRect()
GetToolBarCtrl()
LoadBitmap()
LoadToolBar()
SetBitmap()
SetButtonInfo()
SetButtons()
SetButtonStyle()

Description
Obtains the index of a button, given its ID
Creates the toolbar
Obtains information about a button
Obtains a button's style
Obtains a button's text label
Obtains the ID of a button, given its index
Obtains an item's display rectangle, given its index
Obtains a reference to the CToolBarCtrl object represented by the CToolBar object
Loads the toolbar's button images
Loads a toolbar resource
Sets a new toolbar button bitmap
Sets a button's ID, style, and image number
Sets the IDs for the toolbar buttons
Sets a button's style

SetButtonText()
SetHeight()
SetSizes()

Sets a button's text label


Sets the toolbar's height
Sets the button sizes

Lucrul cu bara de stare (Status Bars)


Bara de stare const n afiarea unui text ce descrie comanda ce urmeaz a fi selectat. De asemenea bara de stare
conine starea unor taste (CAPS, NUM Lock, etc.). Comportamentul barei de stare este ncapsulat n clasa
CStatusBar. O bar de stare este asemntoare cu toolbar-ul. Se creaz n CMainFrame::Create().

Metodele clasei CStatusBar


Method
CommandToIndex()
Create()
GetItemID()
GetItemRect()
GetPaneInfo()
GetPaneStyle()
GetPaneText()
GetStatusBarCtrl()
SetIndicators()
SetPaneInfo()
SetPaneStyle()
SetPaneText()

Description
Obtains an indicator's index, given its ID
Creates the status bar
Obtains an indicator's ID, given its index
Obtains an item's display rectangle, given its index
Obtains information about an indicator
Obtains an indicator's style
Obtains an indicator's text
Obtains a reference to the CStatusBarCtrl object represented by the CStatusBar object
Sets the indicators' IDs
Sets the indicators' IDs, widths, and styles
Sets an indicator's style
Sets an indicator's text

Bara de stare conine mai multe pri, numite panes, care afieaz informaii despre starea aplicaiei i a sistemului.
Metoda cea mai folosit pentru a personaliza bara de stare, este de aduga noi pri. Pentru a face acest lucru
procedm astfel:

1. Crem un ID pentru o comand pentru noul pane.


2. Crem un string implicit pentru acest pane.
3. Adugm comanda ID a pane-ului la tabloul (array) indicatorilor barei de stare.
4. Crem funcia corespunztoare pentru acest ID.
Explicm aceste lucruri n detaliu.

Crearea unui ID pentru o nou comand


Pentru a aduga un ID pentru o comand (definirea ID-ului) procedm astfel: View -> Resource Symbols -> New
Symbol i apoi tastm ID-ul in boxa Name, de ex. ID_MYNEWPANE, apoi OK i Close.

Crearea stringului implicit


Presupunem c am creat ID-ul. Pentru a defini stringul procedm astfel:
1. selectm Resource View (din panelul workspace)-> i apoi dublu clic pe resursa String Table pentru a o
deschide;
2. alegem Insert, New String pentru a deschide boxa de dialog String Properties.
3. tastm ID-ul, ID_MYNEWPANE n boxa ID (sau l alegem din lista drop-down) i apoi tastm textul
(stringul) in boxa Caption .

Adugarea Id-ului la tabloul (array) indicatorilor


MFC folosete un tablou de ID-uri pentru a determina ce paneluri s afieze. Acest tablou este pasat ca argument n
funcia membru a barei de stare SetIndicators(), care este apelat n funcia Create() din CMainFrame.

Listing MainFrm.cpp--The Indicator Array


static UINT indicators[] =
{
ID_SEPARATOR,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};

// status line indicator

Pentru a aduga noul pane, tastm ID-ul n acest vector n poziia n care vrem s apar panelul nou, urmat de
virgul dac nu este pe ultima poziie.

Listing MainFrm.cppVectorul indicatorilor dup adugare


static UINT indicators[] =
{
ID_SEPARATOR,
ID_MYNEWPANE,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};

// status line indicator


// ID adaugat

Crearea funciei pentru Update (CCmdUI)


MFC nu actualizeaz (enable) n mod automat noul pane adgat. Trebuie s crem o funcie pentru actualizarea
(enable) noului pane.
n mod normal se folosete ClassWizard pentru a trata mesajele, dar ClassWizard nu face nimic pentru bara de stare.
Va trebui s adgm manual intrrile n harta de mesaje, n fiierul .h i n n .cpp. Aceste modificri le vom face n
afara comentariilor speciale AFX_MSG_MAP folosite de ClassWizard.

Listing MainFrm.h--Message Map


// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
// NOTE - the ClassWizard will add and remove member functions here.
//
DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
afx_msg void OnUpdateMyNewPane(CCmdUI *pCmdUI);
DECLARE_MESSAGE_MAP()

Listing MainFrm.cpp--Message Map


BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
//
DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_UPDATE_COMMAND_UI(ID_MYNEWPANE, OnUpdateMyNewPane)
END_MESSAGE_MAP()

Listing CMainFrame::OnUpdateMyNewPane()
void CMainFrame::OnUpdateMyNewPane(CCmdUI *pCmdUI)
{
pCmdUI->Enable();
pCmdUI->SetText(m_paneString);
}
m_paneString conine stringul (este de tip CString).

Modificarea stringului pentru m_paneString


Se adaug data membru la clasa CMainFrame:
private:
CString m_paneString;
Prima varianta:
Se iniializeaz aceast variabil n constructorul clasei CMainFrame:
m_paneString = "Default string";
Pentru a afia bara de stare pentru prima dat, se adaug urmtoarele linii de cod n CMainFrame::OnCreate(),
nainte instruciunea return:
CClientDC dc(this);
SIZE size = dc.GetTextExtent(m_paneString);
int index = m_wndStatusBar.CommandToIndex(ID_MYNEWPANE);
m_wndStatusBar.SetPaneInfo(index,ID_MYNEWPANE, SBPS_POPOUT, size.cx);
Acest cod seteaz stringul i mrimea panelului. Setarea mrimii panelului se face printr-un apel la funcia
SetPaneInfo(), care are nevoie de indexul panelului, ID-ul, stilul de afiare i mrimea acestui panel.
CommandToIndex() obine indexul panelului avnd ca parametru ID-ul panelului. i GetTextExtent() obine
mrimea, calculat conform fontului utilizat, mrimii caracterelor i lungimii irului m_paneString.
A doua variant:
Adugarea unei opiuni n meniu pentru modificarea coninutului variabilei m_paneString. De obicei se creaz o
box de dialog n care se preia noua valoare. Acest lucru implic adugarea unei opiuni de meniu i tratarea acesteia
(scrierea codului pentru funcie). De asemenea implic crearea unei boxe de dialog. Se vor explica n detaliu aceste
lucruri.
Cod posibil:

Listing CMainFrame::OnFileChangestring()
void CMainFrame::OnFileChangestring()
{
CPaneDlg dialog(this);
dialog.m_paneString = m_paneString;
int result = dialog.DoModal();
if (result == IDOK)
{
m_paneString = dialog.m_paneString;
CClientDC dc(this);
SIZE size = dc.GetTextExtent(m_paneString);
int index = m_wndStatusBar.CommandToIndex(ID_MYNEWPANE);

m_wndStatusBar.SetPaneInfo(index,
ID_MYNEWPANE, SBPS_POPOUT, size.cx);
}

De observat asemnarea codului cu cel din prima variant.

Lucrul cu Rebar
Rebar sunt toolbar-uri care conin alte controale dect butoanele toolbar.
Ca exemplificare vom aduga un check box care este reprezentat de clasa CButton.
Etape:
n CMainFrame (.h) adugm:
public:
CReBar m_rebar;
CButton m_check;
n CMainFrame::Create() adugm la sfrit urmtoarele linii:
if (!m_rebar.Create(this) )
{
TRACE0("Failed to create rebar\n");
return -1;
// fail to create
}
Controlul check box are nevoie de un ID.
Selectm View->Resource Symbols->New i tastm IDC_CHECK. Acceptm aceast alegere. Se adaug astfel o
linie n resource.h i aceast resurs nu poate fi utilizat i de alte controale.
Din nou n CMainFrame::OnCreate(), adugm urmtoarele linii pentru a crea check box-ul:
if (!m_check.Create("Check Here",
WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX,
CRect(0,0,20,20), this, IDC_CHECK) )
{
TRACE0("Failed to create checkbox\n");
return -1;
// fail to create
}
n final, se adaug acest control la rebar:
m_rebar.AddBar(&m_check, "On The Bar", NULL,
RBBS_BREAK | RBBS_GRIPPERALWAYS);
AddBar() are patru parametri: un pointer la controlul care va fi adugat, textul afiat alturi de control, un pointer la
un bitmap pentru a fi folosit pentru imaginea background-ului pe rebar i stilul rebar-ului.
Alte stiluri sunt:

RBBS_BREAK puts the band on a new line, even if there's room for it at the end of an existing line.
RBBS_CHILDEDGE puts the band against a child window of the frame.

RBBS_FIXEDBMP prevents moving the bitmap if the band is resized by the user.
RBBS_FIXEDSIZE prevents the user from resizing the band.
RBBS_GRIPPERALWAYS guarantees sizing wrinkles are present.
RBBS_HIDDEN hides the band.
RBBS_NOGRIPPER suppresses sizing wrinkles.
RBBS_NOVERT hides the band when the rebar is vertical.
RBBS_VARIABLEHEIGHT enables the band to be resized by the rebar.

n acest moment aplicaia funcioneaz dar nu se ntpl nimic la selecie sau deselecie check box.
Pentru ca aplicaia s reacioneze la clic pe check box trebuie s prindem mesajul i s-l tratm. Cel mai simplu mod
pentru a face acest lucru este s schimbm ceea ce se deseaneaz n OnDraw() din vizualizare. Adugm la clasa
vizualizare tratarea mesajului care apare cnd se face clic pe acest buton. Adugarea se face manual ca la bara de
stare, n afara codului generat de ClassWizard:
nainte de DECLARE_MESSAGE_MAP, adugm:
afx_msg void OnClick();
Adugm funcia la clasa vizualizare:
void CRebarView::OnClick()
{
Invalidate();
}
Aceasta va apela OnDraw().
n harta de mesaje adugm (tot n afara codului generat de ClassWizard):
ON_BN_CLICKED(IDC_CHECK, OnClick)
La nceputul fiierului adugm:
#include "mainFrm.h"
n OnDraw() adugm:
CString message;
if ( ((CMainFrame*)(AfxGetApp()->m_pMainWnd))->m_check.GetCheck())
message = "The box is checked";
else
message = "The box is not checked";
pDC->TextOut(20,20,message);