- •О.С. Зеленський
- •Розділ 1. Загальні відомості створення додатку windows
- •1.1. Створення додатку Windows за допомогою майстра AppWizard
- •1.2. Варіанти майстрів для різних проектів
- •1.3. Короткий опис sdi програми
- •1.4. Короткий опис mdi програми
- •1.5. Короткий опис простого діалогового додатку
- •Контрольні питання
- •Розділ 2. Повідомлення і команди
- •2.1. Обробка повідомлень
- •2.2. Цикли обробки повідомлень
- •2.3. Карти повідомлень
- •Контрольні питання
- •Розділ 3. Документи та види
- •3.1. Клас додатку
- •3.2. Клас головного вікна
- •3.3. Клас документа
- •3.4. Класи виду
- •Контрольні питання
- •Розділ 4. Робота з клавіатурою, мишею і меню
- •4.1. Робота з клавіатурою
- •4.2. Робота з мишею
- •4.3. Робота з меню
- •Контрольні питання
- •Розділ 5. Виведення на екран
- •5.1. Класи графічних об'єктів
- •5.2. Робота зі шрифтами
- •5.3. Робота з пензликами та малювання графічних фігур
- •5.4. Робота з пензликом
- •5.5. Робота зі скролінгом
- •5.6. Приклад роботи з таблицями
- •5.7. Малювання на екрані маніпулятором "миша"
- •5.8. Завантаження та виведення на екран бітових зображень
- •5.9. Копіювання бітових образів
- •5.10. Малювання графічних об'єктів з використанням резинових контурів та метафайлів
- •5.11. Виділення графічних об'єктів у прямокутній області
- •5.12. Універсальний приклад роботи з двовимірною графікою з використанням резинового контуру
- •5.13. Запис на диск та зчитування з диску графічних об'єктів
- •5.14. Побудова кругових діаграм і гістограм
- •5.15. Користувацький режим роботи з графікою на прикладі малювання годинника Clock
- •Контрольні питання
- •Завдання
- •Розділ 6. Друк і попередній перегляд документів
- •6.1. Вибір і налаштування параметрів друку
- •6.2. Створення контекста пристрою
- •6.3. Друк документів і бібліотека mfc
- •6.4. Масштабування
- •6.5. Друк багатосторінкового документа
- •Контрольні питання
- •Розділ 7. Робота з файлами
- •7.1. Приклад роботи з файлами на основі класів cFile, cStdioFile та потоку fstream
- •7.1.1. Робота з класом cFile
- •7.1.2. Робота з потоком fstream
- •Можливі режими доступу
- •7.1.3. Робота з класом cStdioFile
- •7.2. Серіалізація даних, клас cArchive
- •7.3. Використання реєстру в додатках
- •Контрольні питання
- •Завдання
- •Розділ 8. Діалогові вікна
- •8.1. Створення діалогового вікна та простіші елементи керування
- •8.2. Робота зі списками і комбінованими полями
- •8.3. Ускладнений приклад зі списками
- •8.4. Робота з повзунками
- •8.5. Виведення бітових матриць в діалозі та у вікні виду
- •8.6. Лінійний регулятор, лінійний індикатор, інкриментний регулятор
- •8.7. Стандартні діалоги вибору файлів, шрифтів та кольору
- •8.8. Взаємоз'вязок діалога, документа та виду при розробці додатку
- •8.8.1. Клас cDialDoc
- •8.8.2. Клас cDialView
- •8.8.3. Клас Cdlg
- •8.9. Формування вхідного документа на основі діалогу
- •Контрольні питання
- •Завдання Робота з типовими елементами керування
- •Робота зі списками і комбінованими полями
- •Список літератури
5.7. Малювання на екрані маніпулятором "миша"
Приклад роботи малювання на екрані за допомогою мишки знаходиться у папці DISK\GDI\GDI5.
Створимо MDI програму з назвою LineApp, у якій будемо малювати мишею на екрані. Для малювання мишею у вікні додамо у клас виду наступні змінні:
class CLineAppView : public CView
{
.............................................................
CPen pen;
CClientDC* dc;
int nWidth;
};
Де pen – олівець, яким будемо малювати; nWidth – ширина олівця; dc – клієнтський контекст пристрою для малювання. Ініціалізацію змінної nWidth робимо у конструкторі вікна:
CLineAppView::CLineAppView()
{
nWidth = 1;
}
Для створення об’єкту клієнтського контексту вікна створимо функцію OnCreate, яка викликається при появі вікна.
int CLineAppView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
dc = new CClientDC(this);
return 0;
}
Додамо функцію на натиснення лівої кнопки миші, напишемо у ній наступний код:
void CLineAppView::OnLButtonDown(UINT nFlags, CPoint point)
{
pen.DeleteObject();
pen.CreatePen(PS_SOLID, nWidth, RGB(0,0,0));
dc->SelectObject(&pen);
dc->MoveTo(point);
CView::OnLButtonDown(nFlags, point);
}
При натисненні лівої кнопки миші ми створюємо олівець для малювання у змінній pen, після чого завантажуємо створений олівець у контекст клієнтського вікна dc. Через функцію MoveTo фіксуємо координати курсора миші.
Додамо функцію на переміщення миші, напишемо у ній наступний код:
void CLineAppView::OnMouseMove(UINT nFlags, CPoint point)
{
if(nFlags==MK_LBUTTON)
dc->LineTo(point);
CView::OnMouseMove(nFlags, point);
}
До функції OnMouseMove надходить змінна nFlags, яка зберігає константу натиснення кнопки миші. Так, якщо користувач переміщує мишку та при цьому натиснута ліва кнопка миші – змінна nFlags дорівнює MK_LBUTTON, якщо права кнопка миші – MK_RBUTTON.
Отже, якщо включено режим малювання (nFlags==MK_LBUTTON) то виводимо лінію через функцію LineTo.
Для зміни товщини лінії додамо функцію на натиснення правої кнопки миші, напишемо наступний код:
void CLineAppView::OnRButtonDown(UINT nFlags, CPoint point)
{
nWidth++;
CView::OnRButtonDown(nFlags, point);
}
Результат роботи програми на рис. 5.12:
Рис. 5.12. Малювання мишею ліній у вікні
5.8. Завантаження та виведення на екран бітових зображень
Приклад завантаження та виведення на екран бітових зображень знаходиться у папці DISK\GDI\GDI6.
Створимо SDI-додаток з назвою Kart для роботи з бітовими зображеннями. Роботу з бітовими зображеннями слід розділити на два етапи:
Завантаження бітового зображення.
Виведення на екран бітового зображення.
Завантажувати зображення у форматі *.bmp можна двома засобами: використовуючи файл ресурсів та зчитування зображення безпосередньо з файлу *.bmp.
Зберігання зображення у ресурсах самого додатку збільшить розмір виконавчого *.exe файлу, але при цьому окремі файли зображень стануть непотрібними. Для зчитування зображень із ресурсів програми використовується функція LoadBitmap класу CBitmap.
У даній програмі створюються три ідентифікатори ресурсів для роботи з картинками – IDB_BITMAP1, IDB_BITMAP2 та IDB_BITMAP3. Кожен з цих ресурсів посилається на файл з розширенням *.bmp, відповідно «BMP\audi.bmp», «BMP\BMW.bmp», «BMP\GAZ.bmp».
На рис. 5.13. наведемо властивості ресурсу з ідентифікатором IDB_BITMAP1.
Для зчитування зображення безпосередньо з файлу *.bmp використовується функція WinAPI LoadImage.
Рис. 5.13. Властивості ресурсу Bitmap з ідентифікатором IDB_BITMAP1
Наведемо вхідні параметри цієї функції:
HANDLE LoadImage(
// вказівка на додаток, який містить зображення
HINSTANCE hinst,
// текст з найменуванням файлу зображення
LPCTSTR lpszName,
// тип зображення
UINT uType,
// ширина зображення
int cxDesired,
// висота зображення
int cyDesired,
// прапорці для зчитування
UINT fuLoad );
Розроблена програма завантажує зображення двома засобами – за допомогою зчитування з файлу ресурсів (функція LoadBitmap класу CBitmap) та за допомогою зчитування з файлу *.bmp (функція LoadImage).
Меню «Картинка на экране 1» призначено для роботи з картинками, які завантажуються з ресурсів (Audi, Bmw, Gaz). Цим картинкам відповідають значення змінної kod_graf від 1 до 3. Крім того, тут передбачено включення та виключення таймеру (опції меню «Включить таймер», «Выключить таймер») по якому відбувається почергове виведення картинок – Audi, Bmw, Gaz.
Опція меню «Картинка на экране 2» призначена для роботи з картинкою, яка завантажується з файлу «BMP\opel.bmp».
Опція меню «Коллаж картинок» призначено для виведення колажу картинок на екрані дисплею.
Наведемо функції відгуків кожної з цих опцій меню.
void CKartView::OnM1()
{
kod_graf = 1;
Invalidate();
}
void CKartView::OnM2()
{
kod_graf = 2;
Invalidate();
}
void CKartView::OnM3()
{
kod_graf = 3;
Invalidate();
}
void CKartView::OnT1()
{
//Включення таймеру
SetTimer(1,500,0);
}
void CKartView::OnT2()
{
//Відключення таймеру
KillTimer(1);
}
// Завантаження картинки з файлу
void CKartView::OnK2()
{
//Відключення таймеру
KillTimer(1);
//Перевірка наявності папки і файлу, а також
//структури файлу та отримання дескриптору startBitmap
if(access("BMP",0))
{
MessageBox("Отсутствует папка BMP,\nгде должны находится файлы *.bmp\nдля работы с картинками \n","Внимание!",MB_ICONINFORMATION);
return;
}
if(access("BMP\\opel.bmp",0))
{
MessageBox("В папке BMP отсутствует файл opel.bmp","Внимание!",MB_ICONINFORMATION);
return;
}
//Завантаження картинки з файлу
HBITMAP startBitmap = (HBITMAP)LoadImage(NULL,
"BMP\\opel.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
if (!startBitmap)
{
MessageBox("В папке BMP ошибочная структура файла opel.bmp","Внимание!",MB_ICONINFORMATION);
return;
}
else
DeleteObject(startBitmap);
kod_graf = 4;
Invalidate();
}
void CKartView::OnK3()
{
//Відключення таймеру
KillTimer(1);
kod_graf = 5;
Invalidate();
}
У функціях відгуку OnM1, OnM2, OnM3 змінній kod_graf привласнюється значення, відповідно, 1, 2, 3 та визивається метод OnDraw. У функції відгуку OnT1 відбувається включення таймеру за допомогою функції SetTimer:
SetTimer(1,500,0);
У даній функції 1 – це ідентифікатор таймеру, 500 – кількість мілісекунд, через яку спрацює функція OnTimer (повідомлення ON_WM_TIMER()). Це значення відповідає половині секунди. У функції відгуку OnT2 відбувається відключення таймеру за допомогою функції KillTimer з вказанням відповідного ідентифікатору – 1:
KillTimer(1);
Наведемо функцію відгуку OnTimer.
void CKartView::OnTimer(UINT nIDEvent)
{
if(kod_graf==0||kod_graf>2)kod_graf=1;
else kod_graf++;
Invalidate();
CView::OnTimer(nIDEvent);
}
У даній функції відбувається збільшення змінної kod_graf в діапазоні від 1 до 3, що відповідає опціям меню Audi, Bmw, Gaz, після чого спрацьовує Invalidate, який викликає метод OnDraw.
У функції відгуку OnK2 відбувається завантаження картинки з файлу «BMP\opel.bmp». Спочатку використовуючи функцію access перевіряється наявність папки BMP та файлу opel.bmp в ній. Якщо такої папки або файлу не існує – на екрані дисплею з’явиться відповідне повідомлення. Далі, використовуючи функцію LoadImage завантажимо картинку з файлу.
HBITMAP startBitmap = (HBITMAP)LoadImage(NULL,
"BMP\\opel.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
Дана функція використовується для контролю та повертає значення 0 при невідповідності формату, або дескриптор startBitmap типу HBITMAP, якщо відкриття пройшло успішно.
Якщо картинку відкрито успішно змінній kod_graf привласнюється значення 4 та визивається метод OnDraw.
У функції відгуку OnK3 відбувається відключення таймеру та змінній kod_graf привласнюється значення 5 після чого визивається метод OnDraw.
Отже всі перелічені функції відгуку викликають метод OnDraw для виведення зображень на екран дисплею.
Наведемо текст даної функції:
void CKartView::OnDraw(CDC* pDC)
{
CKartDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(!kod_graf)return;
CDC mem;
CBitmap bm;
BITMAP bb;
CRect rect;
mem.CreateCompatibleDC(pDC);
GetClientRect(&rect);
//Завантаження картинки з ресурсу
if(kod_graf>0&&kod_graf<4)
{
//Завантаження картинки
bm.LoadBitmap(IDB_BITMAP1+kod_graf-1);
//Отримання ширини та висоти картинки
//(структура BITMAP)
bm.GetBitmap(&bb);
//Завантаження картинки в контекст пам’яті, та
//виведення її з контексту
mem.SelectObject(&bm);
int x,y;
x = (rect.Width()-bb.bmWidth)/2;
y = (rect.Height()-bb.bmHeight)/2;
pDC->BitBlt(x, y, bb.bmWidth, bb.bmHeight, &mem,
0,0,SRCCOPY);
}
//Завантаження картинки з файлу
if(kod_graf==4)
{
HBITMAP startBitmap = (HBITMAP)LoadImage(NULL,
"BMP\\opel.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
bm.Attach(startBitmap);
bm.GetBitmap(&bb);
mem.SelectObject(&bm);
pDC->StretchBlt(0, 0,rect.Width(),rect.Height(),
&mem,0,0,bb.bmWidth,bb.bmHeight,SRCCOPY);
}
//Колаж картинок
if(kod_graf==5)
{
int i,j,kolx,koly;
kolx = 5;
koly = 5;
CRect r1(0,0,rect.Width()/kolx,rect.Height()/koly);
bm.LoadBitmap(IDB_BITMAP1);
bm.GetBitmap(&bb);
mem.SelectObject(&bm);
for(i=0;i<koly;i++)
{
for(j=0;j<kolx;j++)
{
pDC->StretchBlt(r1.left,r1.top, r1.Width(),
r1.Height(),&mem,0,0,bb.bmWidth,
bb.bmHeight,SRCCOPY);
r1.OffsetRect(r1.Width(),0);
}
r1.OffsetRect(-kolx*r1.Width(),r1.Height());
}
}
}
Для виведення картинок на екран дисплею необхідно її спочатку завантажити в контекст пам’яті mem. Створюється даний контекст за допомогою функції CreateCompatibleDC.
Завантаження картинки з ресурсу та її виведення відносно центру вікна продемонстровано у наступному фрагменті коду
//Завантаження картинки з ресурсу
if(kod_graf>0&&kod_graf<4)
{
//Завантаження картинки
bm.LoadBitmap(IDB_BITMAP1+kod_graf-1);
//Отримання ширини та висоти картинки
//(структура BITMAP)
bm.GetBitmap(&bb);
//Завантаження картинки в контекст пам’яті, та
//виведення її з контексту
mem.SelectObject(&bm);
int x,y;
x = (rect.Width()-bb.bmWidth)/2;
y = (rect.Height()-bb.bmHeight)/2;
pDC->BitBlt(x, y, bb.bmWidth, bb.bmHeight, &mem,
0,0,SRCCOPY);
}
За допомогою функції LoadBitmap картинка завантажується з ресурсу. За допомогою функції GetBitmap зчитуємо інформацію щодо розмірів картинки у об’єкт bb структури BITMAP. В залежності від клієнтської області вікна rect та розмірів картинки, розраховуємо відступи x та y для виведення картинки на екран. Виведення картинки робиться за допомогою функції BitBlt.
Функція BitBlt копіює бітовий масив з одного контексту пристрою у інший:
BOOL CDC::BitBlt
(
int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop
).
Параметр dwRop визначає растрову операцію, яка використовується при копіюванні бітового масиву з контексту пристрою, заданого параметром pSrcDC у область, що задається параметрами x, y, nWidth та nHeight. Параметри xSrc та ySrc задають верхній лівий кут області контексту пристрою джерела, який і визначає бітовий масив, який треба скопіювати. Для операцій, не вимагаючих бітового масиву у якості джерела, параметр pSrcDC повинен дорівнювати нулю.
У таблиці 5.3 приведено перелік використання растрових операцій:
Таблиця 5.3.
Перелік растрових операцій
Назва растрової операції |
Опис |
BLACKNESS |
задана область замальовується суцільним чорним кольором |
DSTINVERT |
інвертування поточного заповнення |
MERGECOPY |
комбінування поточного заповнення з поточним пензлем за допомогою оператора AND |
MERGEPAINT |
комбінування інвертованого бітового масиву з поточним заповненням за допомогою оператора OR |
NOTSRCCOPY |
копіювання інвертованого бітового масиву |
Продовження таблиці 5.3
Назва растрової операції |
Опис |
NOTSRCERASE |
інвертування результату комбінування поточного заповнення з бітовим масивом за допомогою оператора OR |
PATCOPY |
заповнення області за допомогою поточного пензля |
PATINVERT |
комбінування поточного заповнення з пензлем за допомогою оператора XOR |
PATPAINT |
комбінування інвертованого бітового масиву з поточним пензлем за допомогою оператора OR і комбінування результату цієї операції з поточним заповненням за допомогою оператора OR |
SRCAND |
комбінування поточного заповнення і бітового масиву за допомогою операції AND |
SRCCOPY |
заповнення заданої області бітовим масивом |
SRCERASE |
комбінування бітового масиву і інвертованого поточного заповнення за допомогою операції AND |
SRCINVERT |
комбінування бітового масиву і поточного заповнення за допомогою операції XOR |
SRCPAINT |
комбінування бітового масиву і поточного заповнення за допомогою операції OR |
WHITENESS |
задана область замальовується суцільним білим кольором |
Результат виведення картинки відносно центру екрану приведено на рис. 5.14.
Рис. 5.14. Виведення картинки відносно центру екрану
При завантаженні картинки з файлу, коли kod_graf дорівнює 4, відбувається її виведення у клієнтську область вікна. Виведення у задану область робиться за допомогою функції StretchBlt.
pDC–>StretchBlt(0,0, rect.Width(), rect.Height(),
&mem,0,0,bb.bmWidth,bb.bmHeight,SRCCOPY);
Функція StretchBlt копіює бітовий масив одного контексту в інший, змінюючи розміри.
BOOL CDC::StretchBlt
(
int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop
).
Функція копіює бітовий масив з контексту пристрою, заданого параметром pSrcDC у область, яка задається параметрами x, y, nWidth та nHeight. Параметри xSrc та ySrc визначають верхній лівий кут області контексту пристрою джерела, а параметри nSrcWidth та nSrcHeight – розміри бітового масиву. Якщо параметри nWidth та nSrcWidth мають різні знаки, то вхідний бітовий масив відображується зеркально по вісі x. Якщо параметри nHeight та nSrcHeight мають різні знаки, то вхідний бітовий масив відображується зеркально по вісі OY.
Результат виведення картинки у клієнтській області вікна приведено на рис. 5.15.
При виведенні колажу картинок задається кількість картинок по вісі OX та вісі OY, а потім за допомогою функції StretchBlt відбувається виведення відповідної кількості картинок на екран дисплею.
Результат виведення колажу картинок приведено на рис. 5.16.
Рис. 5.15. Результат виведення картинки у клієнтській області вікна
Рис. 5.16. Результат виведення колажу картинок