Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Visual1.doc
Скачиваний:
8
Добавлен:
07.03.2016
Размер:
4.35 Mб
Скачать

6.5. Друк багатосторінкового документа

Коли ви маєте справу з таким додатком, як Print1, то включення в нього функцій виведення на друк виконується практично без вашої участі. Це відбувається тому, що документ займає тільки одну сторінку і, таким чином, ніякої розбивки на сторінки не потрібно. Що б ви не включили до такого односторінкового документу (крім растрових зображень (bitmap image)), MFC всі турботи по роздрукуванню бере на себе. Функція OnDraw(), яка є членом класу виду вашої програми, однаково формує зображення документа і для виведення у вікно програми, і для виведення на друк, і для виведення у вікно попереднього перегляду документу. Однак все значно ускладнюється, коли мова заходить про великі документи, які вимагають розбивки на сторінки або спеціальної обробки, як, наприклад, включення верхніх і нижніх колонтитулів.

Для того щоб на практиці переконатися в наявності проблем, що виникають при роздрукуванні багатосторінкових документів, модифікуємо додаток Print1. Збільшимо кількість сформованих прямокутників таким чином, щоб вони розміщувались на декількох сторінках. Додамо в клас документа додатку змінну, яка буде зберігати кількість намальованих прямокутників і дозволить користувачеві збільшувати або зменшувати їх кількість, клацаючи лівою та правою кнопками миші.

1. У вікні ClassView розгорніть клас CPrint1Doc і клацніть правою кнопкою миші на ньому. Виберіть Add Member Variable (Додати член-змінну) у контекстному меню. У полі Variable Type (Тип змінної) введіть int, в поле Variable Declaration (Оголошення змінної) введіть m_nRects, а тип доступу задайте Public (Відкрита).

2. Двічі клацніть на конструкторі CPrint1Doc і включіть в нього оператор:

m_nRects = 5;

В результаті безпосередньо після запуску програми в документі буде сформовано 5 прямокутників.

3. За допомогою ClassWizard організуйте перехоплення клацання лівою кнопкою миші (повідомлення WM_LBUTTONDOWN) функцією OnLButtonDown() – членом класу виду, як це показано на рис. 6.7.

Рис. 6.7. Використання ClassWizard для включення в додаток функції OnLButtonDown()

4. Тепер клацніть на Edit Code (Редагувати текст програми) щоб відредагувати текст функції OnLButtonDown():

void CPrint1View::OnLButtonDown(UINT nFlags, CPoint point)

{

CPrint1Doc* lpDoc = GetDocument();

ASSERT_VALID(lpDoc);

lpDoc->m_nRects++;

Invalidate();

CView::OnLButtonDown(nFlags, point);

}

Дана функція збільшує значення лічильника прямокутників.

5. За допомогою ClassWizard додайте функцію обробки клацання правою кнопкою миші OnRButtonDown(), як це показано на рис. 6.8.

Рис. 6.8. Використання ClassWizard для включення в додаток функції OnRButtonDown()

6. Тепер клацніть на Edit Code і відредагуйте текст функції OnRButtonDown() наступним чином:

void CPrint1View::OnRButtonDown(UINT nFlags, CPoint point)

{

CPrint1Doc* lpDoc = GetDocument();

ASSERT_VALID(lpDoc);

if(lpDoc-> m_nRects)lpDoc-> m_nRects--;

Invalidate();

CView::OnRButtonDown(nFlags, point);

}

Функція зменшує лічильник прямокутників щоразу, коли користувач клацає правою кнопкою миші.

7. Модифікуйте функцію OnDraw() – член класу виду. Функція повинна формувати не один, а кілька – m_nRects - прямокутників. Додаток Print1 буде формувати прямокутники один під іншим, у результаті чого кількість сторінок документа може зростати. Крім того, кількість сформованих прямокутників також виводиться на екран. Новий варіант тексту функції:

void CPrint1View::OnDraw(CDC* pDC)

