Sunteți pe pagina 1din 31

Programare orientat obiect

Lucrare laborator 7
APLICAII SDI, LIST, MDI
1. Crearea unei aplicaii SDI
Vom dezvolta o aplicaie referitoare la afiarea unui teanc de cri. Opiunile de meniu
vor permite adugarea sau nlturarea unei cri din teanc. Datele sunt de fapt numrul de cri,
sunt reinute n clasa document, fiind accesate de clasa reprezentare n scopul afirii teancului.
Realizarea unei aplicaii SDI cu AppWizard, va cuprinde urmtorii pai:
Se va selecta New din meniul File, i n cadrul paginii Projects a casetei de dialog
New, se va selecta MFC AppWizard (exe);
Se specific un nume pentru proiect (Cri), i se d clic pe OK;
n caseta de dialog MFC AppWizard Step1, se selecteaz butonul de opiune Single
Document, i se va asigura c opiunea Document/View Arhitecture Support? este
validat, i se d clic pe Next;
n caseta de dialog a pasului 2, se selecteaz butonul de opiune None, opiunile
prezentate aici se refer la diferitele tipuri de suport pentru bazele de date, nefiind
necesare pentru exemplul considerat, i se alege Next pentru a trece la pasul urmtor;
la pasul trei, se va selecta opiunea None i se valideaz opiunea
ActiveXControls. Celelalte opiuni din fereastr privesc adugarea unor faciliti
de automatizare OLE care nu sunt necesare pentru exemplul nostru, dup care se
selecteaz Next;
n caseta de dialog a pasului patru, se vor valida urmtoarele opiuni: Docking
Toolbar, Initial Status Bar, Printing and Print Preview i 3D
Controls. Se va selecta butonul de opiune normal pentru stilul de bar cu
instrumente, apoi se d clic pe Next;
n pasul cinci, se selecteaz MFC Standard ca stil al proiectului, i se alege Yes
pentru a genera comentarii n fiierele surs i selectai As a Shared DLL pentru
a indica modul de utilizare a bibliotecii MFC, apoi se efectueaz clic pe Next;
n caseta de dialog a pasului 6, se alege Finish, i se va afia caseta de dialog New
Project Information, care conine informaii utile privind clasele generate i numele
fiierelor surs. Tot aici se poate confirma lista de faciliti, prin darea unui clic pe
OK, i n acest moment ar trebui s fie creat
i deschis noul proiect.
Acceptarea opiunilor implicite din pasul 4 al
procesului de creare a unei aplicaii SDI cu AppWizard,
conduce la o aplicaie avnd o bar de titlu cu butoane
de maximizare/minimizare i nchidere, un meniu
derulant ce include opiuni pentru tiprire i
previzualizare, o bar cu instrumente i o bar de
stare. Unele dintre aceste elemente sunt ns opionale.
Prin efectuarea unui clic pe butonul Advanced
din aceast caset de dialog sunt oferite i alte opiuni,
care permit personalizarea stilului ferestrei cadru.
Zona client a ferestrei cadru nu este folosit pentru a implementa reprezentarea, ea avnd
o fereastr proprie, care este o fereastr copil a ferestrei cadru, lipsit de margine i de meniu.
Aceast fereastr a reprezentrii acoper ntreaga zon client a ferestrei cadru.
Elementele vizuale ale unei aplicaii SDI sunt:
5
143

Programare orientat obiect

CMainFrame
2 CToolbar
3 CSDIcartiView
4 CStatus Bar
5 Fereastra reprezentarii

Toate aceste elemente sunt mbinate i gestionate prin intermediul unei clase machet de
document.
Clasa machet de document utilizat de aplicaiile cu interfa de tip
document singular, este CSingleDocTemplate. O instan a acestei clase este creat i
folosit n funcia CSDICartiApp::InitInstance (listingul de mai jos):
BOOL CSDICartiApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)

144

Programare orientat obiect

// Register the application's document templates. Document templates


