Sunteți pe pagina 1din 6

Tiprire i Previzualizare

Bazele tipririi i previzualizrii n MFC


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

Obiective:
determinarea obiectelor folosite de ctre MFC pentru tiprire i previzualizare;
determinarea ordinii de apel al funciilor implicate n tiprire i previzualizare;
determinarea elementelor ce identific pagina de tiprit, etc.
Lecia se va desfura n laborator. Drept exerciiu independent: s se adauge codul necesar pentru a realiza
defilarea orizontal i/sau vertical.

Pentru nvarea manevrrii contextului de dispozitiv se poate propune construirea unei aplicaii care s
deseneze graficul unei funcii. Se vor avea n vedere toate situaiile posibile unde poate fi desenat graficul funciei
astfel nct s fie ocupat ct mai bine zona client (pentru un grafic ce apare numai n cadranul IV se va desena
numai acest cadran i graficul, etc.).

Vom exemplifica tiprirea i vizualizarea pe baza unui exemplu.

Se creaz o aplicaie cu arhitectura Document/View i tip SDI (restul setrilor rmnnd cele implicite) i cu
suport pentru print/preview.

Numele proiectului este Print1.

Prima modificare.
n funcia CPrint1View::OnDraw() adugm:

pDC->Rectangle(20, 20, 220, 220);

Se va desena un dreptunghi (cu mrimile msurate n pixeli). (20,20) reprezint colul din stnga sus al
dreptunghiului, iar (220,220) reprezint colul din dreapta jos al dreptunghiului. Deci mrimea laturilor
dreptunghiului este 200 pe 200 pixeli.

Colul din stnga sus al zonei client are coordonatele (0,0), axa Ox este pe orizontal, axa Oy este pe vertical.

Aceast aplicaie poate produce vizualizarea i tiprirea documentului.

Scalarea
Documentul listat i cel afiat pe ecran nu are aceeai dimensiune (nu arat la fel) pentru c imprimanta folosete
unitatea de msur, dots, iar pe ecran se folosete pixelul, i acestea au mrimi diferite (200 dots # 200 pixeli).
Acest lucru este descris de modul de mapare (implicit MM_TEXT).
Dac dorim s scalm imaginea tiprit la o anumit dimensiune, trebuie s alegem diferite moduri de mapare.
Moduri de mapare
Mode Unit X Y
MM_HIENGLISH 0.001 inch Increases right Increases up
MM_HIMETRIC 0.01 millimeter Increases right Increases up
MM_ISOTROPIC User-defined User-defined User-defined
MM_LOENGLISH 0.01 inch Increases right Increases up
MM_LOMETRIC 0.1 millimeter Increases right Increases up
MM_TEXT Device pixel Increases right Increases down
MM_TWIPS 1/1440 inch Increases right Increases up

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

pDC->SetMapMode(MM_LOENGLISH);
pDC->Rectangle(20, -20, 220, -220);

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

Tiprirea mai multor pagini


MFC trateaz tiprirea documentului (mai puin bitmap-uri). Funcia OnDraw() din clasa pentru vizualizare
realizeaz desenarea pe ecran ct i tiprirea la imprimant. Lucrurile se complic cnd documentul are mai multe
pagini sau alte tratri speciale (informaii de nceput i de sfrit de pagin).

Exemplificare:
Vom modifica aplicaia astfel nct s desenm mai multe dreptunghiuri care s nu ncap pe o pagin.
Adugm o variabil membru (int m_numrects) la clasa document care va memora numrul de dreptunghiuri
care se vor desena i pe care o iniializm n constructor.
Pe mesajul WM_LBUTTONDOWN vom incrementa aceast variabil, iar pe mesajul WM_RBUTTONDOWN
vom decrementa aceast variabil. Codul pentru cele dou funcii este dat mai jos:

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

Vedem ce se ntmpl n PrintPreview. Codul din PrintPreview (n acest moment) nu tie cum s afieze mai multe
pagini.

Determinarea numrului de pagini se face n funcia OnBeginPrinting().


print1View.cpp --CPrint1View::OnBeginPrinting()
void CPrint1View::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
CPrint1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
int pageHeight = pDC->GetDeviceCaps(VERTRES);
int logPixelsY = pDC->GetDeviceCaps(LOGPIXELSY);
int rectHeight = (int)(2.2 * logPixelsY);
int numPages = pDoc->m_numRects * rectHeight / pageHeight + 1;
pInfo->SetMaxPage(numPages);
}

