Застосування обробників повідомлень

Лекція № 3

Тема: Обробники подій. Концепція документ/представлення

План

1. Використання обробників подій

2. Концепція документ/предсталення

 

Застосування обробників повідомлень

Як відомо, операційна система Windows використовує модель, керовану подіями (event-driven). Це означає, що замість послідовного набору команд додаток містить цикл повідомлень (message loop), який обробляє повідомлення (або події), передавані додатку операційною системою Windows. Як тільки повідомлення отримане, цикл повідомлень бере на себе всю відповідальність за його обробку (зазвичай для цього застосовується обробник повідомлення (message handler) або функція, спеціально написана для обробки конкретного повідомлення). Цикл повідомлень виконується впродовж всього періоду роботи додатку. Виконання циклу завершується під час вступу повідомлення WM_QUIT. Але де ж цей цикл в демонстраційному застосуванні? Якщо "копати" бібліотеку MFC достатньо глибоко, то він виявиться у функції
CWnd: :RunModalLoop, розташованою у файлі thrdcore. cpp. Цей цикл - великий фрагмент складної коди. Не варто турбуватися, якщо він поки не до кінця зрозумілий. На даному етапі розглянемо лише наступне основні моменти.

• За операторами ініціалізації слідує нескінченний цикл for (;;), призначений для обробки повідомлень.

• Усередині цього циклу for розташований цикл while, який спочатку визначає, чи не можна виконати цю роботу в режимі очікування (idle). Як відомо, додатки MFC перехоплюють повідомлення постійно (у фоновому режимі) навіть тоді, коли здавалося б додаток не робить нічого. Таким чином, цикл while перевіряє спочатку стан прапора bldle і з'ясовує, чи достатньо часу, щоб виконати цю частину роботи у фоновому режимі. Для підтвердження того, що додаток не завершив роботу, здійснюється виклик функції PeekMessage, яка повертає значення 0, якщо в черзі немає ніяких повідомлень. Отже, якщо прапор bldle встановлений в стан 1 і в черзі є повідомлення, то виконується код, що посилає окну повідомлення про те, що воно здатне виконати обробку у фоновому режимі.

• Наступний цикл (do) фактично обробляє повідомлення. Це і є цикл повідомлень (message loop), який іноді називають конвеєром повідомлень (message pump), саме він і здійснює в додатку фактичну обробку повідомлень. Звернете увагу, після звернення до функції ContinueModal (що дозволяє упевнитися в тому, що модальний стан повинен бути збережене) код перевіряє наявність в черзі повідомлення WM_QUIT (в цьому випадку функція AfxPurapMessage повертає значення 0). Якщо це так, то здійснюється вихід з функції і завершення роботи додатку. Інакше цикл продовжує отримувати і пересилати повідомлення.

Не дивлячись на те, що це достатньо поверхневий опис процесу обробки повідомлень в додатку MFC, воно зачіпає таку фундаментальну концепцію MFC, як передача повідомлень, що забезпечує прийом повідомлень, посланих додатку з операційної системи Windows, і їх розподіл між обробниками повідомлень. Але як перехопити певне повідомлення? Реалізовуючи обробник події для кнопки ОК, розташованої в діалоговому вікні, розробник фактично організовує перехоплення відповідного повідомлення, хоч це і не цілком очевидно. Для цього в карті повідомлень (message map) створюється запис про те, що повідомлення кнопки BN_CLICKED необхідно передавати на обробку призначеної для користувача функції OnBnClickedOk. Щоб проглянути карту повідомлень, відкрийте файл HelloDialogDlg.cpp і відшукайте рядок, що починається словами BEGIN MESSAGE_MAP. Там розташований наступний код:

 

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

ON_BN_CLICKED(IDOK, OnBnClickedOk)

END MESSAGE MAP()

 

Для успішної роботи з бібліотекою MFC достатньо знати, що існують карти повідомлень, що зв'язують повідомлення і функції, а також різноманітні майстри, які дозволяють створювати ці функції. Докладніша інформація про внутрішню організацію і функціонування таких макросів бібліотеки MFC, як BEGINMESSAGEMAP, приведена в книзі Худоби Вінго (Scot Wingo) MFC Internals.