// serve as the connection between documents, frame windows and
views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSDICartiDoc),
RUNTIME_CLASS(CMainFrame),
// main SDI frame window
RUNTIME_CLASS(CSDICartiView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BOOL CSDICartiApp::InitInstance() este apelat de MFC la nceputul
execuiei programului;
IDR_MAINFRAME macheta de document este iniializat pe baza
identificatorului de resurs i a claselor document, cadru i reprezentare;
ParseCommandLine(cmdInfo); sunt analizai parametrii din linia de
comand
if (!ProcessShellCommand(cmdInfo)) prelucrm parametrii din linia de
comand i crem un nou document sau deschidem un fiier.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow(); se afieaz i actualizeaz fereastra
principal a aplicaiei.
n linia pDocTemplate = new CsingleDocTemplate (este creat un obiect
CSingleDocTemplate, fiind transmii patru parametrii. Primul parametru este
identificatorul de resurs IDR_MAINFRAME, n exemplul nostru, IDR_MAINFRAME
identific patru resurse distincte: pictograma aplicaiei, un meniu, o bar cu instrumente i o
tabel de acceleratori. Urmtorii trei parametrii sunt toi pointeri la informaii de clas
dinamice pentru clasele document, cadru i respectiv reprezentare. Pointerii sunt generai cu
ajutorul macrodefiniiei RUNTIME_CLASS, acest lucru este posibil, din cauz c, AppWizard
a prevzut suport pentru crearea dinamic a acestor clase, incluznd macrodefiniiile
DECLARE_DYNCREATE i IMPLEMENT_DYNCREATE.
Codul iniializeaz obiectul CSingleDocTemplate cu informaii necesare acestuia
pentru a putea s ncarce resursele i s aloce la cerere documente, reprezentri i clase. Obiectul

145

Programare orientat obiect

machet de document propriu-zis este reinut n clasa aplicaiei. Apelul funciei


AddDocTemplate nregistreaz obiectul machet de document nou creat n cadrul clasei
CWinApp. Aceast clas pstreaz obiectul CSingleDocTemplate pn cnd este distrus,
ceea ce se ntmpl doar la nchiderea aplicaiei. n cadrul acestui proces de distrugere, clasa
CWinApp elibereaz orice memorie alocat pentru macheta de document.
Dup crearea i iniializarea obiectului CSingleDocTemplate, are loc prelucrarea
parametrilor din linia de comand i apoi este afiat fereastra aplicaiei.
Clasa CCommandLineInfo ajut la tratarea parametrilor transmii aplicaiei prin
intermediul liniei de comand. Funcia CWinApp::ParseCommandLine primete ca
parametru o referin la obiectul CCommandLineInfo. Pentru fiecare parametru din linia de
comand este apelat funcia ParseParam, completndu-se variabilele membru ale obiectului
CCommandLineInfo din linia de comand :
nimic - se creeaz un nou document;
fiier - se deschide fiierul specificat;
/p fiier - se tiprete fiierul specificat la imprimanta implicit;
/p fiier - imprimant port - se tiprete fiierul specificat la imprimanta specificat;
/dde - ncepe o sesiune DDE;
/automation - lanseaz aplicaia ca server de automatizare OLE;
/embedding - lanseaz aplicaia pentru a edita un obiect OLE ncapsulat ntr-o alt
aplicaie.
n listingul anterior, se poate observa, c dac n linia de comand nu este transmis nici
un parametru, la lansarea aplicaiei este creat un nou document (aceasta se ntmpl n mod
implicit). Pe lng document, sunt create fereastra cadru i reprezentarea, ceea ce se ntmpl n
funcia: CWinApp::ProcessShellCommand.

Adugarea n document a variabilelor membru


Pentru a aduga n document variabile membru, se va trece la dezvoltarea exemplului
SDICarti. Ne vom ocupa mai nti de clasa CSDICartiDoc. Informaia necesar n aceast
clas este numrul curent de cri, care poate fi stocat ntr-o singur variabil membru. De
fiecare dat cnd clasa reprezentare trebuie s deseneze teancul de cri, va avea nevoie s
acceseze acest contor. Soluia cea mai simpl n acest sens ar fi o variabil membru public n
cadrul documentului care s rein contorul, permind accesul direct al clasei reprezentare.
Dezavantajul acestei abordri este faptul c devine posibil alterarea valorii contorului de ctre
codul clasei reprezentare, poate chiar accidental. Soluia preferat este folosirea unei variabile
membru protejate care s rein contorul, mpreun cu oferirea de ctre clasa document a unei
funcii de acces prin care clasa de reprezentare s poat obine valoarea contorului. Pentru
adugarea codului necesar se vor urma paii urmtori:
se va selecta clasa CSDICartiDoc din cadrul paginii ClassView, apoi se alege
Add Member Variable din meniul contextual;
se introduce o variabil de tip int, cu numele m_nCarti, i se va selecta butonul de
opiune protected Access, dup care se va efectua un clic pe OK;
se va alege apoi Add Member Function, i se va introduce o funcie de tip int cu
numele GetCartiCount, i se va selecta butonul Public Access;
se va introduce n corpul funciei urmtoarea linie de cod: return m_nCarti;

146

Programare orientat obiect

se apeleaz MessageMaps din ClassWizard, unde se va selecta CSDICartiDoc


n caseta combinat Class Name i se va selecta CSDICartiDoc n caseta cu list
Objectt IDs;
se va selecta DeleteContents din caseta cu list Messages, i se d clic pe Add
function, dup care se nchide ClassWizard;
dup comentariile TODO din funcia DeleteContents: m_nCarti = 1.
CSDICartiDoc conine n acest moment o variabil membru protejat, m_Carti care
este iniializat n funcia DeleteContents supradefinit,
i o variabil membru de acces
GetCartiCount, care va fi utilizat de ctre reprezentare pentru a determina valoarea
m_nCarti.
Pentru ca reprezentarea s poat extrage date ale documentului, ea trebuie s fie mai nti
capabil s acceseze obiectul document. Infrastructura MFC se ocup automat de acest aspect,
adugnd n clasa reprezentare a aplicaiei o funcie GetDocument, care ntoarce un pointer
ctre obiectul document la care reprezentarea a fost ataat prin intermediul machetei de
document. Clasa CSDICartiView conine o implementare GetDocument n
SDICartiView.cpp i o alta n SDICartiView.h, care fac exact acelai lucru, singura
diferen este c prima se folosete n versiunea de depanare a proiectului, n timp ce cea de-a
doua este utilizat n versiunea final. Motivul pentru aceast abordare este faptul c funciile
inline sunt mai eficiente, iar aceast funcie este probabil s fie apelat frecvent n timpul rulrii.
Clasa CSDICartiView este responsabil pentru afiarea teancului de cri. Codul care
se ocup efectiv de desenarea crilor este relativ simplu i se afl n funcia
CSDICartiView::OnDraw. AppWizard a creat deja un schelet al acestei funcii care se
poate folosi. Infrastructura MFC apeleaz funcia OnDraw de fiecare dat cnd reprezentarea
trebuie generat pe ecran. Funcia OnDraw este apelat, de asemenea, pentru a gestiona
operaiile necesare pentru tiprire i previzualizare. Contextul dispozitiv int transmis funciei
difer dup destinaia reprezentrii. Funcia CSDICartiView::OnDraw va avea urmtorul
cod:

void CSDICartiView::OnDraw(CDC* pDC)


{
CSDICartiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
// ** Salvam pensula curenta
CBrush* pOldBrush = pDC->GetCurrentBrush();
//** Cream o pensula plin de culoare galbena
CBrush br;
br.CreateSolidBrush (RGB (255, 255, 0));
//Selectam pensula galbena in contextul dispozitiv
pDC->SelectObject (&br);
// Obtinem de la document numarul de carti si
// desenam cate doua patrate care sa reprezinte fiecare cartea
for (int nCount = 0; nCount < pDoc->GetCartiCount(); nCount++);
{

147

Programare orientat obiect

int y = 200 - 10 * nCount;


pDC-> Rectangle (40,y, 100, y-30);
pDC->Rectangle (40, y-10, 100, y-35);
}
//** Refacem pensula curenta
pDC->SelectObject (pOldBrush);
}
Dup introducerea acestui cod, dac se va
executa aplicaia, pe ecran va trebui s apar urmtoarea
imagine:
La proiect sunt adugate automat meniul, bara cu
instrumente, o pictogram, o tabel de acceleratori i irul specific documentului.
Pentru exemplul considerat de noi, vom aduga dou opiuni de meniu, una care s
adauge o carte i cealalt s nlture o carte. La selectarea lor, aceste opiuni vor apela fiecare
cte o funcie a clasei document care va crete sau va scdea numrul de cri i va asigura
actualizarea reprezentrii. Pentru adugarea opiunilor de meniu se vor parcurge urmtorii pai:
n cadrul paginii ResourceView, se
expandeaz catalogul Menu i se efectueaz un
dublu clic pe IDR_MAINFRAME;
se va da clic pe elementul de meniu Edit, i se
va deschide un meniu derulant;
se va da dublu clic pe elementul gol de la baza
meniului derulant. Caseta de dialog Menu
Item Properties;
se va specifica un identificator pentru
elementul
de
meniu,
ID_EDIT_ADAUGA_CARTE;
se specific o etichet (Caption)
pentru elementul de meniu (Adaug o
carte).
se specific o explicaie (Prompt)
pentru elementul de meniu (Crete numrul de cri);
se efectueaz un dublu clic pe elementul gol de la baza meniului derulant;
se
specific
un
nou
identificator
pentru
elementul
de
meniu
ID_EDIT_STERGE_CARTE, i se va specifica o etichet terge o carte;
Se va specifica o explicaie pentru elementul de meniu, Scade numrul de cri;
Se apeleaz Message Maps din ClassWizard, se selecteaz SDICartiDoc n
caseta combinat Class Name, i ID_EDIT_ADAUGA_CARTE n caseta Objectt
IDs;
Se va selecta COMMAND n caseta cu list Messages dup care se alege Add
function, i se d clic pe OK de la Add Variable;
Analog se va proceda pentru ID_EDIT_STERGE_CARTE;
Se d clic pe Edit Code, i se va introduce urmtorul cod:
void CSDICartiDoc::OnEditAdaugaCarte()
{
// TODO: Add your command handler code here

148

Programare orientat obiect

//** Incrementam numarul de carti


m_nCarti++;
//**Actualizam reprezentarea pentru
// aredesena teancul de carti
UpdateAllViews (NULL);
}
void CSDICartiDoc::OnEditStergeCarte()
{
// TODO: Add your command handler code here
//** Decrementam numarul de carti
if (m_nCarti>0)
m_nCarti--;
//** Actualizam reprezentarea pentru a
// redesena teancul de carti
UpdateAllViews (NULL);
}
void CSDICartiDoc::OnEditAdaugaCarte()
{
// TODO: Add your command handler code here
//** Incrementam numarul de carti
m_nCarti++;
//**Actualizam reprezentarea pentru
// a redesena teancul de carti
UpdateAllViews (NULL);
}
void CSDICartiDoc::OnEditStergeCarte()
{
// TODO: Add your command handler code here
//** Decrementam numarul de carti
if (m_nCarti>0)
m_nCarti--;
//** Actualizam reprezentarea pentru a
// redesena teancul de carti
UpdateAllViews (NULL);
}
Valoarea NULL determin actualizarea tuturor reprezentrilor ataate la document.
Actualizarea fiecrei reprezentri se face prin apelul funciei OnUpdate a acesteia. Efectul
este invalidarea zonei client a ferestrei reprezentrii i apelarea funciei OnDraw.

149

Programare orientat obiect

2. Crearea i editarea resurselor de tip meniu


Adugarea unei noi resurse meniu, se realizeaz prin
selectarea paginii ResourceView, i efectuarea unui clic cu
butonul drept al mouse-ului pe elementul aflat la primul nivel i se
va selecta opiunea Insert din meniul afiat pentru a apela caseta
de dialog InsertResource, de unde se va selecta Menu, i se va da
clic pe New, n acest moment sub nodul Menu ar trebui s apar
noua machet de meniu.
Se poate sri peste aceste etape, folosind combinaia de taste
Ctrl+2, care insereaz o resurs meniu indiferent de unde v aflai
n Developer Studio. Dup apsarea acestor taste ar trebui s fie afiat pagina de resurse, cu
noul meniu selectat i afiat n fereastra de editare.
Pentru a afia proprietile meniului, se efectueaz clic cu butonul drept al mouse-ului pe
resursa meniu, i se selecteaz Properties, unde
se poate nlocui identificatorul de resurs implicit
cu un nume mai potrivit pentru meniu. Ca
alternativ, se poate expanda resursele
proiectului i se va efectua un clic pe butonul
drept pe nodul menu, ceea ce ofer posibilitatea
de a selecta opiunea Insert Menu pentru a
aduga o nou resurs meniu, dup care se poate
modifica identificatorul ca mai sus.Pentru a
insera un nou titlu de meniu, la unul deja existent
sau la o nou resurs de tip meniu, se va selecta n cadrul paginii ResourceView resursa
meniu dorit, i se selecteaz dreptunghiul gol afiat n dreapta titlurilor de meniu existente pe
bara de meniuri. Dreptunghiul va aprea selectat, n jurul lui fiind afiat un chenar alb. n acest
moment, se va tasta numele noului titlu de meniu, textul aprnd n interiorul dreptunghiului pe
msur ce se tasteaz, fiind afiat i o caset de dialog Menu Item Properties, iar sub noul titlu
de meniu va aprea o caset pentru un element de meniu.
Se vor selecta opiunile dorite pentru titlul de meniu, apoi se va apsa Enter pentru a
ncheia inserarea noului titlu de meniu, dup care se poate trage i plasa noul titlu de meniu n
orice poziie de pe bara de meniu, modificnd dup dorin ordinea titlurilor de meniu.
Pentru adugarea unui element de meniu n cadrul unui submeniu, se va efectua clic pe
titlul submeniului pentru a afia lista cu elementele coninute. Dreptunghiul va aprea selectat
prin afiarea unui chenar alb n jurul su. se va tasta numele noului element de meniu, textul
aprnd n interiorul dreptunghiului i se va
afia concomitent i caseta de dialog Menu
Item Properties. Se vor selecta opiunile
necesare pentru elementul de meniu, se va da
un clic pe Prompt, i se va putea specifica
textul care va aprea pe bara de stare la
selectarea acestei opiuni de meniu. Se poate
preciza i un al doilea ir, aflat n continuarea
primului i separat de el prin caracterul linie
nou /n, acesta fiind afiat ca explicaie
pentru butonul asociat de pe bara cu
instrumente.

150

Programare orientat obiect

Efectund un clic pe caseta de editare ID, va aprea un identificator de meniu implicit,


bazat pe elementul de meniu i pe titlul meniului care-l conine. Dac este necesar, se va nlocui
acest identificator implicit cu altul mai semnificativ. Odat realizat noul element se poate trage i
amplasa n orice poziie din cadrul meniului.
Un element de meniu poate fi ters prin selectarea acestuia i apsarea tastei Delete. Dac
se terge un titlu de meniu, vor fi terse toate elementele aflate n meniul respectiv, dup ce se
cere confirmarea.
Este posibil adugarea de separatori care s grupeze elementele de meniu prin trasarea
unor bare orizontale de-a latul casetei meniului, efectund un dublu clic pe dreptunghiul gol care
marcheaz un nou element pentru a afia caseta de dialog Menu Item Properties, i se va
alege caseta de validare Separator. La selectarea acestei proprieti, vor fi dezactivate toate
controalele, mai puin caseta Caption, care va fi golit de coninut. Pentru a nchide aceast
caset de dialog se va apsa Enter, iar separatorul va aprea ca o bar orizontal, putndu-l trage
i plasa n poziia dorit.
Se pot crea elemente de
submeniu, dac se efectueaz un clic pe
caseta de validare Pop-Up din caseta
de proprieti, astfel, cmpul ID va fi
voalat, iar n dreapta elementului de
meniu va fi afiat o mic sgeat
orientat spre dreapta, indicnd un alt
dreptunghi gol de inserare.
Elementele de meniu pot fi
nsoite de marcaje de validare care
sunt afiate n partea stng a acestora, i pot fi manipulate prin cod i prin intermediul editorului
de resurse, pot fi afiate implicit alturi de un element de meniu la apariia iniial a acestuia.
Pentru determinarea afirii implicite a unui marcaj de validare, se selecteaz proprietatea
Checked din caseta de proprieti pentru fiecare element de meniu care se dorete a fi afiat
iniial mpreun cu marcajul de validare.
De asemenea, pentru elementele de meniu se pot defini taste de acces care s permit
utilizatorului selectarea unui element prin apsarea tastei de acces asociate.
Odat creat un nou meniu, exist posibilitatea de a aduga o funcie de tratare, prin
intermediul lui ClassWizard,
avnd grij ca n caseta combinat
Class Name s fie nfiat clasa
destinaie pentru noua funcie de
tratare, dup care va alege mesajul
COMMAND din caseta cu list
Messages pentru a apela caseta de
dialog Add Member Function,
iar dup adugarea variabilei, se
va edita codul specific aplicaiei.
De
exemplu,
pentru
introducerea unui mesaj, se va
introduce urmtorul cod:
void
CSDIMenuDoc::OnMyheaderSubmenu()
{
// TODO: Add your command handler code here

151

Programare orientat obiect

AfxMessageBox ("Puteti introduce primul submeniu");


}
Funciile care trateaz interfaa cu utilizatorul sunt responsabile de aspectul, stilul i
comportamentul fiecrui element de meniu. nainte de afiarea unui meniu sunt apelate funciile
corespunztoare de tratare a interfeei cu utilizatorul, aplicaia avnd astfel posibilitatea de a
activa sau dezactiva elementele de meniu, de a aduga sau nltura marcaje de validare sau de a
modifica etichetele opiunilor.
Atributele referitoare la interfaa cu utilizatorul, pot fi modificate prin apelul funciilor de
acces ale unui obiect CCmdUI asociat cu un element de meniu. La orice apelare a unei funcii
de tratare a interfeei cu utilizatorul (UI-user interface), acesteia i va fi transmis un pointer la un
obiect CCmdUI.
De exemplu, funcia de tratare UI de activare a unui element din meniu este Enable () a
obiectului CCmdUI, iar pentru adugarea unei funcii de tratare a unei comenzi din meniu, se
va selecta mesajul UPDATE_COMMAND_UI. Funcia de tratare UI de mai jos activeaz un
element de meniu pentru a permite selectarea acestuia de ctre utilizator, este apelat funcia
Enable () a obiectului CCmdUI:
void CSDIMenuDoc::OnUpdateMyheaderSubmenu(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable (TRUE);
}
La transmiterea valorii TRUE la apelul funciei, meniul va fi activat, n caz contrar
opiunea de meniu va fi dezactivat i afiat voalat. Starea de activare se poate reine prin
intermediul unei variabile membru a clasei, avnd tip boolean, i transmind-o apoi funciei
Enable () a obiectului CCmdUI n cadrul funciei de tratare UI, ca mai jos:
pCmdUI->Enable (m_bMySubItemEnableStatus);
Afiarea sau nlturarea unui marcaj de validare
Prezena marcajului de validare poate fi stabilit prin apelul funciei SetCheck () a
obiectului CCmdUI, transmind valoarea zero pentru nlturarea marcajului sau valoarea unu
pentru afiarea acestuia.
Pentru implementarea unui comutator simplu prin intermediul unui element de meniu,
care s permit utilizatorului s comute afiarea marcajului de validare prin selectarea
elementului respectiv, se poate opta pentru urmtoarea implementare:
void CSDIMenuDoc::OnMyheaderSubmenu()
{
// TODO: Add your command handler code here
m_nToggleState =m_nToggleState ==0 ? 1 : 0;
}
void CSDIMenuDoc::OnUpdateMyheaderSubmenu(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
// ** Activam elementul de meniu

152

Programare orientat obiect

pCmdUI->Enable (TRUE);
//** Stabilim starea de comutare
pCmdUI->SetCheck (m_nToggleState);
}
Variabila membru care apare este definit n cadrul clasei ca un ntreg: int
m_nToggleState.
Funciile de tratare UI pot fi utilizate i pentru modificarea etichetei unui element de
meniu, transmind o nou etichet funciei SetText () a obiectului CCmdUI. Eticheta
meniului va fi nlocuit de noul ir de caractere, fiind luate n considerare i eventualele taste de
acces specificate prin intermediul simbolului ampersand &.
Pentru modificarea etichetei elementului de meniu din exemplul de comutator, pentru a
afia On sau Off n funcie de starea de comutare, se va aduga la sfritul funciei de tratare UI
urmtoarea linie de cod:
PCmdUI->SetText (m_nToggleState?&On:O&ff);
Operatorul condiional inlinie? Este utilizat pentru a transmite unul din dou iruri de
caractere, n funcie de valoarea m_nToggleState.
Implementarea meniurilor de context
n aplicaii implementarea meniurilor de context se poate face prin crearea unei funcii de
tratare a mesajului WM_CONTEXTMENU din Windows, acesta fiind transmis unei aplicaii n
momentul n care se efectueaz un clic cu butonul drept al mouse-ului undeva n fereastra
aplicaiei. n cadrul funciei de tratare se va ncrca resursa meniu corespunztoare i se va
deschide meniul de context prin apelul funciei TrackPopupMenu ().
Pentru apelarea unui meniu de context se va aduga funcia de tratare a mesajului
WM_CONTEXTMENU, dup care se va aduga propriul cod la implementarea standard.
Pentru afiarea meniului de context trebuie declarat mai nti un obiect CMenu care s
implementeze respectivul meniu (clasa CMenu este o clas MFC de ncapsulare care permite
ntreinerea i accesarea unui obiect HMENU din Windows). Noul obiect poate fi iniializat cu
resursa de meniu corespunztoare, apelnd funcia LoadMenu () a acestuia i transmind
identificatorul resursei meniu, astfel obiectul CMenu va fi iniializat cu titlul de meniu al
resursei. Pentru afiarea meniului de context, ns, este nevoie de elementele subordonate
respectivului titlu de meniu, n acest scop va fi apelat funcia GetSubMenu (), transmind
valoarea zero pentru a solicita primul element subordonat.
Pe baza meniului obinut, se poate apela funcia TrackPopupMenu () care afieaz
i controleaz meniul de context. Aceast funcie ateapt un numr de patru parametrii, primul
este un indicator de aliniere care specific unde va fi afiat meniul relativ la poziia precizat.
Indicatorii de aliniere pentru aceast funcie sunt:
TPM_LEFTALIGN - aliniaz meniul astfel nct poziia specificat s se afle n
partea stng;
TPM_RIGHTALIGN - aliniaz meniul astfel nct poziia specificat s se afle n
partea dreapt;
TPM_ TOPALIGN - aliniaz meniul astfel nct poziia specificat s se afle
deasupra meniului;
TPM_BOTTOMALIGN - aliniaz meniul astfel nct poziia specificat s se afle
dedesuptul meniului;

153

Programare orientat obiect

TPM_CENTERALIGN - aliniaz meniul astfel nct poziia specificat s fie


centrat pe orizontal;
TPM_VCENTERALIGN - aliniaz meniul astfel nct poziia specificat s fie
centrat pe vertical;
TPM_HORIZONTAL - n cazul n care nu exist spaiu suficient pe ecran, alinierea
orizontal primeaz;
TPM_VERTICAL - n cazul n care nu exist spaiu suficient pe ecran, alinierea
vertical primeaz.
Al doilea i al treilea parametru precizeaz coordonatele pe orizontal i pe vertical ale
poziiei de afiare a meniului, unde se transmit de regul valorile point.x i point.y funciei
OnContextMenu (). Ultimul parametru este un pointer la obiectul fereastr, transmindu-se de
obicei operatorul this din C++ pe post de pointer la obiectul reprezentare curent.
De exemplu, se va implementa un meniu de context care permite utilizatorului s aleag
ntre opiunile: FA, BBV, MF, MK, IE, CIG, pornind de la o aplicaie SDI generat cu
AppWizard. Mai nti va trebui inserat o nou resurs de
meniu corespunztoare meniului de context.
La funcia de tratare pentru apelarea meniului de
context se va aduga urmtorul cod:

void CSDIMenuView::OnContextMenu(CWnd*
pWnd, CPoint point)
{
// TODO: Add your message handler code here
// ** Declaram un obiect CMenu
CMenu MenuPopup;
//** Initializam cu resursa meniu de context
MenuPopup.LoadMenu (IDR_MYCONTEXT);
//** Afisam si controlam noul meniu
MenuPopup.GetSubMenu (0)->TrackPopupMenu(TPM_LEFTALIGN,
point.y, this);
}

point.x,

Prin apelarea funciei TrackPopup Menu (), se specific c alinierea se face considernd
punctul de coordonate aflat n stnga i transmind poziia cursorului care a fost primit de
funcia de tratare a meniului de context.
Dup adugarea meniului de context se pot aduga funcii de tratare asociate elementelor
din acest meniu, exact ca i ntr-un meniu obinuit.
Dup inserarea noii resurse de meniu, ClassWizard afieaz la prima apelare caseta de
dialog Adding a Class pentru c a descoperit noua resurs, se poate ignora efectund clic pe
Cancel. Se poate utiliza ClassWizard pentru a aduga funcii de tratare asociate elementelor din
acest meniu, de exemplu, eu am realizat o afiare ntr-o caset de mesaj fiecare din opiunile din
meniul contextual odat cu selectarea vreunei opiuni, conform secvenei de cod de mai jos.
void CSDIMenuView::OnBbv()
{
// TODO: Add your command handler code here
AfxMessageBox ("BBV");
}

154

Programare orientat obiect

void CSDIMenuView::OnUpdateBbv(CCmdUI* pCmdUI)


{
// TODO: Add your command update UI handler code here
pCmdUI->Enable (TRUE);
}
Analog, se introduc pentru toate opiunile de meniu, n
final, la rularea aplicaiei, i la darea unui clic pe butonul
dreapta al mouse-ului oriunde n fereastra reprezentrii va
conduce la afiarea noului meniu de context.
La selectarea
corespunztor.

unei

opiuni,

va

apare

mesajul

Crearea i accesarea obiectelor meniu


Funciile de iniializare ntorc valoarea TRUE dac se
reuete iniializarea meniului, sau FALSE cnd nu este
iniializat:
ncrcarea unui meniu dintr-o resurs - se poate realiza cu ajutorul funciei
membru LoadMenu();
crearea de noi meniuri - CreateMenu () va crea dinamic o resurs meniu goal, fr
nici un element de meniu, la care se pot aduga elementele de meniu care s formeze
structura noului meniu; ca alternativ, se poate apela CreatePopupMenu() pentru a
crea un meniu derulant ce poate fi utilizat ca submeniu pentru un element sau ca
meniu de context;
ataarea la un meniu existent, se poate realiza prin apelarea la funcia Attach(), prin
transmiterea n apel a idicatorului HMENU ctre meniul n cauz. Acest indicator
poate fi obinut pe baza unui obiect CWnd (sau derivat din CView) asociat, prin
apelul funciei GetMenu() a respectivului obiect fereatsr. n momentul terminrii
manipulrii meniului, se poate detaa de obiectul CMenu apelnd funcia Detach().
Dup ce a fost iniializat obiectul CMenu, se poate aduga, nltura sau modifica
elemente de meniu pentru a ndeplini cerinele aplicaiei.
Adugarea ntr-un meniu a unui nou element de meniu se poate face prin apelarea
funciei AppendMenu() sau InsertMenu(), dup cum elementul de meniu trebuie adugat
la sfritul meniului sau inserat n meniu ntr-o anumit poziie.
Funcia AppendMenu() ateapt trei parametrii. Primul parametru necesar este un
indicator care specific tipul noului element de meniu i o combinaie de valori de stil. De obicei
se va transmite MF_STRING ca prim parametru, specificndu-se astfel c, noul element conine
un pointer la un ir obinuit de caractere, terminat cu caracterul nul (se pot folosi i obiecte
CString). Prin al doilea parametru, se poate transmite un identificator pentru mesajele de
comand sau un indicator HMENU al unui meniu derulant, n cazul n care a fost specificat
indicatorul MF_POPUP.
Prin al treilea parametru, se poate transmite un ir de caractere care va reprezenta eticheta
elementului de meniu (sau se poate lsa valoarea NULL implicit n cazul elementelor de tip
separator).
Este bine s se asigure c identificatorii de meniuri sunt unici i nu exist conflicte ntre
acetia.
Indicatorii pentru meniuri utilizai de ctre funciile AppendMenu () i
InsertMenu () sunt:

155

Programare orientat obiect

MF_CHECKED - stabilete indicatorul pentru marcaj de validare, avnd ca efect


afiarea unui marcaj de validare alturi de elementul de meniu;
MF_UNCHECKED - anuleaz indicatorul pentru marcaj de validare, al meniului
asociat;
MF_ENABLED - activeaz elementul de meniu;
MF_DISBLED - dezactiveaz elementul de meniu;
MF_GRAYED - identic cu anteriorul;
MF_POPUP - elementul de meniu are asociat un submeniu specificat de ctre
identificatorul transmis ca parametru;
MF_MENUBARBREAK - elementul de meniu va fi plasat pe o nou linie (sau pe o
nou coloan, n cazul meniurilor derulante, fiind separat printr-o linie vertical);
MF_MENUBREAK similar, cu indicatorul anterior, dar fr separarea prin linie
vertical.
Funcia alternativ InsertMenu () permite inserarea unui nou element de meniu ntr-o
poziie precis sau naintea unui element de meniu cu un identificator bine precizat. Dac poziia
este specificat prin index, se va transmite ca prim parametru respectivul index, pornind de la
zero, i se va aduga indicatorul MF_BYPOSITION printre indicatorii combinai n cadrul celui
de-al doilea parametru.
Pentru inserarea unui element de meniu nou, naintea altuia deja existent, avnd un
identificator cunoscut, se transmite acest identificator ca prim parametru i se va include
MF_BYCOMMAND printre indicatorii care formeaz al doilea parametru.
Ceilali trei parametrii sunt identici cu cei transmii funciei AppendMenu ().
De exemplu, pentru a crea dinamic un meniu derulant prin intermediul mai multor
indicatori de opiune se poate realiza urmtoarea secven de cod:

#define ID_MENU_ROSU 5001


#define ID_MENU_VERDE 5002
#define ID_MENU_ALBASTRU 5003
#define ID_MENU_GALBEN 5004
void CSDIMenuView::OnContextMenu(CWnd* pWnd, CPoint point)
{
// TODO: Add your message handler code here
// ** Declaram un obiect CMenu
CMenu MenuPopup;
// Cream resursa meniu
if (MenuPopup.CreatePopupMenu() )
{
//adaugam elemente de meniu simple
MenuPopup.AppendMenu
(MF_STRING,
"ROSU");

ID_MENU_ROSU,

// Inseram un element la inceputul meniului


MenuPopup.InsertMenu (0, MF_BYPOSITION | MF_STRING,
ID_MENU_VERDE, "&VERDE");
MenuPopup.AppendMenu (MF_SEPARATOR);
//Adaugam un element validat

156

Programare orientat obiect

MenuPopup.AppendMenu
(MF_STRING
ID_MENU_ALBASTRU, "&ALBASTRU");

|MF_CHECKED,

// MF_MENUBARBREAK
MenuPopup.AppendMenu (MF_STRING | MF_MENUBARBREAK,
ID_MENU_GALBEN, "&GALBEN");
MenuPopup.TrackPopupMenu (TPM_LEFTALIGN, point.x, point.y,
this);
}
Primele patru linii ale listingului, definesc valorile de identificatori pentru cele patru
elemente de meniu ce vor fi adugate. n linia CMenu MenuPopup; este declarat obiectul
MenuPopup de tip CMenu, fiind iniializat ca meniu derulant prin apelul funciei
CreatePopupMenu().
Funcia AppendMenu () ataeaz la meniu un nou
element, cu eticheta ROSU, iar funcia InsertMenu()
insereaz nainte de Rosu un alt element de meniu cu eticheta
VERDE. Elementul ALBASTRU este introdus cu un marcaj de
validare, iar elementul GALBEN, este afiat n dreapta liniei
separatoare.
Se pot crea funcii de tratare asociate elementelor de
meniu dinamice adugnd la sfritul hrii de mesaje a clasei
reprezentare intrri corespunztoare identificatorilor care au fost
definii.
ON_COMMAND (ID_MENU_GALBEN, OnGalben)
Liniile #define, pentru identificatori trebuie s se afle n cod naintea hrii de mesaje,
astfel nct compilatorul s poat recunoate aceti indicatori.
Funcia OnGalben () va fi apelat atunci cnd utilizatorul selecteaz opiunea de
meniu dinamic avnd identificatorul ID_MENU_GALBEN, iar implementarea funciei de
tratare a comenzii se face n mod normal.
Modificarea elementelor de meniu, n timp ce acestea sunt afiate sau reprezint obiecte
valide, apelnd n acest sens funcia ModifyMenu (), ce are patru parametrii.
Primul parametru necesar are acelai rol cu parametrul care specific poziia pentru
InsertMenu (). Dac se dorete specificarea poziiei prin index, se va transmite ca prim
parametru respectivul index pornind de la zero i se va aduga indicatorul MF_BYPOSITION
printre indicatorii transmii sub forma celui de-al doilea parametru. Pentru a modifica elementul
de meniu care are un anumit identificator ca prim parametru se va transmite acel identificator, i
se va include MF_BYCOMMAND printre indicatorii care formeaz al doilea parametru.
Prin cel de-al doilea parametru trebuie transmis o combinaie de indicatori care modific
starea elementului de meniu nlocuind combinaia curent. Opional, se poate transmite noul
identificator al meniului ca al treilea parametru (sau identificatorul curent pentru a-l lsa
neschimbat), iar prin cel de-al patrulea parametru se poate transmite un pointer la un ir de
caractere care va nlocui eticheta curent a elementului de meniu.
Elementele de meniu dintr-un obiect CMenu pot fi nlturate prin intermediul funciei
RemoveMenu (), aceasta primind doi parametrii, primul este identificatorul sau valoarea de
index prin care se precizeaz elementul de meniu care va fi nlturat, iar al doilea, trebuie s fie
unul dintre indicatorii MF_BYCOMMAND sau MF_BYPOSITION, specificnd modul n care
primul parametru indic poziia.

157

Programare orientat obiect

3. Crearea unei infrastructuri SDI cu reprezentare de tip list


Crearea unei astfel de infrastructuri se efectueaz printr-un clic pe meniul File i se
selecteaz New;
se va selecta pagina Projects, din care se alege MFC AppWizard(exe);
se va da un nume proiectului ListV;
se va alege opiunea Single document, i se va da Next, pn la caseta de dialog ce
arat steagul caroiat;
se va da clic pe clasa CListView din lista claselor create de AppWizard;
va fi activat caseta combinat BaseClase, i se va apsa clic pe sgeata de
derulare pentru a deschide lista cu clasele de baz posibile pentru clasa reprezentare;
se va selecta CListView ca i clas de reprezentare, apoi se va alege Finish;
se va da clic pe OK, iar AppWizard va crea noul proiect i fiierele sale surs.
n acest moment, este la dispoziie un schelet de aplicaie SDI a crei clas reprezentare
este derivat din CListView, putndu-se asambla i rula aplicaia n acest moment, dar
deoarece n controlul list nu a fost nscris nici un element, nu se va observa nimic n plus, fa
de o aplicaie SDI cu reprezentare de tip CView. Pentru a afia ceva, va trebui s se insereze
elemente n cadrul liste.
Inserarea de elemente
Locul adecvat pentru a pstra o list de elemente este clasa CListVDoc, derivat din
CDocument. Se vor alctui ca date o list de iruri, acestea vor fi nume de localiti. MFC
pune la dispoziie o clas CStringList potrivit acestui scop.
Adugarea n document a datelor se va face prin urmtorii pai:
se selecteaz ClassView din seciunea spaiului de lucru;
se deschid clasele proiectului ListV pentru a putea vedea clasa CListVDoc;
se apeleaz meniul de context al acestei clase, de unde se selecteaz opiunea Add
Member Variable, i se va introduce o variabil de tip CStringList, cu
numele m_listElemente;
se va selecta opiunea Private Access.
n acest moment, exist un obiect list de iruri ncapsulat n clasa document. S-a optat
pentru accesul privat, pentru ca aceasta s fie modificat direct numai de ctre funciile membru
ale clasei document, prevenindu-se astfel, accidentele determinate de modificarea inadecvat a
acestei variabile list de ctre funcii membru ale altor clase. Un acces de tip public, ar
presupune c variabila ar putea fi accesat de orice alt clas.
Aa cum a fost creat variabila membru, ea nu poate fi accesat din exteriorul
documentului, astfel pentru a nscrie n reprezentarea de tip list coninutul listei de iruri din
cadrul documentului, va trebui apelat o funcie de acces. Sarcina unei funcii de acces este s
ofere un acces sigur la o variabil membru privat.
n document, se va aduga o astfel de funcie de tip const CstringList& i cu
declaraia GetElements (), dup care se va aduga linia
return m_listElemente;

158

Programare orientat obiect

Deoarece funcia ntoarce o valoare de tipul precizat, orice funcie care va accesa lista de
iruri din afara documentului va putea exclusiv s-o citeasc. Accesul exclusiv la citire se
datoreaz cuvntului cheie const, care nseamn c, clasa reprezentare poate s acceseze lista,
dar nu poate s-o modifice.
Pentru a testa reprezentarea de tip list, este nevoie de nite date, care se vor introduce n
constructorul clasei document. Pentru a edita constructorul clasei document, se va efectua un
dublu clic pe funcia membru CLIstVDoc din clasa CListVDoc, i se vor aduga elementele
de test:
CListVDoc::CListVDoc()
{
// TODO: add one-time construction code here
// Adaugam elemente in lista de siruri
m_listElemente.AddTail ("Arad");
m_listElemente.AddTail ("Bucuresti");
m_listElemente.AddTail ("Cluj");
m_listElemente.AddTail ("Craiova");
m_listElemente.AddTail ("Iasi");
m_listElemente.AddTail ("Timisoara");
}
n listingul anterior, se adaug diferite elemente n lista m_listElemente transmind
iruri de caractere funciei membru AddTail () a obiectului CStringList, funcie care
adaug irul specificat la coada listei existente.
n continuare, trebuie ncrcate aceste date de test n reprezentarea de tip list la prima
afiare a acesteia. Singura posibilitate de accesare a listei de iruri din cadrul reprezentrii este
funcia GetElements(), aa c va trebui utilizat n metoda OnInitialUpdate() a clasei
reprezentare. OnInitialUpdate () este apelat o singur dat, la prima afiare a reprezentrii.
Pentru a fi accesat se va selecta pagina ClassView i se va da un dublu clic pe numele su
aflat n subordinea clasei CListVView, unde se va aduga urmtoarea secven de cod, pentru
a efectua ncrcarea elementelor din lista membru a documentului n cadrul reprezentrii de tip
list.
void CListVView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
// TODO: You may populate your ListView with items by directly accessing

// its list control through a call to GetListCtrl().


//** Obtinem un pointer la document
CListVDoc* pDoc = GetDocument();
//** ne asiguram ca documentul este valid
ASSERT_VALID (pDoc);
//** determinam capul listei de siruri
POSITION pos =
pDoc->GetElements (). GetHeadPosition ();
//** Cat timp elementul nu este NULL, se adauga elemente
while (pos)

159

Programare orientat obiect

{
//** Accesam urmatorul element din lista
CString strElement = pDoc->GetElements().GetNext (pos);
//** Il inseram in reprezentarea de tip lista
GetListCtrl ().InsertItem (0, strElement);
}
}
Un pointer la document se poate obine prin intermediul funciei GetDocument() a
reprezentrii, funcie care ntoarce documentul posesor al reprezentrii.
Macrodefiniia ASSERT_VALID verific dac obiectul indicat de pointer este valid.
Controlul list al reprezentrii este obinut cu ajutorul funciei GetListCtrl (), aceasta
fiind analoag cu funcia GetElements(), deoarece ntoarce o referin la un membru privat
cu scopul de a proteja modificarea accidental a membrului respectiv.
n acest moment, dac este asamblat i rulat aplicaia, va aprea o form destul de brut
a listei.
Stilul implicit de afiare pentru o reprezentare de tip list dispune elementele de-a lungul
paginii. Pentru mbuntirea aspectului, se va putea alege un alt stil de list. Exist patru stiluri
posibile:
LVS_LIST - list obinuit, afiat de sus n jos;
LVS_REPORT - list obinuit, afiat de sus n jos, dar cu coloane cu antet;
LVS_ICON - pictograme mari, dispuse de la stnga la dreapta, rnd cu rnd;
LVS_SMALLICON - pictograme mici, dispuse de la stnga la dreapta, rnd cu rnd.
Pentru a nlocui stilul implicit LVS_ICON, pentru lista afiat mai sus, cu un stil de tip
list LVS_LIST se vor utiliza funciile GetWindowLong() i SetWindowLong(),
introducndu-se urmtoarea secven de cod la sfritul funciei OnInitialUpdate(), dup
bucla while:
GetListCtrl ().InsertItem (0, strElement);
//** Determinam indicatorii de stil curenti
DWORD dwStyle = GetWindowLong (GetListCtrl().GetSafeHwnd(), GWL_STYLE);

//** Anulam stilul curent


dwStyle &= ~LVS_TYPEMASK;
//** Stabilim stilul lista
dwStyle = LVS_LIST;
//**Transmitem indicatorii inapoi la reprezentarea de tip lista
SetWindowLong(GetListCtrl().GetSafeHwnd(), GWL_STYLE, dwStyle);
//Actualizam afisarea reprezentarii de tip lista
SetRedraw (TRUE);

160

Programare orientat obiect

Pentru a putea stabili un stil a trebuit mai nti s se obin stilul curent al ferestrei, prin
apelarea funciei SetWindowLong(), iar prin specificarea indicatorului GWL_STYLE se
arat c din proprietile ferestrei intereseaz doar opiunile de stil.
Adugarea de coloane i antete asociate
Acestea se pot aduga utiliznd stilul LVS_REPORT, putndu-se aduga cu uurin
coloane dimensionabile cu antet, aplicaia se poate face mai interesant, prin adugarea de
coloane suplimentare care s afieze, prefixul, i codul potal.
Prima modificare necesar este adugarea n cadrul documentului a noilor informaii.
ntr-o aplicaie complex, se poate considera ideea crerii i utilizrii unei clase proprii n scopul
colectrii acestor informaii. Pentru simplitate, ns, noile informaii au fost ataate irurilor
existente, fiind separate prin virgul.
CListVDoc::CListVDoc()
{
// TODO: add one-time construction code here
// Adaugam elemente in lista de siruri
m_listElemente.AddTail ("Arad, 057, 2900");
m_listElemente.AddTail ("Bucuresti, 01, 70000");
m_listElemente.AddTail ("Cluj, 064, 3400");
m_listElemente.AddTail ("Craiova, 051, 1100");
m_listElemente.AddTail ("Iasi, 032, 6600");
m_listElemente.AddTail ("Timisoara, 056, 1900");
}
Dup ce au fost modificate datele, trebuie inserate antetele de coloan pentru noile
informaii din cadrul elementelor. Aceast operaie poate fi efectuat n funcia
OnInitialUpdate() a clasei reprezentare (CListVView) derivate din CListView, prin
adugarea urmtorului cod:
void CListVView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
// TODO: You may populate your ListView with items by directly accessing

// its list control through a call to GetListCtrl()


//** Inseram coloanele i antetele acestora
GetListCtrl().InsertColumn (0, "Nume oras", LVCFMT_LEFT, 120);
GetListCtrl().InsertColumn (1, "Prefix", LVCFMT_LEFT, 80);
GetListCtrl().InsertColumn (2, "Cod Postal", LVCFMT_LEFT, 130);
//** Obtinem un pointer la document
CListVDoc* pDoc = GetDocument();
//** ne asiguram ca documentul este valid
ASSERT_VALID (pDoc);
//** determinam capul listei de siruri
POSITION pos =
pDoc->GetElements (). GetHeadPosition ();

161

Programare orientat obiect

//** Cat timp elementul nu este NULL, se adauga elemente


while (pos)
{
//** Accesam urmatorul element din lista
CString strElement = pDoc->GetElements().GetNext (pos);
//** Extragem din sir numele elementului (orasului)
CString strName = strElement.Left (strElement.Find (","));
//** Extragem din sir prefixul
CString strPrefix = strElement.Mid (strElement.Find (",")+1);
//** Separam codul postal
CString strCodPostal = strPrefix.Mid (strPrefix.Find (",")+1);
//** Detasam codul postal de la sfirsit
strPrefix=strPrefix.Left(strPrefix.Find(","));
//** Inseram numele orasului in lista in coloana 0
GetListCtrl ().InsertItem (0, strName);
//** Inscriem prefixul orasului in a doua coloana
GetListCtrl().SetItemText (0,1, strPrefix);
//** Inscriem codul postal in a treia coloana
GetListCtrl().SetItemText(0,2, strCodPostal);
}
//** Determinam indicatorii de stil curenti
DWORD dwStyle = GetWindowLong (GetListCtrl().GetSafeHwnd(), GWL_STYLE);

//** Anulam stilul curent


dwStyle &= ~LVS_TYPEMASK;
//** Stabilim stilul raport
dwStyle = LVS_REPORT;
//**Transmitem indicatorii inapoi la reprezentarea de tip lista
SetWindowLong(GetListCtrl().GetSafeHwnd(), GWL_STYLE, dwStyle);
//Actualizam afisarea reprezentarii de tip lista
SetRedraw (TRUE);
}
Coloanele sunt inserate prin intermediul
membrului InsertColumn() al controlului
list, fiecare coloan putnd fi formatat astfel
nct coninutul su s fie aliniat la stnga, la
dreapta sau centrat, n acest sens se poate

162

Programare orientat obiect

transmite
unul
dintre
indicatorii:
LVCFMT_LEFT,
LVCFMT_RIGHT
sau
LVCFMT_CENTER.
Coloanele inserate pot fi terse prin intermediul funciei DeleteColumn(),
transmind numrul coloanei de ters.
La asamblarea i rularea programului se va afia o list cu coloanele dimensionabile.
Determinarea elementelor selectate ntr-o list
Pentru identificarea elementelor dup anumite criterii se folosete funcia
GetNextItem(), funcie ce primete doi parametrii, primul reprezentnd punctul de nceput
al cutrii, putndu-se ncepe cutarea de la un element arbitrar sau se transmite valoarea -1,
pentru a porni de la nceputul listei.
Cel de-al doilea parametru reprezint o combinaie de indicatori prin care se specific
elementele vizate. Aceti indicatori sunt:
LVNI_SELECTED - elementul este selectat curent;
LVNI_FOCUSED - elementul este ncadrat de un dreptunghi punctat care indic
focusul;
LVNI_ALL - ntoarce elementul urmtor - acesta este indicatorul implicit;
LVNI_ABOVE - ntoarce elementul aflat deasupra celui specificat prin indice;
LVNI_BELOW - ntoarce elementul aflat sub cel specificat prin indice;
LVNI_TOLEFT- ntoarce elementul aflat la stnga celui specificat prin indice;
LVNI_TORIGHT- ntoarce elementul aflat la dreapta celui specificat prin indice.
n momentul n care este deja un indice furnizat de
GetNextItem(), coninutul elementului respectiv se
poate obine cu ajutorul unei alte funcii a controlului list,
GetItemText, care primete indicele elementului i
coloana vizat, ntorcnd un CString care conine
informaia solicitat.
Se poate scrie un cod care s utilizeze aceste
funcii pentru a afia pe bara de titlu a aplicaiei lista
elementelor selectate curent, dar trebuie gndit cum se
poate actualiza aceast list. Se poate intercepta mesajul generat la efectuarea unui clic pe
controlul list, folosind ClassWizard care genereaz scheletul unei funcii de tratare.
Se va aduga o funcie de tratare, prin selectarea paginii Message Maps, a clasei
CListVView, i cutarea mesajului =NM_CLICK, i prin dublu clic va apare funcia
generat automat OnClick() creia ulterior i se va aduga codul aferent. Aceast funcie va fi
apelat de fiecare dat cnd utilizatorul efectueaz clic undeva n cadrul reprezentrii list.
void CListVView::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
*pResult = 0;
//** Cream sirul care va contine elementele selectate
CString strSelectedItems;
//Primul indice transmis functiei GetNextItem() trebuie sa fie zero
int nSelected=-1;
do

163

Programare orientat obiect

{
//**Cautam urmatorul element selectat
nSelected = GetListCtrl().GetNextItem(nSelected,LVNI_SELECTED);
//Am gasit un element selectat?
if (nSelected !=-1)
{
//** Adaugam continutul sau in sirul creat
strSelectedItems +=" "+ GetListCtrl().GetItemText (nSelected,0);
}
} while (nSelected !=-1);
//** Elementele selectate formeaza titlul documentului
GetDocument()->SetTitle("Selected:" +strSelectedItems);
}
La asamblarea i rularea programului, dup adugarea codului de mai sus, n cadrul
funciei de tratare, elementele selectate vor fi afiate pe bara de titlu:

4. Crearea i utilizarea unei reprezentri de tip arbore


4.1. Crearea unei reprezentri de tip arbore
Se poate genera automat o aplicaie SDI care s foloseasc o reprezentare de tip arbore,
paii sunt asemntori cu cei de la reprezentarea de tip list, cu deosebirea c, acolo unde s-a
selectat CListView, se va selecta CTreeView.
La fel ca i reprezentrile de tip list, i cele de tip arbore, folosesc o serie de indicatori
de stil, care se utilizeaz pentru adugarea unor diverse componente ntr-o reprezentare de tip
arbore.
Aceste componente sunt liniile care unesc elementele printe i elementele subordonate i
butoanele care deschid i nchid nivelele ierarhice. De asemenea, exist, indicatori care
dezactiveaz tragerea i plasarea, sau care permit editarea direct a elementelor. O list a
indicatorilor de stil pentru reprezentarea de tip arbore este urmtoarea:
TVS_HASLINES - traseaz linii ntre elementele subordonate i prinii acestora;
TVS_HASLINES - traseaz linii ntre nodul rdcin i elementele subordonate
acestuia;
TVS_HASBUTTONS afieaz mici butoane care permit expandarea sau
condensarea nivelelor ierarhice;
TVS_SHOWSELAWAYS- evideniaz elementul bselectat chiar dac este activat o
alt fereastr;
TVS_DISABLEDRAGDROP- dezactiveaz tragerea elementelor din arbore n
cadrul operaiilor de tragere i plasare.
Majoritatea arborilor, combin mai muli din aceti indicatori de stil pentru a obine o
reprezentare arborescent n stilul Explorer. Stabilirea stilurilor se face tot cu ajutorul funciei
GetWindowLong() pentru a determina opiunile curente, i transmind noile opiuni prin
apelul SetWindowLong().
Inserarea elementelor se face prin apelul funciei InsertItem(), care are mai multe
forme, fiind primii diferii parametrii. Cea mai simpl form primete doar trei parametrii: irul