{

CString vr;

int colontit,dl;

int h_page,h_pr,pust,nach,zn,ot_left;

CString out;

double pie,K_px,K_py;

CFont fon;

CRect rect;

CPrintAppDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

vr.Format("Количество прямоугольников - %d ",

pDoc->m_nRects);

((CMainFrame*)GetParentFrame())->SetWindowText(vr);

((CChildFrame*)GetParent())->GetClientRect(&rect);

pDC->SetMapMode(MM_TEXT);

if(!pDC->IsPrinting())

{

if( nom_var == 1)

{

dl = (rect.Width() - pDC->GetTextExtent

("Работа с пикселями").cx)/2;

pDC->TextOut(dl,2, "Работа с пикселями");

}

if( nom_var == 2)

{

dl = (rect.Width() - pDC->GetTextExtent

("Работа в 0.01 дюйма").cx)/2;

pDC->TextOut(dl,2, "Работа в 0.01 дюйма");

}

}

CPen pen( PS_SOLID, 1, RGB(0,0,0) );

CPen* oldPen = pDC-> SelectObject( &pen );

if(nom_var == 1)

{

h_page = pDC->GetDeviceCaps(VERTRES);

K_py = (double)(pDC->GetDeviceCaps(LOGPIXELSY));

K_px = (double)(pDC->GetDeviceCaps(LOGPIXELSX));

ot_left = (int)(ots_left*K_px/25.4 + 0.5);

zn = 1;

}

if(nom_var == 2)

{

pDC->SetMapMode(MM_LOENGLISH);

h_page= (int)(100.0*

pDC->GetDeviceCaps(VERTRES)/

pDC->GetDeviceCaps(LOGPIXELSY) + 0.5);

K_px = K_py = 1.0;

ot_left = (int)(100.0*ots_left/25.4 + 0.5);

zn = -1;

}

pie=count*(1+otstup);

colontit= 0;

if(pDC->IsPrinting())

{

colontit= (int)(h_page*dol_collon + 0.5);

pie+=otstup;

}

h_pr=(int)((h_page-colontit)/pie + 0.5);

pust=(int)(h_pr*otstup+0.5);

//***********************************

fon.CreatePointFont(5*h_pr,"Arial" );

CFont* old_font = pDC->SelectObject(&fon);

//***********************************

int kol_st = 0;

nach= zn*colontit;

for( int i=1; i < pDoc->m_nRects + 1; i++)

{

nach= nach + zn*pust;

out.Format("%d",i);

CRect rect(ot_left, nach,(int) (ot_left +

h_pr*K_py/K_px), nach+h_pr*zn);

pDC->Rectangle(rect);

pDC->DrawText(out,rect,

DT_CENTER|DT_VCENTER|DT_SINGLELINE);

nach = nach + zn*h_pr;

if(pDC->IsPrinting() && i%count == 0)

{

kol_st++;

nach = (kol_st*h_page + colontit)*zn;

}

}

pDC-> SelectObject( oldPen );

if(pDC->IsPrinting())return;

CSize docSize( 300, abs(nach) + 1);

GetClientRect(&rect);

CSize pageSize( rect.right, rect.bottom );

CSize lineSize( 0, count*h_pr + (count+1)*pust);

if(nom_var == 1)

SetScrollSizes( MM_TEXT, docSize, pageSize, lineSize );

if(nom_var == 2)

SetScrollSizes( MM_LOENGLISH, docSize, pageSize,

lineSize );

pDC->SelectObject(old_font);

}

Розглянемо цю функцію більш детально. Попередній перегляд документів зроблено у двох варіантах (змінна nom_var). Перший варіант характеризує роботу з пікселями (nom_var = 1), другий варіант – роботу в 0,01 дюйми (nom_var = 2).

Наведемо перелік основних змінних, які використовуються для друку багатосторінкового документу.

1) h_page – висота сторінки у пікселях або у 0,01 дюйма.

2) count – кількість прямокутників на сторінці;

3) otstup – доля відступу між прямокутниками відносно висоти прямокутника;

4) ots_left – відступ зліва в міліметрах;

5) pie – кількість прямокутників на сторінці з врахуванням відступів;

6) colontit – місце, яке займає колонтитул у пікселях або у 0,01 дюйма;

7) dol_collon – доля колонтитула відносно сторінки;

8) h_pr – висота прямокутника;

9) pust – висота пустоти (зазор між сусідніми прямокутниками);

10) zn – змінна, яка характеризує знак числа, 1 – додатний знак, – 1 – від’ємний;

11) nach – початок виведення прямокутника по осі OY;

12) kol_st – кількість сторінок.

У конструкторі класу виду задані наступні параметри за умовчанням:

CPrint1View::CPrint1View()

{

// -------------- Вхідні данні -------------------

nom_var = 1; // код використання пікселів

count = 5; // кількість прямокутників на сторінці

otstup = 0.5; // доля відступу між прямокутниками

// відносно висоти прямокутника

dol_collon = 1/30.0; //доля колонтитулу відносно сторінки

ots_left = 10; // відступ зліва в міліметрах

// ----------------------------------------------------

}

Тобто кількість прямокутників на сторінці дорівнює 5, відступ між прямокутниками дорівнює половині висоти прямокутника, місце для колонтитулу складає тридцяту частину сторінки, а відступ зліва складає 10 міліметрів.

