Documente Academic
Documente Profesional
Documente Cultură
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
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
145
146
147
148
149
150
151
152
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
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
unei
opiuni,
va
apare
mesajul
155
ID_MENU_ROSU,
156
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
158
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
159
{
//** 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);
160
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
161
162
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
{
//**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:
164
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
165
166
167
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;
}
168
169
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
}
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
172
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