- •О.С. Зеленський
- •Розділ 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. Формування вхідного документа на основі діалогу
- •Контрольні питання
- •Завдання Робота з типовими елементами керування
- •Робота зі списками і комбінованими полями
- •Список літератури
2.2. Цикли обробки повідомлень
Серцем будь-який Windows-програми є цикл обробки повідомлень (Message Loop), який практично завжди знаходиться у функції WinMain(). Ця функція в Windows-додатках відіграє ту ж роль, що і функція Main() в DOS-додатках, - її викликає операційна система відразу ж після завантаження програми в пам'ять. Програмісти тепер можуть не відволікатися на набирання тексту WinMain(), оскільки це зробить AppWizard. Але це не означає, що сама функція зникла. Текст типової функції WinMain() має наступний вид:
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR IpCmdLine,
int nCmdShow)
{
MSG msg;
if(!InitAppIication(hInstance))
return (FALSE);
if(!InitInstance(hInstance, nCmdShow))
return (FALSE);
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}
У С-програмах для Windows, схожих на цю, функція InitAppIication() викликає RegisterWindow(), a InitInstance() - CreateWindow(). Потім настає черга циклу обробки повідомлень. Він являє собою типову циклічну конструкцію С на базі оператора while, усередині якої викликається функція GetMessage(). Ця функція API заповнює msg кодом повідомлення, яке операційна система розподілила для цього додатка, і майже завжди повертає TRUE. Таким чином, цикл повторюється знову і знову до тих пір, поки працює програма. Єдиний варіант, при якому GetMessage() повертає FALSE, - отримання повідомлення WM_QUIT.
При роботі з повідомленнями, що надходять з клавіатури, деяку частину попередньої обробки бере на себе функція API TranslateMessage(). Її призначення полягає в наступному. Прикладної частини програми немає діла до повідомлень на кшталт "Натиснуто клавішу <А>" і "Звільнено клавішу <А>". Прикладну частину, в кінці кінців, цікавить тільки те, яку літеру (символ) ввів користувач, тобто її цілком задовольнить повідомлення "Введено символ А". Ось це перетворення - кілька повідомлень про деталі процесу в одне повідомлення про його суть - і виконує функція TranslateMessage(). Вона перехоплює повідомлення WM_KEYDOWN і WM_KEYUP і замість них посилає повідомлення WM_CHAR. Звичайно, якщо користуватися бібліотекою MFC, то такі дрібниці, як введення символу А, проходять, як правило, повз вас. Користувач вводить текст в текстовому полі або в інший елемент керування, і турбота програміста - витягти введений текст з цього об'єкта після того, як користувач клацне на ОК. Як був організований прийом символів з клавіатури, тепер вже не наша справа. Таким чином, на функцію TranslateMessage() можна не звертати особливої уваги.
Функція API DispatchMessage() викликає, у свою чергу, функцію WndProc() того вікна, для якого предназначено повідомлення. Типова функція WndProc() у, С-програмі для Windows являє собою величезний оператор switch з окремими case для кожного повідомлення, який додаток має намір самостійно обробляти. Текст її приведено далі:
LONG API ENTRY MainWndProc( HWND hwnd, // Дескриптор вікна.
UINT msg, // Тип повідомлення.
UINT wParam, // Додаткова інформація.
LONG lParam) // Додаткова інформація.
switch (msg){
case WM_MOUSEMOVE: {
// Обробка переміщення миші.
break;
case WM_LBUTTONDOWN: {
// Обробка клацання лівою кнопкою миші.
break;
case WM_RBUTTONDOWN: {
// Обробка клацання правою кнопкою миші.
break;
case WM_PAINT:
// Перемалювати вікно.
break;
case WM_DESTROY: // Повідомлення: вікно буде знищено.
PostQuitMessage(0);
return 0;
break;
default:
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
return (0);
}
Ви, звичайно, можете собі уявити, якої довжини досягає подібна функція в більш-менш порядному додатку. Супроводжувати таку програму дуже важко. MFC вирішує проблему в такий спосіб – інформація про повідомлення, які мають оброблятися, розташована ближче до функцій, які і повинні виконувати обробку. Таким чином, відпадає необхідність у величезних операторах switch, в яких зосереджено розподіл повідомлень.