Виведення прямокутників відбувається таким чином. Спочатку розраховується висота сторінки h_page. Її розрахунок відбувається у пікселях або у 0,01 дюйма в залежності від змінної nom_var. Якщо ми працюємо з пікселями необхідно розрахувати змінні K_px, K_py, відповідно кількість пікселів на дюйм по вісі OX та OY.

Потім розраховується змінна ot_left – відступ зліва у пікселях або у 0,01 дюйма в залежності від змінної nom_var. Так як для роботи з одиницями вимірювання у 0,01 дюйма вісь OY має від’ємні координати, введено змінну zn, яка враховує знак для виведення прямокутника на екран. Якщо zn дорівнює 1 – виведення прямокутників відбувається у пікселях, якщо -1 – у 0,01 дюйма.

Наведемо рядки розрахунку висоти прямокутника h_pr, а також розмір зазору між прямокутниками.

h_pr=(int)((h_page-colontit)/pie + 0.5);

pust=(int)(h_pr*otstup+0.5);

Змінна colontit застосовується тільки для виведення на друк та розраховується наступним чином.

colontit= (int)(h_page*dol_collon + 0.5);

Виведення прямокутників відбувається у циклі, при чому через кожні 5 прямокутників при виведення на друк (count = 5) збільшується кількість сторінок (змінна kol_st) та перераховується початок виведення прямокутника з нової сторінки відносно осі OY (змінна nach).

………………………………………………………………………………………………………………………

if(pDC->IsPrinting() && i%count == 0)

{

kol_st++;

nach = (kol_st*h_page + colontit)*zn;

}

………………………………………………………………………………………………………………………

Після закінчення циклу виведення прямокутників встановлюється скролінг в залежності від номеру варіанту – у пікселях або 0,01 дюйма.

if(nom_var == 1)

SetScrollSizes( MM_TEXT, docSize, pageSize, lineSize );

if(nom_var == 2)

SetScrollSizes( MM_LOENGLISH, docSize, pageSize, lineSize );

При друкуванні документу у даному прикладі доцільно перевантажити наступні функції: OnPreparePrinting – для установки кількості сторінок у вікні «Печать», OnPrint – для друку окремої сторінки. Розглянемо кожну з цих функцій більш детально. Наведемо код функції OnPreparePrinting.

BOOL CPrintAppView::OnPreparePrinting(CPrintInfo* pInfo)

{

CPrintAppDoc* lpDoc = GetDocument();

ASSERT_VALID( lpDoc );

int kol_page = lpDoc->m_nRects % count ?

lpDoc->m_nRects / count +1:lpDoc->m_nRects / count;

pInfo->SetMaxPage(kol_page);

return DoPreparePrinting(pInfo);

}

У даній функції розраховується кількість сторінок – змінна kol_page з розрахунку кількості прямокутників на сторінці (змінна count). Максимальна кількість сторінок для друку встановлюється за допомогою функції SetMaxPage.

Розглянемо функцію OnPrint, яка визивається для попереднього перегляду та для друку кожної окремої сторінки. Наведемо код даної функції.

void CPrintAppView::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

CFont font;

CFont* oldFont;

CString Out;

CRect rect = pInfo-> m_rectDraw;

rect.bottom = (int)(rect.bottom*dol_collon);

font.CreatePointFont((int)(5*rect.bottom),"Arial");

oldFont = pDC->SelectObject(&font);

Out.Format("Страница № %d ", pInfo->m_nCurPage);

pDC->DrawText(Out,rect,

DT_CENTER|DT_VCENTER|DT_SINGLELINE);

pDC-> SetViewportOrg( 0, -pDC->GetDeviceCaps(VERTRES)

*(pInfo->m_nCurPage - 1) );

pDC-> SelectObject( oldFont );

CScrollView::OnPrint(pDC, pInfo);

}

У даній функції в залежності від номеру сторінки pInfo->m_nCurPage виводиться зверху її колонтитул та за допомогою функції SetViewportOrg встановлюється початок виведення для даної сторінки. Початок виведення необхідно задавати тільки у пікселях незалежно від того, яка одиниця вимірювання вибрана.

Початок виведення сторінки по осі OY повинен бути від’ємним, так як кожна сторінка починається з нульової координати. Отже, якщо не встановити початок виведення на друк окремої сторінки – буде постійно виводитись перша сторінка. Так, для виведення першої сторінки – початок виведення буде дорівнювати нулю, для виведення другої сторінки – від’ємна висота сторінки, щоб при виведенні другої сторінки виведення відбувалось з нульової позиції.

Результат попереднього перегляду друку Preview представлений на рис.6.9.

Рис.6.9. Результат попереднього перегляду друку

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]