164

Programare orientat obiect

care trebuie inserat, un indicator ctre printele noului element i un indicator ctre poziia dup
care va fi inserat elementul. Obligatoriu este doar irul care trebuie inserat, ceilali au valori
implicite care determin adugarea irului la nivelul rdcin, la sfritul listei.
Cnd se ncepe crearea arborelui, primul element trebuie s aib ca printe TVI_ROOT,
care precizeaz c printele elementului este rdcina arborelui. Operaii ulterioare de inserare
pot s specifice ca printe un element existent, caz n care se formeaz o ramur i noul element
devine subordonat elementului inserat anterior. Cele de-al treilea parametru al funciei
InsertItem() permite specificarea locului n care se efectueaz inserarea. Dac lum un
exemplu pe care l crem cu AppWizard, vom introduce un cod pentru popularea acestui arbore
n funcia OnInitialUpdate().
void CTreeVView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
// TODO: You may populate your TreeView with items by directly accessing

// its tree control through a call to GetTreeCtrl().


//**Cream o scurtatura catre controlul arbore
CTreeCtrl& tree = GetTreeCtrl();
//**Inseram un element la nivelul radacina
HTREEITEM hAnimale = tree.InsertItem ("Animale");
//**Inseram un element subordonat elementului radacina
HTREEITEM hVertebrate=tree.InsertItem ("Vertebrate", hAnimale);
//**Inseram elemente subordonate elementului hVertebre
tree.InsertItem ("AnimaleSalbatice", hVertebrate, TVI_SORT);
tree.InsertItem ("AnimaleDomestice", hVertebrate, TVI_SORT);
tree.InsertItem ("AnimaleAcvatice", hVertebrate, TVI_SORT);
//**Inseram un element subordonat elementului radacina
HTREEITEM hNevertebrate=tree.InsertItem("Nevertebrate", hAnimale);
//**Inseram elemente subordonate elementului hNevertebate
tree.InsertItem ("Moluste", hNevertebrate, TVI_SORT);
tree.InsertItem ("Serpi", hNevertebrate, TVI_SORT);
tree.InsertItem ("Viermi", hNevertebrate, TVI_SORT);
//**Inseram un element la nivelul radacina, dupa hAnimale
HTREEITEM hPlante = tree.InsertItem ("Plante", TVI_ROOT, hAnimale);

