Таблица сообщений
Таблица сообщений
В библиотеке классов MFC для обработки сообщений используется специальный механизм, который получил название Message Map – таблица сообщений .
Таблица сообщений состоит из набора специальных макрокоманд, ограниченных макрокомандами BEGIN_MESSAGE_MAP и END_MESSAGE_MAP. Между ними расположены макрокоманды, отвечающие за обработку отдельных сообщений.
Макрокоманда BEGIN_MESSAGE_MAP представляет собой заголовок таблицы сообщений. Она имеет два параметра. Первый параметр содержит имя класса таблицы сообщений. Второй параметр указывает его базовый класс.
Если в таблице сообщений класса отсутствует обработчик для сообщения, оно передается для обработки базовому классу, указанному вторым параметром макрокоманды BEGIN_MESSAGE_MAP. Если таблица сообщений базового класса также не содержит обработчик этого сообщения, оно передается следующему базовому классу и т. д.
В том случае если ни один из базовых классов не может обработать сообщение, выполняется обработка по умолчанию, зависящая от типа сообщения.
• Стандартные сообщения Windows обрабатываются функцией “default window procedure”
• Командные сообщения передаются по цепочке следующему объекту, который может обработать командное сообщение. Более подробно мы расскажем об этой цепочке в главах “Однооконный интерфейс” и “Многооконный интерфейс”
В библиотеке MFC определены несколько макрокоманд, отвечающих за обработку сообщений. Их названия представлены в следующей таблице.
Макрокоманда Устанавливает методы для обработки сообщений ON_WM_<name> Стандартных сообщений операционной системы Windows ON_REGISTERED_MESSAGE Зарегистрированные сообщения операционной системы Windows ON_MESSAGE Сообщений, определенных пользователем ON_COMMAND, ON_COMMAND_RANGE Командных сообщений ON_UPDATE_COMMAND_UI, ON_UPDATE_COMMAND_UI_RANGE Сообщений, предназначенных для обновления пользовательского интерфейса ON_<name>, ON_CONTROL_RANGE Сообщений от органов управленияПеречисленные в таблице макрокоманды имеют различное количество параметров в зависимости от типа обрабатываемых ими сообщений.
Макрокоманда ON_WM_<name>
Обрабатывает стандартные сообщения операционной системы Windows. Вместо <name> указывается имя сообщения без префикса WM_. Так, например для обработки сообщения WM_SIZE предназначена макрокоманда ON_WM_SIZE.
Для обработки сообщений, определенных в таблице сообщений макрокомандами ON_WM_<name>, вызываются одноименные методы. Имя метода обработчика соответствует названию сообщения, без учета префикса WM_.
В классе CWnd определены обработчики для стандартных сообщений. Эти обработчики будут использоваться по умолчанию. Вот некоторые из таких методов.
Сообщение Макрокоманда Метод обработчик WM_CHAR ON_WM_CHAR() afx_msg void OnChar(UINT, UINT, UINT); WM_CREATE ON_WM_CREATE() afx_msg int OnCreate(LPCREATESTRUCT); WM_HSCROLL ON_WM_HSCROLL() afx_msg void OnHScroll(UINT, UINT, CWnd*); WM_KEYDOWN ON_WM_KEYDOWN() afx_msg void OnKeyDown(UINT, UINT, UINT); WM_KEYUP ON_WM_KEYUP() afx_msg void OnKeyUp(UINT, UINT, UINT); WM_LBUTTONDOWN ON_WM_LBUTTONDOWN() afx_msg void OnLButtonDown(UINT, CPoint); WM_LBUTTONUP ON_WM_LBUTTONUP() afx_msg void OnLButtonUp(UINT, CPoint); WM_PAINT ON_WM_PAINT() afx_msg void OnPaint(); WM_SIZE ON_WM_SIZE() afx_msg void OnSize(UINT, int, int); WM_TIMER ON_WM_TIMER() afx_msg void OnTimer(UINT); WM_VSCROLL ON_WM_VSCROLL() afx_msg void OnVScroll(UINT, UINT, CWnd*);Все методы-обработчики определены с ключевым словом afx_msg. Оно позволяет отличить эти методы от остальных методов класса. На этапе препроцессорной обработки ключевое слово afx_msg удаляется. Определение afx_msg вы можете найти в файле afxwin.h:
#define afx_msg
Макрокоманды ON_WM_<name> не имеют параметров. Однако методы, которые вызываются для обработки соответствующих сообщений, имеют параметры, количество и назначение которых зависит от обрабатываемого сообщения.
Когда вы определяете обработчик стандартного сообщения Windows в своем классе, он будет использоваться вместо обработчика определенного в классе CWnd (или другом базовом классе). В любом случае вы можете вызвать метод обработчик базового класса из своего метода обработчика.
Макрокоманда ON_REGISTERED_MESSAGE
Макрокоманда ON_REGISTERED_MESSAGE обслуживает сообщения операционной системы Windows, зарегистрированные с помощью функции RegisterWindowMessage. Параметр nMessageVariable указывает идентификатор сообщения, для которого будет вызываться метод memberFxn.
ON_REGISTERED_MESSAGE(nMessageVariable, memberFxn)
Макрокоманда ON_MESSAGE
Макрокоманда ON_MESSAGE обрабатывает сообщения, определенные пользователем. Идентификатор сообщения (его имя) указывается параметром message. Метод, который вызывается для обработки сообщения, указывается параметром memberFxn.
ON_MESSAGE(message, memberFxn)
Макрокоманда ON_COMMAND
Макрокоманды ON_COMMAND предназначены для обработки командных сообщений. Командные сообщения поступают от меню, кнопок панели управления и клавиш акселераторов. Характерной особенностью командных сообщений является то, что с ними связан идентификатор сообщения.
Макрокоманда ON_COMMAND имеет два параметра. Первый параметр соответствует идентификатору командного сообщения, а второй имени метода, предназначенного для обработки этого сообщения. Таблица сообщений должна содержать не больше одной макрокоманды для командного сообщения.
ON_COMMAND(id, memberFxn)
В общем случае командные сообщения не имеют обработчиков, используемых по умолчанию. Существует только небольшая группа стандартных командных сообщений, имеющих методы обработчики, вызываемые по умолчанию. Эти сообщения соответствуют стандартным строкам меню приложения. Так, например, если вы (или MFC AppWizard) присвоите строке Open меню File идентификатор ID_FILE_OPEN, то для его обработки будет вызван метод OnFileOpen, определенный в классе CWinApp. Список стандартных командных сообщений и их описание представлены в главах “Однооконный интерфейс” и “Многооконный интерфейс”.
Принято, что методы обработчики командных сообщений (как и методы обработчики всех других сообщений) должны быть определены с ключевым словом afx_msg.
Макрокоманда ON_COMMAND_RANGE
Макрокоманда ON_COMMAND ставит в соответствие одному командному сообщению один метод-обработчик. В некоторых случаях более удобно, когда один и тот же метод-обработчик применяется для обработки сразу нескольких командных сообщений с различными идентификаторами. Для этого предназначена макрокоманда ON_COMMAND_RANGE .
Она назначает один метод memberFxn для обработки ряда командных сообщений, идентификаторы которых лежат в интервале от id1 до id2.
ON_COMMAND_RANGE(id1, id2, memberFxn)
Макрокоманда ON_UPDATE_COMMAND_UI
Макрокоманда ON_UPDATE_COMMAND_UI обрабатывает сообщения, предназначенные для обновления пользовательского интерфейса, например меню, панелей управления и позволяет менять их состояние.
Параметр id указывает идентификатор сообщения, а параметр memberFxn имя метода для его обработки.
ON_UPDATE_COMMAND_UI(id, memberFxn)
Методы, предназначенные для обработки данного класса сообщений, должны быть определены с ключевым словом afx_msg и иметь один параметр – указатель на объект класса CCmdUI . Для удобства, имена методов, предназначенных для обновления пользовательского интерфейса, начинаются с OnUpdate:
afx_msg void OnUpdate<имя_обработчика>(CCmdUI* pCmdUI);
В качестве параметра pCmdUI методу передается указатель на объект класса CCmdUI. В нем содержится информация о объекте пользовательского интерфейса, который надо обновить – строке меню или кнопке панели управления. Класс CCmdUI также включает методы, позволяющие изменить внешний вид представленного им объекта пользовательского интерфейса.
Сообщения, предназначенные для обновления пользовательского интерфейса передаются, когда пользователь открывает меню приложения и во время цикла ожидания приложения, когда очередь сообщений приложения становится пуста.
При этом посылается несколько сообщений, по одному для каждой строки меню. С помощью макрокоманд ON_UPDATE_COMMAND_UI можно определить методы-обработчики, ответственные за обновление внешнего вида каждой строки меню и соответствующей ей кнопке на панели управления. Эти методы могут изменять состояние строки меню – отображать ее серым цветом, запрещать ее выбор, отображать около нее символ v и т. д.
Если вы не определите метод для обновления данной строки меню или кнопки панели управления, выполняется обработка по умолчанию. Выполняется поиск обработчика соответствующего командного сообщения и если он не обнаружен, выбор строки меню запрещается.
Дополнительную информацию об обновлении пользовательского интерфейса приложения вы можете получить в разделе “Однооконный интерфейс”.
Макрокоманда ON_UPDATE_COMMAND_UI_RANGE
Макрокоманда ON_UPDATE_COMMAND_UI_RANGE обеспечивает обработку сообщений, предназначенных для обновления пользовательского интерфейса, идентификаторы которых лежат в интервале от id1 до id2. Параметр memberFxn указывает метод используемый для обработки.
ON_UPDATE_COMMAND_UI_RANGE(id1, id2, memberFxn)
Макрокоманда ON_name>
Макрокоманды ON_ <name> предназначены для обработки сообщений от органов управления. Такие сообщения могут передаваться органами управления диалоговой панели. Сообщения от органов управления не имеют обработчиков, используемых по умолчанию. При необходимости вы должны определить их самостоятельно.
Все макрокоманды ON_<name> имеют два параметра. В первом параметре id указывается идентификатор органа управления. Сообщения от этого органа управления будут обрабатываться методом memberFxn.
ON_BN_CLICKED(id, memberFxn)
Макрокоманда ON_CONTROL_RANGE
Макрокоманда ON_CONTROL_RANGE обрабатывает сообщения, идентификаторы которых находятся в интервале от id1 до id2. Параметр wNotifyCode содержит код извещения. Метод-обработчик указывается параметром memberFxn.
ON_CONTROL_RANGE(wNotifyCode, id1, id2, memberFxn)
Забегая вперед
Вы, конечно, можете определить таблицу сообщений класса вручную, однако наиболее удобно воспользоваться для этой цели средствами ClassWizard. ClassWizard не только позволит в удобной форме выбрать сообщения, которые должен обрабатывать ваш класс. Он включит в состав класса соответствующие методы-обработчики. Вам останется только вставить в них необходимый код. К сожалению использовать все возможности ClassWizard можно только в том случае, если приложение создано с использованием средств автоматизированного программирования MFC AppWizard .
Однако ClassWizard не всесилен. Так он не позволяет определить один метод для обработки нескольких сообщений. Как вы уже знаете, для этих целей предназначены макрокоманды ON_COMMAND_RANGE и ON_CONTROL_RANGE. Если вы решите воспользоваться этими макрокомандами, вам придется редактировать таблицу сообщений непосредственно, без использования ClassWizard.
Более подробно об использовании ClassWizard для создания обработчиков сообщений вы можете прочитать в разделе “Средства ClassWizard” главы “Приложение с главной диалоговой панелью”. А сейчас мы рассмотрим механизм обработки сообщений, используемый MFC, на примере нескольких приложений.