OnBeginPrinting() are doi parametri: un pointer la un context de dispoztiv al imprmantei i un pointer la un


obiect CPrintInfo. Pentru c versiunea implicit nu se refer la aceti doi pointeri, numele parametrilor sunt
comentai pentru a preveni mesajele de avertizare la compilare.

void CPrint1View::OnBeginPrinting(CDC* /*pDC*/ , CPrintInfo* /*pInfo*/)

Pentru a seta numrul paginii, trebuie s accesm ambele obiecte CDC* i CPrintInfo, deci va trebui s scoatem
comentariile de la ceti doi parametri.

Trebuie s avem urmtoarele informaii:


1. nlimea paginii;
2. numrul de dots pe inch.

nlimea paginii o obinem printr-un apel al funciei GetDviceCaps(), care furnizeaz informaii despre
posibilitile contextului de dispozitiv. Avem nevoie de rezoluia vertical (numrul de dots tipribili de la nceputul
paginii pn la sfritul ei), deci vom furniza ca parametru constanta VERTRES, n funcia GetDeviceCaps().
Constanta HORZRES n aceeai funcie ne furnizeaz rezoluia orizontal.
GetDeviceCaps() accept un numr de 29 de constante diferite (a se vedea help-ul).

n exemplul nostru, pentru a ti cte dreptunghiuri ncap pe o pagin, trebuie s tim nlimea dreptunghiului n
dots, deci va trebui s mprim dots pe pagin la dots pe dreptunghi.
tim c fiecare dreptunghi este nalt de 2 inch cu un spaiu de 20/100 ntre fiecare dreptunghi. Distana total de la
nceputul desenrii unui dreptunghi pn la urmtorul este de 2.2 inch.
Apelul GetDeviceCaps(LOGPIXELSY) ne d numrul de dots pe inch pentru imprimant (care este ataat la
sistem)., care nmulit cu 2.2 ne d dots pe dreptunghi.
Rulnd aplicaia vom observa c dei n previzualizare avem dou pagini, la listare vom obine pagina 1 de dou ori.
Trecerea de la o pagin la alta este urmtorul pas.

Setarea originii
Va trebui s furnizm informaia privitoare la nceputul unei noi pagini. Pentru acest lucru, vom rescrie funcia
OnPrepareDC().
Adugm aceaceast funcie la clasa de vizualizare cu ClassWizard. Codul este:
print1View.cpp --CPrint1View::OnPrepareDC()
void CPrint1View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{ if (pDC->IsPrinting())
{
int pageHeight = pDC->GetDeviceCaps(VERTRES);
int originY = pageHeight * (pInfo->m_nCurPage - 1);
pDC->SetViewportOrg(0, -originY);
}
CView::OnPrepareDC(pDC, pInfo);
}

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

MFC i Tiprirea
Alte funcii importante n procesul de tiprire sunt:
Printing Functions of a View Class
Function Description
Override this function to create resources, such as fonts, that you need for printing the
OnBeginPrinting()
document. You also set the maximum page count here.
This function serves triple duty, displaying data in a frame window, a print preview window,
OnDraw()
or on the printer, depending on the device context sent as the function's parameter.
OnEndPrinting() Override this function to release resources created in OnBeginPrinting().
Override this function to modify the device context used to display or print the document.
OnPrepareDC()
You can, for example, handle pagination here.
Override this function to provide a maximum page count for the document. If you don't set
OnPreparePrinting()
the page count here, you should set it in OnBeginPrinting().
Override this function to provide additional printing services, such as printing headers and
OnPrint()
footers, not provided in OnDraw().

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


DoPreparePrinting() care la rndul ei este responsabil pentru afiarea boxei de dialog Print i creaz
contextul de dispozitiv pentru imprimanta selectat.
print1View.cpp --CPrint1View::OnPreparePrinting() as Generated by AppWizard
BOOL CPrint1View::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}

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

Members of the CPrintInfo Class


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

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

Versiune posibil OnPrint() cu Headers i Footers


void CPrint1View::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
// Call local functions to print a header and footer.
PrintHeader();
PrintFooter();
CView::OnPrint(pDC, pInfo);
}

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

Dup ce MFC a terminat de tiprit ultima pagin, apeleaz funcia OnEndPrinting(), unde putem distruge orice
resurs de care nu mai avem nevoie.

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