//**Inseram un element subordonat noului element radacina


HTREEITEM hFructe=tree.InsertItem ("Fructe", hPlante);
//**Inseram elemente subordonate elementului hFructe
tree.InsertItem ("Mere", hFructe, TVI_SORT);
tree.InsertItem ("Pere", hFructe, TVI_SORT);
tree.InsertItem ("Prune", hFructe, TVI_SORT);

165

Programare orientat obiect

//**Inseram un element subordonat noului element radacina


HTREEITEM hCereale=tree.InsertItem("Cereale", hPlante);
//**Inseram elemente subordonate elementului hNevertebate
tree.InsertItem ("Griu", hCereale, TVI_SORT);
tree.InsertItem ("Secara", hCereale, TVI_SORT);
tree.InsertItem ("Porumb", hCereale, TVI_SORT);
//**Determinam indicatorii de stil curenti
DWORD dwStyle=GetWindowLong(GetTreeCtrl().GetSafeHwnd(), GWL_STYLE);

//**Stabilim stilurile dorite


dwStyle |=TVS_HASLINES + TVS_HASBUTTONS + TVS_LINESATROOT;

//** Transmitem indicatorii de stil reprezentarii arbore


SetWindowLong (GetTreeCtrl().GetSafeHwnd(), GWL_STYLE, dwStyle);