Тепер розглянемо створення обробника повідомлення для події, що не відноситься до графічного інтерфейсу користувача (GUI — Graphical User Interface). Створити обробник повідомлення BN_CLICKED для кнопки ОК не так вже і складно: достатньо двічі клацнути в редакторові діалогового вікна на кнопці ОК. Але що робити з іншими повідомленнями, для доступу до яких редактор діалогового вікна не допоможе? Наприклад, якщо необхідно обробляти події переміщення або зміни розміру діалогового вікна? Нижче приведена послідовність дій, що дозволяє легко і просто створити обробник, який відобразить відповідне повідомлення, якщо користувач двічі клацне мишею в клієнтській області.

1. Відкрийте представлення Class View (Класи).

2. Знайдіть клас, що відповідає за те діалогове вікно, обробник повідомлень якого необхідно створити. В даному випадку це клас CHelloDialogDlg.

3. Клацніть правою кнопкою миші на імені класу і в контекстному меню, що з'явилося, виберіть пункт Properties (Властивості).

4. У діалоговому вікні Properties (Властивості) клацніть на піктограмі Messages (Повідомлення) (розташованою у верхній частині діалогового вікна). Вікно буде розділено на два стовпці. Перший з них містить список всіх повідомлень, для яких можна створити обробники, а другий — перелік імен всіх вже створених обробників.

5. Клацніть в полі праворуч від ідентифікатора повідомлення WM_LBUTTONDBLCLK. Поле ідентифікатора повідомлення виявиться виділеним, а в полі справа з'явиться кнопка із стрілкою. Вибираючи повідомлення в правому стовпці, звернете увагу на інформаційне поле в нижній частині діалогового вікна, що містить опис повідомлення поточного ідентифікатора. В даному випадку (мал. 1.21) про повідомлення з ідентифікатором WM_LBUTTONDBLCLK мовиться (внизу вікна), що воно "Означає подвійне клацання лівої кнопки миші". Хоча інформація про повідомлення не завжди настільки очевидна, як в даному випадку, вона виявиться вельми корисною при пошуку ідентифікатора, точне ім'я якого невідоме.

Клацання на кнопці із стрілкою розверне список дій, які можна виконати за допомогою обробника цієї події. Оскільки на справжній момент ніяких обробників для події не існує, єдиним пунктом списку буде <Add> OnLButtonDblClk (<Додати> OnLButtonDblClk).

7. Виберіть в списку цей пункт, і середовище розробки Visual Studio самостійно створить як функцию-член на ім'я CHelloDialogDlg: : OnLButtonDblClk, так і елемент карти повідомлень, переадресующий повідомлення WM_LBUTTONDBLCLK саме цій функції. От і все.

 

 

Мал. 1.21. Діалогове вікно Properties дозволяє легко додавати нові обробники повідомлень

 

8. Для перевірки працездатності обробника зміните функцию-член OnLButtonDblClkTaK, щоб вона виглядала таким чином:

 

void CHelloDialogDlg::OnLButtonDblClk(UINT nFlags, CPoint point) {

AfxMessageBox("Ouch! Don't touch me there!");

CDialog::OnLButtonDblClk(nFlags, point);

}

 

9. Відкомпілювавши і запустивши це застосування, можна переконатися, що у відповідь на подвійне клацання в клієнтській області головного діалогового вікна з'являється відповідне повідомлення.

Безумовно, обробник повідомлення можна відредагувати у будь-який момент. Досить відкрити файл, що містить його, і внести зміни до функції. Але як видалити обробник? Один із способів полягає у видаленні прототипу функції (function prototype) з файлу заголовка, видаленні визначення функції (function definition) з файлу реалізації . СРР і видаленні запису з карти повідомлень. Проте такий підхід складний і важкий. Найпростіше видалити обробник повідомлення за допомогою діалогового вікна Properties (Властивості). Перейшовши до поля повідомлення WM_LBUTTONDBLCLK і відкривши список можливих дій, можна відмітити, що тепер він містить два пункти — один для редагування функції, а другий для її видалення. Вибір пункту відповідного видаленню, приведе до повного автоматичного видалення обробника події зі всіх вищеперелічених місць.

Видаляючи обробники за допомогою діалогового вікна Properties, будьте дуже обережні. У попередніх версіях Visual Studio для видалення обробників застосовувався майстер ClassWizard, який не тільки запрошував підтвердження на видалення прототипу і запису в карті повідомлень, але і залишав текст коди, щоб його можна було згодом відновити у разі помилкового видалення.

Діалогове вікно Properties підтвердження при видаленні не запрошує і видаляє обробник події повністю.