//**Actualizam afisarea reprezentarii de tip arbore


}
n urma asamblrii i rulrii aplicaiei, va aprea urmtoarea imagine:
Pentru a determina nodul selectat n cadrul unei
reprezentri de tip arbore se va folosi funcia membru
GetSelectedItem(),
care
va
ntoarce
indicatorul
HTREEITEM al elementului selectat. Ca alternativ, exist o
funcie GetNextItem() care opereaz la fel ca omonimul su
din cadrul reprezentrilor de tip list. Versiunea oferit de
controlul arbore primete doi parametrii: primul este un
HTREEITEM, iar al doilea este o combinaie de indicatori prin
care se specific criteriile de cutare.
Valorile de indicatori posibili pentru funcia GetNextItem() a
controlului arbore sunt:
TVGN_CARET - ntoarce elementul selectat curent
TVGN_ROOT - ntoarce elementul rdcin pentru
elementul specificat
TVGN_PARENT - ntoarce printele elementului specificat
TVGN_CHILD - ntoarce primul element subordonat; elementul specificat trebuie s
fie NULL
TVGN_NEXT - ntoarce urmtorul element subordonat
TVGN_PREVIOUS - ntoarce precedentul element subordonat
TVGN_PREVIOUS_VISIBLE - ntoarce primul element vizibil
Selectarea unui element se poate face i prin program, apelnd funcia SelectItem() i
transmindu-i indicatorul HTREEITEM ctre elementul care se dorete selectat, iar eticheta
asociat elementului respectiv poate fi obinut cu ajutorul funciei GetItemText.
Codul care determin elementul selectat curent i eticheta asociat acestuia va fi
prezentat n continuare.
Mesajul de notificare reflectat TVN_SELCHANGED este interceptat prin funcia de
tratare ONDELCHANGED() a clasei reprezentare.

166

Programare orientat obiect

void CTreeVView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)


{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
//**Obtinem un indicator pentru elementul selectat
HTREEITEM hSelected=GetTreeCtrl().GetSelectedItem();
//** Ne asiguram ca exista un element selectat
if (hSelected>= 0)
{
//**Obtinem eticheta asociata elementului selectat
CString strSelected=GetTreeCtrl().GetItemText (hSelected);
//** Afisam elementul selectat pe bara de titlu a ferestrei
GetDocument()->SetTitle(strSelected);
}
*pResult = 0;
}
Funcia GetSelectedItem() este folosit pentru a obine un
indicator ctre elementul selectat, validitatea acestui indicator
fiind apoi verificat, iar dac totul este n regul, prin apelul
funciei GetItemtext() ntoarce eticheta asociat elementului
selectat, acesta devenind titlul documentului.
n urma rulrii programului, se observ c elementul
selectat apare afiat n bara de titlu.
4.2. Controlul editrii imediate
Facilitatea prin care aplicaia permite modificarea coninutului unei reprezentri de tip
arbore efectund un clic pe elementul respectiv i modificnd-o pe loc, se numete editare
imediat. Implementarea sa este facil, fiind nevoie de stabilirea indicatorului de stil
TVSEDITLABELS i de tratare a dou mesaje de notificare: TVN_BEGINLABELEDIT
i TVN_ENDLABELEDIT, pentru care se vor aduga funciile de tratare corespunztoare:
OnBeginlabeledit() i OnEndlabeledit().
n prima funcie de tratare se poate utiliza funcia getEditControl() pentru a
manipula controlul de editare care a fost adugat dinamic la arbore cu scopul de a permite
editarea pe loc.
Utilizatorul poate apoi s modifice eticheta, apsnd Enter sau efectund un clic n afara
controlului de editare pentru a ncheia editarea. n acest moment va fi apelat funcia de tratare
OnEndLabelEdit(), dup care va trebui apelat din nou funcia GetEditControl(), cu
scopul de a determina eticheta modificat. n acest moment se poate valida noua etichet, i
eventual s se nscrie n arbore. Pentru nscrierea n arbore a noii etichete se va apela funcia
SetItemtext().
Adugarea stilului TVS_EDITLABELS alturi de celelalte stiluri ale controlului
arbore se poate face astfel:
//**Stabilim stilurile dorite
dwStyle =TVS_HASLINES + TVS_HASBUTTONS + TVS_LINESATROOT + TVS_EDITLABELS;

167

Programare orientat obiect

Partea de cod aferent celor dou funcii de tratare a mesajelor este urmtoarea:
void CTreeVView::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
// TODO: Add your control notification handler code here
GetTreeCtrl().GetEditControl()->LimitText(20);
*pResult = 0;
}
void CTreeVView::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
// TODO: Add your control notification handler code here
//Obtinem eticheta modificat de la conbtrolul de editare
CString strText;
GetTreeCtrl().GetEditControl()->GetWindowText (strText);
//** Aici se poate efectua o validare a etichetei
//**Ne asiguram ca sirul nu este vid
if (strText.GetLength()>0)
{
//** Determinam indicatorul asociat elementului selectat
HTREEITEM hSelected=pTVDispInfo->item.hItem;
//**Inscriem eticheta modificata
GetTreeCtrl().SetItemText (hSelected, strText);
}
*pResult = 0;
}

5. Dezvoltarea aplicaiilor cu documente multiple


Pornind de la aplicaia creat cu SDI cea cu crile, vom crea un nou proiect cu numele
MDICarti, prin parcurgerea urmtorilor pai:
Dup ce s-a dat un nume proiectului, se va selecta opiunea Multiple
Documents, i se va asigura s fie validat caseta Document/View
Archirtecture Support, apoi se va da clic pe Next;
Din caseta corespunztoare pasului doi, se va selecta None, opiunile prezente aici
permit alegerea unor diferite tipuri de suport pentru baze de date, ceea ce nu este
necesar n cazul nostru, apoi se d clic pe Next;
n pasul trei, se selecteaz opiunea None i se valideaz caseta
ActiveXControls, celelalte opiuni privesc faciliti de automatizare OLE;

168

Programare orientat obiect

n caseta de dialog corespunztoare pasului patru, se vor valida opiunile: Docking


Toolbar, Initial Status Bar, Printing and prin Preview i 3D
Controls, i se va selecta butonul de opiune Normal, pentru a preciza stilul barei
de instrumente;
la pasul 5, se va selecta MFC Standard, ca tip de proiect, i Yes pentru a genera
comentarii n codul surs , apoi se va selecta As a Shared DLL pentru a specifica
modul de utilizare a bibliotecii MFC;
la pasul 6 se va efectua clic pe Finish, n urma cruia va apare caseta de dialog New
Project Information, unde se afl cteva informaii utile privind clasele
generate i numele fiierelor surs. Se pot totodat confirma facilitile selectate, apoi
n urma efecturii unui clic pe OK, s-a realizat noul proiect.
Exemplul MDICarti are la baz programul SDICarti, codul fiind foarte asemntor,
dar
MDICarti
permite
deschiderea
simultan
a
mai
multor
ferestre
Document/Reprezentare. Dac o aplicaie cu interfa document singular are o singur
clas derivat din CDocument, o aplicaie cu interfa document multiplu poate avea oricte
astfel de clase.
Fiecare clas document este asociat cu o clas reprezentare. Clasa reprezentare poate fi
utilizat de mai multe documente diferite sau poate aparine unui singur tip de document. Clasa
de baz pentru reprezentare este selectat n pasul 6 din AppWizard; opiunile disponibile sunt
CView,
CScroolView,
CListView,
CTreeView,
CEditView,
CRichEditView, CFormView,CRecordView i CHtmlView. Exemplul
MDICarti folosete clasa CView propus implicit.

Adugarea de variabile membru n document


n clasa CMDICartiDoc este nevoie de o singur variabil membru, care va reine
numrul de cri aflate curent n teanc. Pentru aceasta se introduce variabila membru
m_nCarti de tip int i cu acces protejat.
Pentru ca o clas de reprezentare CMDICartiView s poat accesa aceast variabil,
va trebui adugat n clasa document o funcie care s furnizeze valoarea sa. Astfel, tot din
meniul contextual al clasei CMDICartiDoc se va alege opiunea de adugare a unei funcii de
tip int, avnd ca nume GetCartCount i acces public. n corpul funciei se va introduce
urmtoarea linie de cod:
return m_nCarti;
Se apeleaz funcia constructor CMDICartiDoc, se d dublu clic i se introduce dup
comentariile TODO din funcia constructor urmtoarea linie de cod:
m_nCarti = 1;
Pentru ca reprezentarea s poat extrage date ale documentului, ea trebuie mai nti s fie
capabil s acceseze obiectul document. Infrastructura MFC se ocup automat de acest aspect,
adugnd n clasa reprezentare a aplicaiei o funcie GetDocument, care ntoarce un pointer
ctre obiectul document la care reprezentarea a fost ataat prin intermediul machetei document.
Clasa CMDICartiView afieaz teancul de cri n cadrul funciei OnDraw.
Infrastructura MFC apeleaz funcia CMDICArtiView::OnDraw ori de cte ori

169

Programare orientat obiect

reprezentarea trebuie afiat pe ecran. Pentru aceast funcie se va introduce urmtoarea secven
de cod:
void CMDICartiView::OnDraw(CDC* pDC)
{
CMDICartiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
// ** Salvam pensula curenta
CBrush* pOldBrush = pDC->GetCurrentBrush();
//** Cream o pensula plina de culoare galbena
CBrush br;
br.CreateSolidBrush (RGB (255, 255, 0));
//Selectam pensula galbena in contextul dispozitiv
pDC->SelectObject (&br);
// Obtinem de la document numarul de carti si
// desenam cate doua patrate care sa reprezinte fiecare cartea
for (int nCount = 0; nCount < pDoc->GetCartiCount(); nCount++);
{
int y = 100 - 10 * nCount;
pDC-> Rectangle (40,y, 100, y-30);
pDC->Rectangle (40, y-10, 100, y-35);
}
//** Selectam la loc pensula originala
pDC->SelectObject (pOldBrush);
}
Pentru a putea modifica numrul de cri, trebuie adugate dou opiuni de meniu una
care s adauge o carte i cealalt care s nlture una. Opiunile de meniu trebuie adugate n
cadrul resursei IDR_MDICARTITYPE, din cadrul paginii Resource View, i
expandarea catalogului Menu, deoarece aceasta este specific tipului de document.
n meniul Edit n caseta disponibil se introduce pe rnd la fel ca la SDI,
ID_EDIT_ADAUGA_CARTE i ID_EDIT_STERGE_CARTE, iar apoi din pagina de
mesaje se selecteaz pe rnd cele dou ID-uri create mai sus n caseta cu list Object Ids, i
se selecteaz COMMAND, adugndu-se funciile corespunztoare, la care se va introduce
urmtorul cod:
void CMDICartiDoc::OnEditAdaugaCarte()
{
// TODO: Add your command handler code here
//**Crestem numarul de carti
m_nCarti++;
//**Actualizam reprezentarea pentru a redesena teancul de carti
UpdateAllViews (NULL);

170

Programare orientat obiect

}
void CMDICartiDoc::OnEditStergeCarte()
{
// TODO: Add your command handler code here
//Scadem numarul de carti
if(m_nCarti > 0)
m_nCarti--;
//**Actualizam reprezentarea pentru a redesena teancul de carti
UpdateAllViews (NULL);
}
La asamblarea i rularea proiectului MDICarti , ncercai s selectai opiunea New a
meniului File pentru a crea o nou fereastr document, dup care experimentai adugarea i
tergerea unei cri. Se poate de asemenea s se creeze o a doua reprezentare a aceluiai
document, selectnd opiunea New Window a meniului Window.
Adugarea de noi machete de document
Avantajul pe care l ofer modelul MDI fa de SDI nu privete doar posibilitatea oferit
utilizatorului de a lucra simultan cu mai multe documente, ci i capacitatea de a gestiona ntr-o
singur aplicaie mai multe tipuri de documente. n acest sens, va trebui s se creeze propriile
clase document i reprezentare, s se insereze resursele necesare i s se adauge codul care
creeaz i iniializeaz un obiect CMultiDocTemplate.
Vom exemplifica acest lucru, prin adugarea la proiectul MDICarti un nou tip de
document, care va opera nu cu cri ci cu reviste. Pentru generarea noilor clase document i
reprezentare se vor urma paii de mai jos:
se apeleaz ClassWizard;
este selectat opiunea Add Class i se selecteaz New, fiind deschis caseta de
dialog pentru adugarea noii clase;
numele pe care-l vom da clasei pentru exemplul ales va fi CMDIrevisteDoc, iar
la clasa de baz se va selecta CDocument;
n mod analog se va introduce clasa CMDIRevisteView, avnd clas de baz
CView;
n clasa CMDIRevisteDoc se va aduga o variabil de tip int, cu numele
m_nReviste, de tip protejat, apoi o funcie tot de tip int, avnd ca declaraie
GetRevisteCount, i cu acces public, iar n linia de cod corespunztoare se va
introduce return m_nReviste;
se apeleaz funcia constructor CMDIRevisteDoc, i se va introduce linia de cod:
m_nReviste = 1;
se selecteaz clasa CMDIRevisteView, i se va aduga funcia de tip
CMDIRevisteDoc* iar la declaraie GetDocument, cu acces public, dup
care se va introduce n corpul funciei urmtoarea linie de cod: return
(CMDIRevisteDoc*)m_pDocument
n acest moment, sunt create noile clase document i reprezentare, documentul conine un
membru care va reine datele, precum i o metod de acces. Clasa reprezentare conine o metod
care furnizeaz documentul asociat. Va trebui adugat la nceputul fiierului

171

Programare orientat obiect

MDIRevisteView.cpp, nainte de directiva #include urmtoarea linie #include


MDIRevisteDoc.h
Pasul urmtor este adugarea unei resurse de tip meniu, care se poate realiza prin
copierea uneia existente, prin urmtorii pai:
n cadrul paginii de resurse se expandeaz catalogul Menu i se va alege elementul
IDR_MDICARTYPE, apsai Ctrl+C i apoi Ctrl+V, i va fi adugat o copie a
meniului selectat, cu identificatorul IDR_MDICARTYPE1;
se va selecta pagina de proprieti aferent acesteia, i se va introduce un nou
identificator, IDR_MDIREVTYPE, i n mod analog se va schimba i coninutul
opiunilor Edit cu adaug o revist i terge o revist;
se va salva cu Save din File i apoi se d Close;
se va accesa pagina Message Maps din ClassWizard, i se va proceda analog
cu MDICarti pentru atribuirea de funcii de tratare a mesajelor COMMANDS.
Dup ce s-a introdus codul corespunztor celor dou funcii (la fel ca la cri), pasul
urmtor l reprezint crearea unei resurse ir de caractere corespunztoare documentului, care
presupune urmtoarele etape:
n cadrul paginii de resurse, se va expanda catalogul String Table i se va efectua
dublu clic pe String table, n acest moment va fi deschis tabela de iruri;
pentru a insera noul ir sub irul IDR_MDICARTYPE, se va selecta acesta din
tabela de iruri i se va alege opiunea New string a meniului de context, fiind
afiat caseta de dialog String Properties;
se va specifica un identificator ID pentru noul ir, IDR_MDIREVTYPE;
se specific coninutul irului n
Caption: \nMDIRev\n\n\nMDIRev.DocumentnMDIRev Document;
se nchide caseta de dialog String Properties.
irul corespunztor documentului are un format bine definit, identic pentru aplicaiile
SDI i MDI irul este format din apte subiruri, separate prin caracterul \n (linie nou).
n acest moment totul este pregtit pentru utilizarea noilor clase document i reprezentare
din cadrul proiectului MDICarti. Se poate lsa infrastructura MFC s se ocupe de instanierea
obiectelor i de gestionarea ferestrelor reprezentare i cadru, pentru aceasta netrebuind dect s
se nregistreze n cadrul aplicaiei perechea document/reprezentare i cadrul asociat, crend n
acest scop o a doua machet de document.
Machetele
de
document
se
nregistreaz
n
supradefiniia
funciei
CwinApp::InitInstance. Pentru a crea i aduga noua machet de document, la nceputul
fiierului MDICartiApp.cpp se vor aduga urmtoarele directive de includere:
#include MDIRevDoc.h
#include MDIRevView.h
apoi n funcia de mai sus se vor aduga liniile de cod:
//** Instantiem o a doua macheta de document i o
//**initializam transmitind identificatorul pentru resursele
//**asociate documentului si infrmatii dinamice pentru
//**clasele document, cadru i reprezentare.
//**Apelam apoi AddDocTemplate pentru a inregistra macheta in cadrul aplicatiei

172

Programare orientat obiect

pDocTemplate
=
new
CMultiDocTemplate(IDR_MDIREVTYPE,
RUNTIME_CLASS
(CMDIRevDoc),
RUNTIME_CLASS
(CChildFrame),RUNTIME_CLASS (CMDIRevView));
AddDocTemplate (pDocTemplate);
n acest moment trebuie implementat n clasa reprezentare codul care va afia teancul de
reviste n funcie de numrul acestora reinut de ctre document. Se va edita funcia
CMDIRevView::OnDraw:
//**Salvam pensula curenta
CBrush*pOldBrush = pDC->GetCurrentBrush ();
//**Cream o pensula plina de culoare verde
CBrush br;
br.CreateSolidBrush (RGB(0,128,32));
//**Selectam pensula verde in contextul dispozitiv
pDC->SelectObject (&br);
//**Obtinem de la document numarul de reviste si desenam
//** cate un dreptunghi si un & prin care reprezentam fiecare revista
for (int nCount = 0; nCount < pDoc->GetRevistaCount(); nCount++);
{
int x = 40 + 20 *nCount;
pDC->Rectangle (x, 40, x+100, 90);
pDC->TextOut (x = 5, 45, "&");
}
//**Selectam la loc pensula originala
pDC->SelectObject (pOldBrush);
Se poate asambla i rula proiectul. La selectarea opiunii New a meniului File ar trebui
s fie afiat caseta de dialog New, care cuprinde ambele elemente Cri i Reviste.
ncercai s deschidei ambele tipuri de documente i apoi comutai ntre ele, se observ c
meniul Edit se modific n funcie de documentul activ.

173

S-ar putea să vă placă și