Обработка сообщений mfc


Обработка сообщений mfc

Основу любой программы для Windows составляет цикл обработки сообщений. Этот цикл есть у каждой программы для Windows. В MFC у нас есть главный объект CWinApp. Именно он запускает цикл обработки сообщений с помощью функции RUN. Только эта функция определена в классе CWinTread, наследником которого является CWinApp. Вот ее реализация:

Сообщения выбирает функция PeekMessage(). Эта функция очень похожа на GetMessage(). Только главное отличие, что GetMessage() переводит поток в состояние ожидания сообщения, а PeekMessage() возвращает значение NULL. Использование PeekMessage() позволяет проводить фоновые задачи до поступления сообщения. Если сообщений нет, то как видите вызывается функция OnIdle(). Эта функция выполняет всякие фоновые задачи, например, обновляет интерфейс, очищает структуры данных и т.д. Вы можете ее переопределить в CWinApp и нагрузить своими задачами.

MFC о сообщении об обработке

Я обращаюсь к описанию дескриптора дескриптора и практикую его выполнение

Я хочу отправить сообщение определения пользователя, такое как WM_MESSAGE, из диалога нажмите нижний щелчок, чтобы отправить сообщение (SendMessage) для получения основного диалогового окна. В главном диалоговом окне (HandleMessageDlg.cpp и HandleMessage.h) я создаю кнопку, чтобы отображать диалог, В диалоговом окне (AboutDlg.cpp и AboutDlg.h), я закрываю кнопку для отправки WM_MESSAGE

Выполните следующие действия: HandleMessageDlg.cpp

AboutDlg.h
Теперь у меня проблема с

какой параметр является отношением к WM_MESSAGE, является wParam или lParam, может ли я (lParam == WM_MESSAGE) или если (wParam == WM_MESSAGE)

Глава 11. Обработка командных сообщений

Процесс обработки командных сообщений значительно отличается от обработки других сообщений. Обычные сообщения обрабатываются только тем объектом, которому они поступили. Если таблица сообщений класса не содержит обработчика сообщения, будут просмотрены таблицы сообщений его базовых классов. В том случае, если ни один из базовых классов также не содержит обработчика сообщений, выполняется обработка сообщения по умолчанию.

Порядок обработки командных сообщений гораздо сложнее. Командное сообщение, переданное для обработки объекту приложения, может последовательно передаваться другим объектам приложения. Один из объектов, класс (или базовый класс) которого содержит обработчик этого сообщения, выполняет его обработку. Например, командное сообщение, переданное главному окну приложения, в конечном счете может быть обработано активным окном просмотра.

Существует стандартная последовательность объектов приложения, которым передаются командные сообщения. Каждый объект в этой последовательности может обработать командное сообщение, если в его таблице сообщений или таблице сообщений базовых классов есть соответствующая макрокоманда. Необработанные сообщения передаются дальше, другим объектам приложения.

Порядок обработки командых сообщений

Объекты различных классов обрабатывают командные сообщения по-разному. Например, объекты, представляющие главное окно приложения, сначала предоставляют возможность обработать полученное сообщение другим объектам. Только если сообщение остается необработанным, просматривается таблица сообщений класса главного окна приложения. Если и здесь сообщение не обрабатывается, оно направляется другим объектам приложения.

Подавляющее большинство приложений, созданных на основе MFC, использует ряд стандартных командных сообщений, как правило, соответствующих элементам меню или кнопкам панели управления. К ним относятся командные сообщения для завершения работы приложения, создания нового документа, открытия документа, записанного на диске, сохранения документа на диске, вызова справочной системы, управления текстовым редактором и т.д. За каждым таким сообщением зарезервирован отдельный идентификатор.

В отдельных случаях может понадобиться изменить порядок, в котором сообщения передаются для обработки объектам приложения. В этом случае необходимо переопределить виртуальный метод OnCmdMsg. Этот метод первоначально определен в классе CCmdTarget и переопределен в классах CView и CDocument.

Стандартные последовательности обработки сообщений

Ниже описаны стандартные последовательности обработки командных сообщений объектами различных классов.

Главное окно многооконного приложения . Большинство командных сообщений передаются главному окну приложения. Для приложений, имеющих многооконный интерфейс, роль главного окна приложения выполняет объект класса CMDIFrameWnd или объект класса, наследованный от базового CMDIFrameWnd.

Получив сообщение, главное окно приложения сначала предоставляет возможность обработать сообщение активному дочернему окну MDI. Дочерние окна MDI представляют собой объекты класса CMDIChildWnd или класса, наследованного от него.

И только если окно MDI не может обработать сообщение, проверяется таблица сообщений класса главного окна приложения. Следует отметить, что, в свою очередь, окно MDI передает сообщения другим объектам.

Если главное окно приложения также не может обработать командное сообщение, оно передается объекту главного класса приложения. Главный класс приложения наследуется от базового класса CWinApp и приложение имеет только один объект этого класса.

Окна MDI и главное окно однооконного приложения. Для приложений, имеющих однооконный интерфейс, роль главного окна приложения выполняет объект класса CFrameWnd или класса, наследованного от него.

Главное окно однооконного приложения и дочерние MDI-окна многооконного приложения обрабатывают командные сообщения одинаклвым образом. Объект класса CFrameWnd или CMDIChildWnd, которому поступило командное сообщение, передает его соответствующему окну просмотра. Если оно просмотра не может обработать сообщение, проверяется таблица сообщений классов CFrameWnd или CMDIChildWnd.

Если главное окно однооконного приложения или MDI-окно многооконного приложения не может обработать сообщение, оно передается объекту главного класса приложения.

Окна просмотра. В отличие от объектов, представляющих окна типа frame (объекты классов CFrameWnd, CMDIFrameWnd и CMDIChildWnd), окно просмотра в первую очередь проверяет собственную таблицу сообщений. И только в том случае, если командное сообщение не может быть обработано, оно передается документу, связанному с данным окном просмотра.

Документ. Так же как и окно просмотра, объект, представляющий документ, сначала проверяет свою таблицу сообщений. Только в том случае, если в классе документа отсутствует обработчик командного сообщения, оно передается для обработки шаблону данного документа.

Объект, представляющий шаблон документа, проверяет только собственную таблицу сообщений и не передает командные сообщения другим объектам приложения.

Диалоговая панель. Диалоговые панели представляются объектами классов, наследованных от базового класса CDialog, Если командное сообщение, поступившее объекту диалоговой панели, не может быть обработано, оно передается его родительскому окну.

Если родительское окно диалоговой панели также не может обработать командное сообщение, оно передается главному объекту приложения.

Стандартные командные сообщения

Большинство приложений, созданных на основе MFC, использует ряд стандартных командных сообщений, как правило, соответствующих элементам меню или кнопкам панели управления. К ним относятся командные сообщения для завершения работы приложения, создание нового документа, открытия документа, записанного на диске, сохранение документа на диске, вызова справочной системы, управления текстовым редактором и т.д. За каждым таким сообщением зарезервирован отдельный идентификатор.

MFC обеспечивает различный уровень обработки стандартных командных сообщений, начиная от простого резервирования идентификатора до полной обработки отдельных сообщений.

Элемент меню или кнопка панели управления приложения имеет тот же идентификатор, что и командное сообщение. Ниже коротко описаны наиболее важные командные сообщения.

Командные сообщения с идентификаторами ID_FILE_. Данные командные сообщения соответствуют элементам меню File приложений, созданных при помощи средств MFC AppWizard. Обработчики этих сообщений входят в состав различных классов MFC, в том числе CWinApp и CDocument.

Командные сообщения с идентификаторами ID_EDIT_. Эти сообщения соответствуют элементам меню Edit приложений, созданных при помощи средств MFC AppWizard. Это меню обычно используется для выполнения различных операций над документом, отображаемым в окне просмотра.

Класс CEditView содержит обработчики для командных сообщений ID_EDIT_. Если в приложении наследуется класс окна просмотра от базового класса CEditView, то меню Edit будет работать.

Класс CView не содержит стандартных обработчиков для командных сообщений, имеющих идентификаторы ID_EDIT_. Программист должен самостоятельно реализовать их в своем окне просмотра.

Командные сообщения с идентификаторами ID_WINDOW_. Данные сообщения соответствуют элементам меню Window многооконных приложений, созданных при помощи средств MFC AppWizard. Обработка этих командных сообщений возложена на метод OnMDIWindowCmd класса CMDIFr ameWnd.

Командные сообщения с идентификаторами ID_APP_. В MFC определены два командных сообщения с идентификаторами ID_APP_. Они предназначены для завершения приложения и вывода информации о приложении и его авторе.

Командные сообщения с идентификаторами I D_HELP_. Данные сообщения используются справочной системой приложения.

Класс CWinApp содержит методы для обработки командных сообщений, связанный со справочной системой. Если в приложении используется справочная система, программист должен сам вызывать соответствующие методы класса CWinApp для обработки командных сообщений ID_HELP_.

MFC AppWizard позволяет создавать приложение, имеющее справочную систему. В этом случае MFC AppWizard автоматически создает программный код, необходимый для управления справочной системой.

Командные сообщения с идентификаторами ID_VIEW_ . Эти командные сообщения соответствуют элементам меню View приложений, созданных при помощи средств MFC AppWizard. За обработку командных сообщений ID_VIEW_ отвечает класс CFrameWnd.

Обработка сообщений mfc

Самые простые приложения с использованием библиотеки классов MFC можно создавать в Microsoft Developer Studio без применения автоматизированных средств разработки приложений MFC AppWizard. Необходимо только создать проект типа Win32 Application и включить в его установки поддержку библиотеки MFC.

Приложение без главного окна

Самые простые приложения с использованием библиотеки классов MFC можно создавать без применения автоматизированных средств разработки приложений MFC AppWizard. Создадим приложение, отображающее на экране маленькую диалоговую панель, которая содержит строку текста. В этом приложении используется единственный класс, наследованный от базового класса CWinApp. Приведем исходный текст приложения:

В этом приложении определен только один класс — CFirstApp, наследованный от базового класса CWinApp . В класс CFirstApp входит метод InitInstance . Кроме того, определена одна глобальная переменная — theApp.

Для использования в приложении классов или функций библиотеки MFC необходимо включить эту библиотеку в проект приложения. Программные коды библиотеки классов MFC могут использоваться приложением двумя разными способами. Код библиотеки MFC либо непосредственно записывается в выполняемый файл приложения, либо вызывается по мере необходимости из отдельной dll-библиотеки.

Использование для приложения DLL-библиотеки немного ускоряет процесс построения проекта и позволяет создавать выполняемые файлы значительно меньшего размера. Однако сам по себе такой выполняемый файл работать не будет. Для него необходима dll-библиотека. Поэтому, если приложение будет устанавливаться и на других компьютерах, его надо распространять вместе с dll-библиотекой.

Замечание. Если для создания нового приложения используется MFC AppWizard, библиотека MFC подключается автоматически. Программисту не нужно вручную вносить изменения в проектный файл в этом случае.

Рассмотрим, как работает приложение first на уровне исходного текста. Сначала в текст приложения включается файл afxwin.h. В этом файле определены классы, методы, константы и другие структуры для библиотеки классов MFC. Кроме того, включаемый файл afxwin автоматически подключает другой файл — windows.h, необходимый для вызовов функций стандартного программного интерфейса Windows.

Сравним исходный текст приложения first с аналогичным приложением, созданным без использования библиотеки классов MFC. В этом приложении присутствует главная функция приложения WinMain , которая вызывается, когда пользователь или операционная система запускает приложение:

Если посмотреть на текст программы first, то там нет хорошо знакомой функции WinMain . Не видно также переменных, представляющих параметры этой функции.


В приложениях, основанных на классах MFC, функция WinMain скрыта от программиста в определении класса CWinApp . В каждом приложении определяется главный класс приложения, наследуемый от базового класса CWinApp . Приложение должно иметь только один объект главного класса приложения, наследованного от класса CWinApp .

Класс CWinApp выполняет все действия, которые обычно выполняет функция WinMain , — инициализирует приложение, обрабатывает сообщения и завершает приложение. Для этого класс CWinApp включает виртуальные методы InitApplication, InitInstance, Run и ExitInstance .

Чтобы выполнить инициализацию приложения, функция WinMain вызывает методы InitApplication и InitInstance для объекта главного класса приложения. Метод InitApplication выполняет инициализацию на уровне приложения. Программист может переопределить этот метод в своем приложении. Метод InitInstance выполняет инициализацию каждой копии приложения. Обычно этот метод создает главное окно приложения. Программист должен обязательно переопределить этот метод в своем приложении. Остальные методы, например Run, можно не переопределять.

Затем функция WinMain начинает обрабатывать цикл сообщений. Для этого вызывается метод Run . Можно переопределить этот метод, чтобы реализовать собственный цикл обработки сообщений.

Когда приложение заканчивает работу и цикл обработки сообщений завершается, вызывается метод ExitInstance. Программист может переопределить этот метод, чтобы выполнить какие-либо действия перед завершением приложения.

В случае приложения first главный класс приложения CFirstApp наследуется от базового класса CWinApp . При этом базовый класс указан как public . Это означает, что в программе доступны все элементы базового класса CWinApp , объявленные как public . Можно вызывать методы класса CWinApp для объектов класса CFirstApp и обращаться к элементам данных класса CWinApp .

В объявлении класса CFirstApp объявлен виртуальный метод InitInstance . Этот метод переопределяется в приложении. Изначально метод InitInstance определен в классе CWinApp . Он отвечает за инициализацию приложения. Он вызывается каждый раз, когда пользователь запускает приложение. Если пользователь запустит приложение несколько раз, то метод InitInstance будет вызываться каждый раз.

Метод InitInstance обязательно должен быть переопределен в главном классе приложения. Остальные виртуальные методы можно оставить без изменения.

Сразу после объявления главного класса приложения создается объект theApp этого класса. Объект главного класса приложения должен быть определен как глобальный . В этом случае он будет создан сразу при запуске приложения и сможет управлять всей работой приложения. После создания глобального объекта вызывается функция WinMain , определенная в классе CWinApp . Она выполняет свои обычные функции — регистрирует классы окон, создает окно и т.д.

Нельзя создавать два или более объекта класса, наследованного от базового класса CWinApp. Каждое приложение должно иметь один и только один объект главного класса приложения.

Метод InitInstance главного класса приложения CFirstApp служит для инициализации. Он вызывается автоматически всякий раз, когда запускается очередная копия приложения. В приложении first метод InitInstance используется для вывода на экран диалоговой панели при помощи функции AfxMessageBox , определенной в MFC.

Вместо функции AfxMessageBox можно воспользоваться функцией MessageBox программного интерфейса Windows. Когда из приложения, созданного с использованием классов MFC, вызываются функции программного интерфейса Windows, необходимо указывать перед именем функции символы . Например, вызов функции MessageBox будет выглядеть следующим образом:

В конце метода InitInstance вызывается оператор return и возвращается значение FALSE. Приложение сразу же завершается. Если метод InitInsatnce вернет значение TRUE, приложение продолжит свою работу и приступит к обработке очереди сообщений.

Приложение с главным окном

Приложение first не имело главного окна. Для вывода сообщения на экран использовалась функция AfxMessageBox , которая очень похожа на функцию MessageBox программного интерфейса Windows.

Рассмотрим другое приложение- приложение start, оно несколько сложнее предыдущего. При запуске оно отображает на экране компьютера обычное окно, имеющее заголовок, системное меню и кнопки управления.

Точно так же, как и в приложении first, во втором приложении используется класс CWinApp в качестве главного класса приложения. Для управления окном приложения создается еще один класс, наследуемый от базового класса CFrameWnd, входящего в библиотеку MFC.

Приложение start очень простое — оно состоит из одного главного окна и не содержит ни меню, ни каких-либо других органов управления. И тем не менее главное окно приложения обладает всеми возможностями Windows-окон. Оно имеет заголовок, системное меню и кнопки управления. Можно изменить размер этого окна, увеличить его на весь экран и уменьшить до размера пиктограммы.

В исходных текстах определяется главный класс CStartApp приложения, который наследуется от базового класса CWinApp . При этом базовый класс указан как public . Можно вызывать методы класса CWinApp для объектов класса CStartApp и обращаться к элементам данных класса CWinApp .

В определении класса CStartApp объявлен виртуальный метод InitInstance . Он переопределяется в файле реализации класса. После объявления главного класса приложения и переопределения функции InitInstance Метод InitInstance главного класса приложения CStartApp служит для инициализации. Он вызывается автоматически каждый раз, когда запускается очередная копия приложения.

Второй класс, класс CMainWindow, наследуется от базового класса CFrameWnd как public и представляет главное окно приложения. В классе главного окна определяется только конструктор.

В данном приложении метод InitInstance используется для отображения на экране окна приложения. Для этого создается объект класса CMainWindow и записывается указатель на этот объект в элемент данных m_pMainWnd класса CWinThread (этот класс является базовым для класса CWinApp ). Таким образом, объект приложения и объект окна приложения связываются вместе.

Для создания объекта класса CMainWindow используется оператор new. Он создает объект указанного класса, отводит память и возвращает указатель на него. При создании нового объекта класса окна оператором new для автоматически вызывается конструктор.

Само окно появится на экране только после того, как будет вызван метод ShowWindow . В качестве параметра методу ShowWindow передается значение m_nCmdShow . Переменная m_nCmdShow является элементом класса CWinApp . Его назначение соответствует параметру функции WinMain , который определяет, как должно отображаться главное окно приложения сразу после его запуска.

После появления окна на экране ему передается сообщение WM_PAINT при помощи вызова метода UpdateWindow . По этому сообщению приложение должно обновить содержимое окна.

В конце метода InitInstance вызывается оператор return и возвращается значение TRUE, означающее, что инициализация приложения завершилась успешно и можно приступать к обработке очереди сообщений (eсли метод InitInstance вернет значение FALSE, приложение немедленно завершится; эта возможность использовалась в приложении first).

Для создания окна приложения создается объект класса CMainWindow. Такой объект — это не окно, которое пользователь видит на экране компьютера . Этот объект является внутренним представлением окна . Для создания окна предназначается метод Create , определенный в классе CFrameWnd . Он создает окно и связывает его с объектом C++, в случае приложения start — с объектом класса CMainWindow. Метод Create вызывается в конструкторе класса CMainWindow.

Илон Маск рекомендует:  Что такое код asp @enablesessionstate

Обработка окном сообщений

Работа операционной системы Windows основана на обработке сообщений. Когда пользователь работает с устройствами ввода/вывода (например, клавиатурой или мышью), драйверы этих устройств создают сообщения, описывающие его действия.

Сообщения сначала попадают в системную очередь сообщений операционной системы. Из нее сообщения передаются приложениям, которым они предназначены, и записываются в очередь приложений . Каждое приложение имеет собственную очередь сообщений.

Приложение в цикле, который называется циклом обработки сообщений , получает сообщения из очереди приложения и направляет их соответствующей функции окна, которая и выполняет обработку сообщения. Цикл обработки сообщений в традиционной Windows-программе обычно состоял из оператора while, в котором циклически вызывались функции GetMessage и DispatchMessage. Для более сложных приложений цикл обработки сообщений содержал вызовы других функций (TranslateMess a ge, TranslateAccelerator). Они обеспечивали предварительную обработку сообщений.

Каждое окно приложения имеет собственную функцию окна. В процессе обработки сообщения операционная система вызывает функцию окна и передает ей структуру, описывающую очередное сообщение. Функция обработки сообщения проверяет, какое именно сообщение поступило для обработки, и выполняет соответствующие действия.

Если при создании приложения используется библиотека классов MFC, то за обработку сообщений отвечают классы. Любой класс, наследованный от базового класса CCmdTarget , может обрабатывать сообщения. Чтобы класс смог обрабатывать сообщения, необходимо, чтобы он имел таблицу сообщений класса . В этой таблице для каждого сообщения указан метод класса, предназначенный для его обработки.

Группы сообщений

Сообщения, которые могут обрабатываться приложением, построенным с использованием библиотеки классов MFC, делятся на 3 группы.

Эта группа включает сообщения, предназначенные для обработки функцией окна. Практически все сообщения, идентификаторы которых начинаются префиксом WM_ , за исключением WM_COMMAND ,. относятся к этой группе.

Оконные сообщения предназначаются для обработки объектами, представляющими окна. Это могут быть практически любые объекты класса CWnd или классов, наследованных от него (CFrameWnd, CMDIFrameWnd, CMDIChildWnd, CView, CDialog) . Характерной чертой этих классов является то, что они включают идентификатор окна.

Большинство этих сообщений имеют параметры, детально характеризующие сообщение.

Сообщения от органов управления

Эта группа включает в себя сообщения WM_COMMAND от дочерних окон (включая окна стандартных классов), передаваемых их родительскому окну. Сообщения от органов управления обрабатываются точно таким же образом, что и оконные сообщения.

Исключение составляет сообщение WM_COMMAND с кодом извещения BN_CLICKED . Это сообщение передается кнопкой, когда пользователь на нее нажимает. Обработка сообщений с кодом извещения BN_CLICKED от органов управления происходит аналогично обработке командных сообщений.

Это сообщения WM_COMMAND от меню, кнопок панели управления и клавиш акселераторов. В отличие от оконных сообщений и сообщений от органов управления командные сообщения могут быть обработаны более широким спектром объектов. Эти сообщения обрабатывают не только объекты, представляющие окна, но также объекты классов, представляющих приложение, документы или шаблон документов.

Характерной особенностью командных сообщений является идентификатор. Идентификатор командного сообщения определяет объект, который вырабатывает (посылает) данное сообщение.

Таблица сообщений

В библиотеке классов MFC для обработки сообщений используется специальный механизм, который имеет название Message Map — таблица сообщений .

Таблица сообщений состоит из набора специальных макрокоманд, ограниченных макрокомандами BEGIN_MESSAGE_MAP и END_MESSAGE_MAP . Между ними расположены макрокоманды, отвечающие за обработку отдельных сообщений:

Макрокоманда BEGIN_MESSAGE_MAP представляет собой заголовок таблицы сообщений. Она имеет два параметра. Первый параметр содержит имя класса таблицы сообщений. Второй — указывает его базовый класс.

Если в таблице сообщений класса отсутствует обработчик для сообщения, оно передается для обработки базовому классу, указанному вторым параметром макрокоманды BEGIN_MESSAGE_MAP . Если таблица сообщений базового класса также не содержит обработчик этого сообщения, оно передается следующему базовому классу и т.д. Если ни один из базовых классов не может обработать сообщение, выполняется обработка по умолчанию, зависящая от типа сообщения:

  • стандартные сообщения Windows обрабатываются функцией обработки по умолчанию;
  • командные сообщения передаются по цепочке следующему объекту, который может обработать командное сообщение.

Можно определить таблицу сообщений класса вручную, однако более удобно воспользоваться для этой цели средствами ClassWizard. ClassWizard не только позволяет в удобной форме выбрать сообщения, которые должен обрабатывать класс. Он включит в состав класса соответствующие методы-обработчики. Программисту останется только вставить в них необходимый код. К сожалению, использовать все возможности ClassWizard можно только в том случае, если приложение создано с применением средств автоматизированного программирования MFC AppWizard.

Рассмотрим макрокоманды, отвечающие за обработку различных типов сообщений.

Макрокоманда ON_WM_ . Обрабатывает стандартные сообщения операционной системы Windows. Вместо указывается имя сообщения без префикса WM_. Например:

Для обработки сообщений, определенных в таблице макрокомандой On_WM_ , вызываются одноименные методы. Имя метода обработчика соответствует названию сообщения, без учета префикса WM_. В классе CWnd определены обработчики для стандартных сообщений. Эти обработчики будут использоваться по умолчанию.

Макрокоманды ON_WM_ не имеют параметров. Однако методы, которые вызываются для обработки соответствующих сообщений, имеют параметры, которые, количество и назначение которых зависит от обрабатываемого сообщения.


Если определить обработчик стандартного сообщения Window в своем классе, то он будет вызываться вместо обработчика, определенного в классе CWnd (или другом базовом классе). В любом случае можно вызвать метод-обработчик базового класса из своего метода-обработчика.

Макрокоманда ON_REGISTERED_MESSAGE. Эта макрокоманда обслуживает сообщения операционной системы Windows, зарегистрированные с помощью функции RegisterWindowMessage . Параметра nMessageVariable этой макрокоманды указывает идентификатор сообщения, для которого будет вызываться метод memberFxn:

Макрокоманда ON_MESSAGE. Данная макрокоманда обрабатывает сообщения, определенные пользователем. Идентификатор сообщения (его имя) указывается параметром message. Метод, который вызывается для обработки сообщения, указывается параметром memberFxn:

Макрокоманда ON_COMMAND. Эти макрокоманды предназначены для обработки командных сообщений. Командные сообщения поступают от меню, кнопок панели управления и клавиш акселераторов. Характерной особенностью командных сообщений является то, что с ними связан идентификатор сообщения.

Макрокоманда ON_COMMAND имеет два параметра. Первый параметр соответствует идентификатору командного сообщения, а второй — имени метода, предназначенного для обработки этого сообщения. Таблица сообщений должна содержать не больше одной макрокоманды для командного сообщения:

Обычно командные сообщения не имеют обработчиков, используемых по умолчанию. Существует только небольшая группа стандартных командных сообщений, имеющих методы-обработчики, вызываемые по умолчанию. Эти сообщения соответствуют стандартным строкам меню приложение. Так например, если строке Open меню File присвоить идентификатор ID_FILE_OPEN, то для его обработки будет вызван метод OnFileOpen, определенный в классе CWinApp.

Макрокоманда ON_COMMAND_RANGE. Макрокоманда ON_COMMAND ставит в соответствие одному командному сообщению один метод-обработчик В некоторых случаях более удобно, когда один и тот же метод-обработчик применяется для обработки сразу нескольких командных сообщений с различными идентификаторами. Для этого предназначена макрокоманда ON_COMMAND_RANGE.

Она назначает один метод-обработчик для обработки нескольких командных сообщений, интервалы которых лежат в интервале от id1 до id2:

Макрокоманда ON_UPDATE_COMMAND_UI . Данная макрокоманда обрабатывает сообщения, предназначенные обновления пользовательского интерфейса, например меню, панелей управления, и позволяет менять их состояние.

Параметр id указывает идентификатор сообщения, а параметр memberFxn — имя метода для его обработки:

Методы, предназначенные для обработки данного класса сообщений, должны быть определены с ключевым словом afx_msg и иметь один параметр — указатель на объект класса CCmdUI . Для удобства имена методов, предназначенных для обновления пользовательского интерфейса, начинаются с OnUpdate:

В качестве параметра pCmdUI методу передается указатель на объект класса CCmdUI . В нем содержится информация об объекте пользовательского интерфейса, который нужно обновить, — строке меню или кнопке панели управления. Класс CCmdUI также включает методы, позволяющие изменить внешний вид представленного им объекта пользовательского интерфейса.

Сообщения, предназначенные для обновления пользовательского интерфейса, передаются, когда пользователь открывает меню приложения, а также во время цикла ожидания приложения, когда очередь сообщений приложения становится пуста.

При этом посылается несколько сообщений, по одному для каждой строке меню. С помощью макрокоманд ON_UPDATE_COMMAND_UI можно определить методы-обработчики, ответственные за обновление внешнего вида каждой строки меню и соответствующие ей кнопки на панели управления. Эти методы могут изменять состояние строки меню — отображать ее серым цветом, запрещать ее выбор, отображать около нее символ «галочка» и т.д.

Если не определить метод для обновления данной строки меню или кнопки панели управления, то выполняется обработка по умолчанию. Выполняется поиск обработчика соответствующего командного сообщения, и, если он не обнаружен, выбор строки запрещается.

Макрокоманда ON_UPDATE_COMMAND_UI_RANGE. Эта макрокоманда обеспечивает обработку сообщений, предназначенных для обновления пользовательского интерфейса, идентификаторы которых лежат в интервале от id1 до id2. Параметр memberFxn указывает метод, используемый для обработки:

Макрокоманда ON_ . Данные макрокоманды предназначены для обработки сообщений от органов управления. Такие сообщения могут передаваться органами управления диалоговой панели. Сообщения от органов управления не имеют обработчиков, используемых по умолчанию. При необходимости их нужно определить самостоятельно.

Все макрокоманды ON_ имеют два параметра. В первом параметре id указывается идентификатор органа управления. Сообщения от этого органа управления будут обрабатываться методом memberFxn. Например:

Макрокоманда ON_CONTROL_RANGE. Эта макрокоманда обрабатывает сообщения от органов управления, идентификаторы которых находятся в интервале от id1 до id2. Параметр wNotifyCode содержит код извещения. Метод-обработчик указывается параметром memberFxn:

Приложение, обрабатывающее сообщения

Предыдущие два рассматриваемых приложения, фактически никак не могли взаимодействовать с пользователем. Они не имели ни меню, ни панели управления. И, самое главное, они не содержали обработчиков сообщений.

Рассмотрим теперь приложение, которое имеет меню и содержит обработчики сообщений, передаваемых приложению, когда пользователь открывает меню и выбирает из него строки. Пусть меню приложения состоит из одного пункта Test. Можно выбрать одну из следующих команд — Beep или Exit.

Файл ресурсов, в который включается описание меню, можно построить либо непосредственным созданием нового файла ресурсов, либо при помощи средств AppWizard. В любом случае при создании меню нужно определить название меню или строки меню. Каждый элемент меню должен иметь уникальный идентификатор, однозначно его определяющий:

Файлы, в которых находятся определение классов приложения и главного окна, представлены ниже:

Чтобы объекты класса могли обрабатывать сообщения, в определении класса необходимо поместить макрокоманду DECLARE_MESSAGE_MAP . По принятым соглашениям эта макрокоманда должна записываться в секцию public .

Кроме этого, необходимо также определить таблицу сообщений. Таблица начинается макрокомандой BEGIN_MESSAGE_MAP и заканчивается макрокомандой END_MESSAGE_MAP . Между этими макрокомандами расположены строки таблицы сообщений, определяющие сообщения, подлежащие обработке данным классом, и методы, которые выполняют такую обработку.

Приложение может содержать несколько классов, обладающих собственными таблицами сообщений. Чтобы однозначно определить класс, к которому относится таблица сообщений, имя этого класса записывается в первый параметр макрокоманды BEGIN_MESSAGE_MAP .

Приложение menu обрабатывает только две команды от меню приложения. Для обработки этих команд используют методы, представленные в определении класса CMainFrame.

Приложению может поступать гораздо больше сообщений и команд, чем указано в таблице сообщений класса CMainFrame. Необработанные сообщения передаются для обработки базовому классу — классу CFrameWnd . Класс, который будет обрабатывать сообщения, не указанные в таблице сообщений, указывается во втором параметре макрокоманды BEGIN_MESSAGE_MAP .

Замечание. Если класс приложения тоже обрабатывает сообщения (т.е. имеет таблицу сообщений), и некоторые из сообщений обрабатываются как окном, так и приложением, то нужно понять, какова очередность обработки сообщений тем или иным объектом. Те команды, которые не имеют обработчика в таблице сообщений класса окна, передаются для обработки в класс приложения. Если же команда может быть обработана и в классе окна, и в классе приложения, она обрабатывается только один раз в классе окна. Обработчик класса приложения в этом случае не вызывается.

Общая информация про MFC. Иерархия классов MFC. Место MFC в среде разработчика Visual C++ (стр. 1 из 3)

Общая информация про MFC . Иерархия классов MFC . Место MFC в среде разработчика Visual C ++

Иерархия основных классов MFC . CObject (обеспечивает базовые операции ввода/вывода) →CGDIObject (поддержка графических объектов); CDC (класс, обеспечивающий связь с устройствами); CExeption (обработка исключительных ситуаций в MFC); CFile (базовый класс для обработки файлов); CMenu (поддержка обьектов меню); CCmdTarget (базовый для обработки сообщения)1)→CWnd (базовый класс для окон); СFrameWnd; 2)→CWinThread;CwinApp;

Структура простой MFC программы . Программа на MFC содержит, по крайней мере, 2 класса. И эти классы порождаются от CWnd и CWinThread. Для реализации простой программы сделаем следующую последовательность шагов: 1) Создать класс приложений, порожденный от CWinApp. 2)Создать класс окна, порожденный от CFrameWnd. 3)Для класса приложения объявить функцию InitInstance(). 4) В конструкторе класса окна вызвать функцию Create для создания окна. 5) Объявить глобальный объект приложения. 6) Создать карту сообщения. 7) Подключить заголовочные файлы и определиться с типом объектов.

//App.h class CApp: public CWinApp ; Class CMainWin:public CFrameWnd ; //App.cpp #include #include “App.h” BOOL CApp::InitInstance () CMainWin::CMainWin () CApp App; BEGIN_MESSAGE_MAP (CMainWin, CFrameWnd) END_MESSAGE_MAP ()

MFC — ( Microsoft Foundation Class Library ) базовая библиотека классов; Иерархия классов MFC . Библиотека MFC содержит большую иерархию классов, написанных на C++. В ее вершине находится класс CObject, который содержит различные функции, используемые во время выполнения программы и предназначенные, в частности, для предоставления информации о текущем типе во время выполнения, для диагностики, и для сериализации. Информация о типе времени выполнения. Если указатель или ссылка ссылается на объект, производный от класса CObject, то в этом случае предусмотрен механизм определения реального типа объекта с помощью макроса RUNTIME­ _CLASS(). Хотя в C++ имеется механизм RTTI, механизм, реализованный в MFC, намного более эффективен по производительности.

Диагностика. Каждый класс, производный от CObject, может по запросу проверить свое внутреннее состояние и выдать диагностическую информацию. Это интенсивно используется в MFC при отладке.

Сериализации. Сериализация — это механизм, позволяющий преобразовать текущее состояние объекта в последовательный поток байт, который обычно затем записывается на диск, и восстановить состояние объекта из последовательного потока, обычно при чтении с диска. Это позволяет сохранять текущее состояние приложения на диске, и восстанавливать его при последующем запуске.

Основные классы. Некоторые классы порождаются непосредственно от CObject. Наиболее широко используемыми среди них являются CCmdTarget, CFile, CDC, CGDIObject и CMenu. Класс CCmdTarget предназначен для обработки сообщений. Класс CFile предназначен для работы с файлами. Класс CDC обеспечивает поддержку контекстов устройств. Об контекстах устройств мы будем говорить несколько позднее. В этот класс включены практически все функции графики GDI. CGDIObject является базовым классом для различных DGI-объектов, таких как перья, кисти, шрифты и другие. Класс CMenu предназначен для манипуляций с меню. От класса CCmdTarget порождается очень важный класс CWnd. Он является базовым для создания всех типов окон, включая масштабируемые («обычные») и диалоговые, а также различные элементы управления. Наиболее широко используемым производным классом является CFrameWnd. Как Вы увидите в дальнейшем, в большинстве программ главное окно создается с помощью именно этого класса. От класса CCmdTarget, через класс CWinThread, порождается, наверное, единственный из наиболее важных классов, обращение к которому в MFC-программах происходит напрямую: С WinApp. Это один из фундаментальных классов, поскольку предназначен для создания самого приложения. В каждой программе имеется один и только один объект этого класса. Как только он будет создан, приложение начнет выполняться.

Функции-члены в MFC . Большинство функций, вызываемых в MFC-программе, являются членами одного из классов, определенных в библиотеке. Большинство функций API доступны через функции-члены MFC. Тем не менее, всегда можно обращаться к функциям API напрямую. Иногда это бывает необходимым, но все же в большинстве случаев удобнее использовать функции-члены MFC.

Глобальные функции в MFC . В библиотеке есть ряд глобальных функций. Все они начинаются с префикса Afx. (Когда MFC только разрабатывалась, то проект назывался AFX, ApplicationFramework. После ряда существенных изменений AFX была переработана в MFC, но прежнее название сохранилось во многих идентификаторах библиотеки и в названиях файлов.) Например, очень часто используется функция AfxMessageBox(), отображающая заранее определенное окно сообщения. Но есть и член-функция MessageBox(). Таким образом, часто глобальные функции перекрываются функциями-членами. Файл AFXWIN . H . Все MFC-программы включают заголовочный файл AFXWIN.H. В нем, а также в различных вспомогательных файлах, содержатся описания классов, структур, переменных и других объектов MFC. Он автоматически подключает большинство заголовочных файлов, относящихся к MFC, в том числе и WINDOWS.H, в котором определены все функции WindowsAPI и другие объекты, которые используются при традиционном программировании на С и «чистом» APL.

Каркас MFC -программы .В простейшем случае программа, написанная с помощью MFC, содержит два класса, порождаемые от классов иерархии библиотеки: класс, предназначенный для создания приложения, и класс, предназначенный для создания окна. Другими словами, для создания минимальной программы необходимо породить один класс от CWinApp, а другой — от CFrameWnd. Эти два класса обязательны для любой программы. Кроме создания вышеупомянутых классов, в программе также должна быть организована обработка всех сообщений, поступающих от Windows. В данном примере программа еще ничего полезного не делает, поэтому отвечать на каждое сообщение не нужно. MFC обработает все сообщения, которые нас не интересуют. Тем не менее в этом примере присутствует карта откликов на сообщения, или просто карта сообщений. Позже мы рассмотрим ее подробнее. Для создания стандартного окна в приложении должен наследоваться класс от CFrameWnd. В данном примере он называется CMainWin. Он содержит конструктор и макрос DECLARE_MESSAGE_MAP(). Макрос на самом деле разворачивается в декларацию карты сообщений, которая определяет, какая член-функция класса должна вызываться в ответ на сообщение Windows. Этот макрос применяется для любого окна, в котором обрабатываются сообщения. Он должен быть последним в декларации класса. Само окно создается в конструкторе с помощью вызова функции Create(). Эта функция используется почти во всех приложениях. Она выполняет действия по созданию окна. В этом примере приведен самый простой случай ее использования. Пока нам нужно знать, что второй параметр определяет заголовок окна, а первый чаще всего равен NULL.

Класс САрр приложения порождается от CWinApp. Этот класс отвечает за работу программы. В примере используется член-функция со следующим прототипом: virtualBOOLCWinApp::lnitlnstance(); Это виртуальная функция, которая вызывается каждый раз при запуске программы. В ней должны производиться все действия, связанные с инициализацией приложения. Функция должна возвращать TRUE при успешном завершении и FALSE в противном случае. В нашем случае, в функции сначала создается объект класса CMainWin, и указатель на него запоминается в переменной m_pMainWnd. Эта переменная является членом класса CWinThread. Она имеет тип CWnd* и используется почти во всех MFC-программах, потому что содержит указатель на главное окно. В последующих двух строчках через нее вызываются функции-члены окна. Когда окно создано, вызывается функция с прототипом: BOOLCWnd::ShowWindow(intHow);

Обработка сообщений. Windows взаимодействует с приложением, посылая ему сообщения. Поэтому обработка сообщений является ядром всех приложений. В традиционных приложениях Windows (написанных с использованием только API) каждое сообщение передается в качестве аргументов оконной функции. Там обычно с помощью большого оператора switch определяется тип сообщения, извлекается информация и производятся нужные действия. Это громоздкая и чреватая ошибками процедура. С помощью MFC все делается намного проще. Здесь мы рассмотрим обработку в программе некоторых наиболее часто используемых сообщений.

Обработка сообщений в MFC . В MFC включен набор предопределенных функций-обработчиков сообщений, которые можно использовать в программе. Если программа содержит такую функцию, то она будет вызываться всякий раз, когда поступает связанное с ней сообщение. При наличии дополнительной информации в сообщении она передается в качестве аргументов функции. Для организации обработки сообщений нужно выполнить следующие действия: В карту сообщений программы должна быть включена команда соответствующего сообщения. Прототип функции-обработчика должен быть включен в описание класса, ответственного за обработку данного сообщения. В программу должна быть включена реализация функции-обработчика.

2. Понятие контекста устройства, применение контекстов устройства, обработка сообщений WM HAR , WM _ PAINT

В широком смысле контекст устройства является путем, по которыму Windows-программа, используя соответствующий драйвер, выводит информацию в рабочую область окна. Контекст устройства является структурой, которая полностью определяет состояние этого драйвера и способ вывода информации.

Прежде чем программа начнет выводить информацию в рабочую область окна, она должны получить контекст устройства. Пока это не сделано, нет связи между программой и окном, предназначенным для вывода.

В традиционных Windows-программах контекст устройства получают вызовом функции GetDC() , а освобождают с помощью ReleaseDC() . Поскольку Windows может предоставить лишь небольшое количество контекстов, важно, чтобы программа освободила контекст после окончания работы с ним. MFC имеет соответствующие классы, способные руководить этим процессом. В частности, при создании экземпляра объекта типа CClientDC программе предоставляется контекст устройства. Если этот объект необходимо изъять, вызывается функция ReleaseDC() и контекст устройства автоматически освобождается. Конструктор класса СClientDC записывается в виде:

Обработка сообщений С++ MFC

0 Thoross [2011-11-03 18:25:00]

Поэтому я делаю приложение MFC, которое обрабатывает несколько различных сообщений и будет отображать разные выходные данные, на основе которых было обработано сообщение. Поэтому сейчас у меня есть тот, который обрабатывает сообщение WM_KEYDOWN и отображает это сообщение. Теперь у меня также есть тот, который обрабатывает WM_RBUTTONDOWN и я хочу, чтобы он запускал игру Brick Breaker, которую я делаю. Проблема, с которой я WM_RBUTTONDOWN , заключается в том, что как только я вхожу в WM_RBUTTONDOWN я хочу отключить определенные ключи, чтобы я мог управлять веслом без вызова WM_KEYDOWN .

TL: DR Как отключить определенные ключи из WM_KEYDOWN в MFC.

4 ответа

3 Решение Mark Ransom [2011-11-03 19:11:00]


Вы можете переопределить PreTranslateMessage чтобы просмотреть и обойти сообщение, прежде чем MFC PreTranslateMessage перевод карты сообщений.

Вам не нужно отключать ключи. Это просто до вашего кода, чтобы решить обработать или не использовать ключ в соответствии с состоянием приложения.

0 DanDan [2011-11-03 19:10:00]

Вам нужно переслать ключи, которые вас интересуют, в код, который управляет вашим объектом.

Вам не нужно отключать ключи в приложении. Когда другая программа имеет фокус, все входные данные должны поступать в эту программу.

Обрабатывать сообщения в MFC

Я создал простую программу о CDialog и Timer в MFC.

Проблема, с которой я столкнулся, я думаю, что это очень нормально, но я не могу объяснить, как MFC обрабатывает сообщения в одном или нескольких потоках.

В основном исходный код программы:

Я отлаживаю программу с помощью следующих шагов:

  1. Установите точки останова в двух функциях: OnBtnStartClicked () и OnTimer () и запустите в режиме отладки.
  2. Нажмите на кнопку Пуск, указатель Visual Studio останавливается в OnBtnStartClicked (). Открыв окно Threads, я вижу, что код выполняется в «Главной теме».
  3. Нажмите F5, чтобы продолжить. Отображается окно сообщения. И я ничего не делаю дальше.
  4. В следующие несколько секунд указатель VS останавливается в OnTimer (). Я также вижу в окне Thread и вижу, что код также выполняется в «Main Thread».
  5. Нажмите F5, чтобы продолжить. Второе окно сообщения — дисплей.

Это сбивает меня с толку: на шаге 3 из-за того, что я ничего не делаю дальше, «главный поток» временно приостановлен; но на шаге 4 «главный поток» выполняется непрерывно.

Пожалуйста, помогите мне объяснить, что меня смущает!

1 ответ

Обмен сообщениями Windows — это система, основанная на событиях. Ваша программа находится в цикле, проверяя очередь сообщений и реагируя на события.

Это означает, что когда ваша программа выглядит так, как будто она ждет, когда вы нажмете кнопку OK в окне сообщения, она все еще будет прослушивать события и реагировать на них. Одним из этих событий будет BN_CLICKED для кнопки ОК, а другое — сообщение таймера.

Если программа когда-либо действительно останавливается, ваша программа перестает отвечать на запросы.

Таблица сообщений

В библиотеке классов MFC для обработки сообщений используется специальный механизм, который получил название Message Map – таблица сообщений .

Таблица сообщений состоит из набора специальных макрокоманд, ограниченных макрокомандами BEGIN_MESSAGE_MAP и END_MESSAGE_MAP. Между ними расположены макрокоманды, отвечающие за обработку отдельных сообщений.

Макрокоманда BEGIN_MESSAGE_MAP представляет собой заголовок таблицы сообщений. Она имеет два параметра. Первый параметр содержит имя класса таблицы сообщений. Второй параметр указывает его базовый класс.

Если в таблице сообщений класса отсутствует обработчик для сообщения, оно передается для обработки базовому классу, указанному вторым параметром макрокоманды BEGIN_MESSAGE_MAP. Если таблица сообщений базового класса также не содержит обработчик этого сообщения, оно передается следующему базовому классу и т. д.

В том случае если ни один из базовых классов не может обработать сообщение, выполняется обработка по умолчанию, зависящая от типа сообщения.

• Стандартные сообщения Windows обрабатываются функцией “default window procedure”

• Командные сообщения передаются по цепочке следующему объекту, который может обработать командное сообщение. Более подробно мы расскажем об этой цепочке в главах “Однооконный интерфейс” и “Многооконный интерфейс”

В библиотеке MFC определены несколько макрокоманд, отвечающих за обработку сообщений. Их названия представлены в следующей таблице.

Макрокоманда Устанавливает методы для обработки сообщений
ON_WM_ Стандартных сообщений операционной системы Windows
ON_REGISTERED_MESSAGE Зарегистрированные сообщения операционной системы Windows
ON_MESSAGE Сообщений, определенных пользователем
ON_COMMAND, ON_COMMAND_RANGE Командных сообщений
ON_UPDATE_COMMAND_UI, ON_UPDATE_COMMAND_UI_RANGE Сообщений, предназначенных для обновления пользовательского интерфейса
ON_ , ON_CONTROL_RANGE Сообщений от органов управления

Перечисленные в таблице макрокоманды имеют различное количество параметров в зависимости от типа обрабатываемых ими сообщений.

Обрабатывает стандартные сообщения операционной системы Windows. Вместо указывается имя сообщения без префикса WM_. Так, например для обработки сообщения WM_SIZE предназначена макрокоманда ON_WM_SIZE.

Для обработки сообщений, определенных в таблице сообщений макрокомандами ON_WM_ , вызываются одноименные методы. Имя метода обработчика соответствует названию сообщения, без учета префикса 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:

Макрокоманды ON_WM_ не имеют параметров. Однако методы, которые вызываются для обработки соответствующих сообщений, имеют параметры, количество и назначение которых зависит от обрабатываемого сообщения.

Когда вы определяете обработчик стандартного сообщения Windows в своем классе, он будет использоваться вместо обработчика определенного в классе CWnd (или другом базовом классе). В любом случае вы можете вызвать метод обработчик базового класса из своего метода обработчика.

Макрокоманда ON_REGISTERED_MESSAGE обслуживает сообщения операционной системы Windows, зарегистрированные с помощью функции RegisterWindowMessage. Параметр nMessageVariable указывает идентификатор сообщения, для которого будет вызываться метод memberFxn.

Макрокоманда ON_MESSAGE обрабатывает сообщения, определенные пользователем. Идентификатор сообщения (его имя) указывается параметром message. Метод, который вызывается для обработки сообщения, указывается параметром memberFxn.

Макрокоманды ON_COMMAND предназначены для обработки командных сообщений. Командные сообщения поступают от меню, кнопок панели управления и клавиш акселераторов. Характерной особенностью командных сообщений является то, что с ними связан идентификатор сообщения.

Макрокоманда ON_COMMAND имеет два параметра. Первый параметр соответствует идентификатору командного сообщения, а второй имени метода, предназначенного для обработки этого сообщения. Таблица сообщений должна содержать не больше одной макрокоманды для командного сообщения.

В общем случае командные сообщения не имеют обработчиков, используемых по умолчанию. Существует только небольшая группа стандартных командных сообщений, имеющих методы обработчики, вызываемые по умолчанию. Эти сообщения соответствуют стандартным строкам меню приложения. Так, например, если вы (или MFC AppWizard) присвоите строке Open меню File идентификатор ID_FILE_OPEN, то для его обработки будет вызван метод OnFileOpen, определенный в классе CWinApp. Список стандартных командных сообщений и их описание представлены в главах “Однооконный интерфейс” и “Многооконный интерфейс”.

Принято, что методы обработчики командных сообщений (как и методы обработчики всех других сообщений) должны быть определены с ключевым словом afx_msg.

Макрокоманда ON_COMMAND ставит в соответствие одному командному сообщению один метод-обработчик. В некоторых случаях более удобно, когда один и тот же метод-обработчик применяется для обработки сразу нескольких командных сообщений с различными идентификаторами. Для этого предназначена макрокоманда ON_COMMAND_RANGE .

Она назначает один метод memberFxn для обработки ряда командных сообщений, идентификаторы которых лежат в интервале от id1 до id2.

ON_COMMAND_RANGE(id1, id2, 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 обеспечивает обработку сообщений, предназначенных для обновления пользовательского интерфейса, идентификаторы которых лежат в интервале от id1 до id2. Параметр memberFxn указывает метод используемый для обработки.


ON_UPDATE_COMMAND_UI_RANGE(id1, id2, memberFxn)

Макрокоманды ON_ предназначены для обработки сообщений от органов управления. Такие сообщения могут передаваться органами управления диалоговой панели. Сообщения от органов управления не имеют обработчиков, используемых по умолчанию. При необходимости вы должны определить их самостоятельно.

Все макрокоманды ON_ имеют два параметра. В первом параметре id указывается идентификатор органа управления. Сообщения от этого органа управления будут обрабатываться методом memberFxn.

Макрокоманда 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, на примере нескольких приложений.

Обработка сообщений mfc

Вспомните, что библиотека MFC разработана для изоляции программиста от некоторых запутанных деталей архитектуры приложений Windows. MFC изолирует вас от обработчика событий, предоставляя свой собственный, который вызывает создаваемые вами индивидуальные функции обработки отдельных событий. Это выполняется с помощью карт сообщений . Карта сообщений — это макрос, который сообщает MFC, что вы заинтересованны в обработке определенного события. Все что вам необходимо — это включить карту сообщений и обработчики для каждого события в вашу программу, а MFC позаботится об остальном. Карта сообщений выглядит следующим образом:

Эта карта сообщений указывает MFC, что у нас есть класс, с именем OurClass являющийся производным от класса BaseClass и обрабатывающий три сообщения: WM_PAINT , WM_SIZE и WM_LBUTTONDOWN (это стандартные сообщения Windows).

Теперь вам необходимо написать функцию-обработчик для каждого из этих сообщений. Например, обработчик сообщения WM_PAINT может выглядеть следующим образом:

Все функции обработки событий должны быть объявлены внутри класса. Для рассматриваемых в примере трех функций описание выглядит следующим образом:

Макроопределение afx_msg определяет описываемую функцию как обработчик события, а макроопределение DECLARE_MESSAGE_MAP указывает MFC, что данный класс использует карту сообщений.

Визуальное программирование и MFC.

Самые простые приложения с использованием библиотеки классов MFC можно создавать в Microsoft Developer Studio без применения автоматизированных средств разработки приложений MFC AppWizard. Необходимо только создать проект типа Win32 Application и включить в его установки поддержку библиотеки MFC.

Приложение без главного окна

Самые простые приложения с использованием библиотеки классов MFC можно создавать без применения автоматизированных средств разработки приложений MFC AppWizard. Создадим приложение, отображающее на экране маленькую диалоговую панель, которая содержит строку текста. В этом приложении используется единственный класс, наследованный от базового класса CWinApp. Приведем исходный текст приложения:

В этом приложении определен только один класс — CFirstApp, наследованный от базового класса CWinApp . В класс CFirstApp входит метод InitInstance . Кроме того, определена одна глобальная переменная — theApp.

Для использования в приложении классов или функций библиотеки MFC необходимо включить эту библиотеку в проект приложения. Программные коды библиотеки классов MFC могут использоваться приложением двумя разными способами. Код библиотеки MFC либо непосредственно записывается в выполняемый файл приложения, либо вызывается по мере необходимости из отдельной dll-библиотеки.

Использование для приложения DLL-библиотеки немного ускоряет процесс построения проекта и позволяет создавать выполняемые файлы значительно меньшего размера. Однако сам по себе такой выполняемый файл работать не будет. Для него необходима dll-библиотека. Поэтому, если приложение будет устанавливаться и на других компьютерах, его надо распространять вместе с dll-библиотекой.

Замечание. Если для создания нового приложения используется MFC AppWizard, библиотека MFC подключается автоматически. Программисту не нужно вручную вносить изменения в проектный файл в этом случае.

Рассмотрим, как работает приложение first на уровне исходного текста. Сначала в текст приложения включается файл afxwin.h. В этом файле определены классы, методы, константы и другие структуры для библиотеки классов MFC. Кроме того, включаемый файл afxwin автоматически подключает другой файл — windows.h, необходимый для вызовов функций стандартного программного интерфейса Windows.

Сравним исходный текст приложения first с аналогичным приложением, созданным без использования библиотеки классов MFC. В этом приложении присутствует главная функция приложения WinMain , которая вызывается, когда пользователь или операционная система запускает приложение:

Если посмотреть на текст программы first, то там нет хорошо знакомой функции WinMain . Не видно также переменных, представляющих параметры этой функции.

В приложениях, основанных на классах MFC, функция WinMain скрыта от программиста в определении класса CWinApp . В каждом приложении определяется главный класс приложения, наследуемый от базового класса CWinApp . Приложение должно иметь только один объект главного класса приложения, наследованного от класса CWinApp .

Класс CWinApp выполняет все действия, которые обычно выполняет функция WinMain , — инициализирует приложение, обрабатывает сообщения и завершает приложение. Для этого класс CWinApp включает виртуальные методы InitApplication, InitInstance, Run и ExitInstance .

Чтобы выполнить инициализацию приложения, функция WinMain вызывает методы InitApplication и InitInstance для объекта главного класса приложения. Метод InitApplication выполняет инициализацию на уровне приложения. Программист может переопределить этот метод в своем приложении. Метод InitInstance выполняет инициализацию каждой копии приложения. Обычно этот метод создает главное окно приложения. Программист должен обязательно переопределить этот метод в своем приложении. Остальные методы, например Run, можно не переопределять.

Затем функция WinMain начинает обрабатывать цикл сообщений. Для этого вызывается метод Run . Можно переопределить этот метод, чтобы реализовать собственный цикл обработки сообщений.

Когда приложение заканчивает работу и цикл обработки сообщений завершается, вызывается метод ExitInstance. Программист может переопределить этот метод, чтобы выполнить какие-либо действия перед завершением приложения.

В случае приложения first главный класс приложения CFirstApp наследуется от базового класса CWinApp . При этом базовый класс указан как public . Это означает, что в программе доступны все элементы базового класса CWinApp , объявленные как public . Можно вызывать методы класса CWinApp для объектов класса CFirstApp и обращаться к элементам данных класса CWinApp .

В объявлении класса CFirstApp объявлен виртуальный метод InitInstance . Этот метод переопределяется в приложении. Изначально метод InitInstance определен в классе CWinApp . Он отвечает за инициализацию приложения. Он вызывается каждый раз, когда пользователь запускает приложение. Если пользователь запустит приложение несколько раз, то метод InitInstance будет вызываться каждый раз.

Метод InitInstance обязательно должен быть переопределен в главном классе приложения. Остальные виртуальные методы можно оставить без изменения.

Сразу после объявления главного класса приложения создается объект theApp этого класса. Объект главного класса приложения должен быть определен как глобальный . В этом случае он будет создан сразу при запуске приложения и сможет управлять всей работой приложения. После создания глобального объекта вызывается функция WinMain , определенная в классе CWinApp . Она выполняет свои обычные функции — регистрирует классы окон, создает окно и т.д.

Нельзя создавать два или более объекта класса, наследованного от базового класса CWinApp. Каждое приложение должно иметь один и только один объект главного класса приложения.

Метод InitInstance главного класса приложения CFirstApp служит для инициализации. Он вызывается автоматически всякий раз, когда запускается очередная копия приложения. В приложении first метод InitInstance используется для вывода на экран диалоговой панели при помощи функции AfxMessageBox , определенной в MFC.

Вместо функции AfxMessageBox можно воспользоваться функцией MessageBox программного интерфейса Windows. Когда из приложения, созданного с использованием классов MFC, вызываются функции программного интерфейса Windows, необходимо указывать перед именем функции символы . Например, вызов функции MessageBox будет выглядеть следующим образом:

В конце метода InitInstance вызывается оператор return и возвращается значение FALSE. Приложение сразу же завершается. Если метод InitInsatnce вернет значение TRUE, приложение продолжит свою работу и приступит к обработке очереди сообщений.

Приложение с главным окном

Приложение first не имело главного окна. Для вывода сообщения на экран использовалась функция AfxMessageBox , которая очень похожа на функцию MessageBox программного интерфейса Windows.

Рассмотрим другое приложение- приложение start, оно несколько сложнее предыдущего. При запуске оно отображает на экране компьютера обычное окно, имеющее заголовок, системное меню и кнопки управления.

Точно так же, как и в приложении first, во втором приложении используется класс CWinApp в качестве главного класса приложения. Для управления окном приложения создается еще один класс, наследуемый от базового класса CFrameWnd, входящего в библиотеку MFC.

Приложение start очень простое — оно состоит из одного главного окна и не содержит ни меню, ни каких-либо других органов управления. И тем не менее главное окно приложения обладает всеми возможностями Windows-окон. Оно имеет заголовок, системное меню и кнопки управления. Можно изменить размер этого окна, увеличить его на весь экран и уменьшить до размера пиктограммы.

В исходных текстах определяется главный класс CStartApp приложения, который наследуется от базового класса CWinApp . При этом базовый класс указан как public . Можно вызывать методы класса CWinApp для объектов класса CStartApp и обращаться к элементам данных класса CWinApp .

В определении класса CStartApp объявлен виртуальный метод InitInstance . Он переопределяется в файле реализации класса. После объявления главного класса приложения и переопределения функции InitInstance Метод InitInstance главного класса приложения CStartApp служит для инициализации. Он вызывается автоматически каждый раз, когда запускается очередная копия приложения.

Второй класс, класс CMainWindow, наследуется от базового класса CFrameWnd как public и представляет главное окно приложения. В классе главного окна определяется только конструктор.

В данном приложении метод InitInstance используется для отображения на экране окна приложения. Для этого создается объект класса CMainWindow и записывается указатель на этот объект в элемент данных m_pMainWnd класса CWinThread (этот класс является базовым для класса CWinApp ). Таким образом, объект приложения и объект окна приложения связываются вместе.

Для создания объекта класса CMainWindow используется оператор new. Он создает объект указанного класса, отводит память и возвращает указатель на него. При создании нового объекта класса окна оператором new для автоматически вызывается конструктор.

Само окно появится на экране только после того, как будет вызван метод ShowWindow . В качестве параметра методу ShowWindow передается значение m_nCmdShow . Переменная m_nCmdShow является элементом класса CWinApp . Его назначение соответствует параметру функции WinMain , который определяет, как должно отображаться главное окно приложения сразу после его запуска.

После появления окна на экране ему передается сообщение WM_PAINT при помощи вызова метода UpdateWindow . По этому сообщению приложение должно обновить содержимое окна.

В конце метода InitInstance вызывается оператор return и возвращается значение TRUE, означающее, что инициализация приложения завершилась успешно и можно приступать к обработке очереди сообщений (eсли метод InitInstance вернет значение FALSE, приложение немедленно завершится; эта возможность использовалась в приложении first).

Для создания окна приложения создается объект класса CMainWindow. Такой объект — это не окно, которое пользователь видит на экране компьютера . Этот объект является внутренним представлением окна . Для создания окна предназначается метод Create , определенный в классе CFrameWnd . Он создает окно и связывает его с объектом C++, в случае приложения start — с объектом класса CMainWindow. Метод Create вызывается в конструкторе класса CMainWindow.

Обработка окном сообщений

Работа операционной системы Windows основана на обработке сообщений. Когда пользователь работает с устройствами ввода/вывода (например, клавиатурой или мышью), драйверы этих устройств создают сообщения, описывающие его действия.

Сообщения сначала попадают в системную очередь сообщений операционной системы. Из нее сообщения передаются приложениям, которым они предназначены, и записываются в очередь приложений . Каждое приложение имеет собственную очередь сообщений.


Приложение в цикле, который называется циклом обработки сообщений , получает сообщения из очереди приложения и направляет их соответствующей функции окна, которая и выполняет обработку сообщения. Цикл обработки сообщений в традиционной Windows-программе обычно состоял из оператора while, в котором циклически вызывались функции GetMessage и DispatchMessage. Для более сложных приложений цикл обработки сообщений содержал вызовы других функций (TranslateMess a ge, TranslateAccelerator). Они обеспечивали предварительную обработку сообщений.

Каждое окно приложения имеет собственную функцию окна. В процессе обработки сообщения операционная система вызывает функцию окна и передает ей структуру, описывающую очередное сообщение. Функция обработки сообщения проверяет, какое именно сообщение поступило для обработки, и выполняет соответствующие действия.

Если при создании приложения используется библиотека классов MFC, то за обработку сообщений отвечают классы. Любой класс, наследованный от базового класса CCmdTarget , может обрабатывать сообщения. Чтобы класс смог обрабатывать сообщения, необходимо, чтобы он имел таблицу сообщений класса . В этой таблице для каждого сообщения указан метод класса, предназначенный для его обработки.

Группы сообщений

Сообщения, которые могут обрабатываться приложением, построенным с использованием библиотеки классов MFC, делятся на 3 группы.

Эта группа включает сообщения, предназначенные для обработки функцией окна. Практически все сообщения, идентификаторы которых начинаются префиксом WM_ , за исключением WM_COMMAND ,. относятся к этой группе.

Оконные сообщения предназначаются для обработки объектами, представляющими окна. Это могут быть практически любые объекты класса CWnd или классов, наследованных от него (CFrameWnd, CMDIFrameWnd, CMDIChildWnd, CView, CDialog) . Характерной чертой этих классов является то, что они включают идентификатор окна.

Большинство этих сообщений имеют параметры, детально характеризующие сообщение.

Сообщения от органов управления

Эта группа включает в себя сообщения WM_COMMAND от дочерних окон (включая окна стандартных классов), передаваемых их родительскому окну. Сообщения от органов управления обрабатываются точно таким же образом, что и оконные сообщения.

Исключение составляет сообщение WM_COMMAND с кодом извещения BN_CLICKED . Это сообщение передается кнопкой, когда пользователь на нее нажимает. Обработка сообщений с кодом извещения BN_CLICKED от органов управления происходит аналогично обработке командных сообщений.

Это сообщения WM_COMMAND от меню, кнопок панели управления и клавиш акселераторов. В отличие от оконных сообщений и сообщений от органов управления командные сообщения могут быть обработаны более широким спектром объектов. Эти сообщения обрабатывают не только объекты, представляющие окна, но также объекты классов, представляющих приложение, документы или шаблон документов.

Характерной особенностью командных сообщений является идентификатор. Идентификатор командного сообщения определяет объект, который вырабатывает (посылает) данное сообщение.

Таблица сообщений

В библиотеке классов MFC для обработки сообщений используется специальный механизм, который имеет название Message Map — таблица сообщений .

Таблица сообщений состоит из набора специальных макрокоманд, ограниченных макрокомандами BEGIN_MESSAGE_MAP и END_MESSAGE_MAP . Между ними расположены макрокоманды, отвечающие за обработку отдельных сообщений:

Макрокоманда BEGIN_MESSAGE_MAP представляет собой заголовок таблицы сообщений. Она имеет два параметра. Первый параметр содержит имя класса таблицы сообщений. Второй — указывает его базовый класс.

Если в таблице сообщений класса отсутствует обработчик для сообщения, оно передается для обработки базовому классу, указанному вторым параметром макрокоманды BEGIN_MESSAGE_MAP . Если таблица сообщений базового класса также не содержит обработчик этого сообщения, оно передается следующему базовому классу и т.д. Если ни один из базовых классов не может обработать сообщение, выполняется обработка по умолчанию, зависящая от типа сообщения:

  • стандартные сообщения Windows обрабатываются функцией обработки по умолчанию;
  • командные сообщения передаются по цепочке следующему объекту, который может обработать командное сообщение.

Можно определить таблицу сообщений класса вручную, однако более удобно воспользоваться для этой цели средствами ClassWizard. ClassWizard не только позволяет в удобной форме выбрать сообщения, которые должен обрабатывать класс. Он включит в состав класса соответствующие методы-обработчики. Программисту останется только вставить в них необходимый код. К сожалению, использовать все возможности ClassWizard можно только в том случае, если приложение создано с применением средств автоматизированного программирования MFC AppWizard.

Рассмотрим макрокоманды, отвечающие за обработку различных типов сообщений.

Макрокоманда ON_WM_ . Обрабатывает стандартные сообщения операционной системы Windows. Вместо указывается имя сообщения без префикса WM_. Например:

Для обработки сообщений, определенных в таблице макрокомандой On_WM_ , вызываются одноименные методы. Имя метода обработчика соответствует названию сообщения, без учета префикса WM_. В классе CWnd определены обработчики для стандартных сообщений. Эти обработчики будут использоваться по умолчанию.

Макрокоманды ON_WM_ не имеют параметров. Однако методы, которые вызываются для обработки соответствующих сообщений, имеют параметры, которые, количество и назначение которых зависит от обрабатываемого сообщения.

Если определить обработчик стандартного сообщения Window в своем классе, то он будет вызываться вместо обработчика, определенного в классе CWnd (или другом базовом классе). В любом случае можно вызвать метод-обработчик базового класса из своего метода-обработчика.

Макрокоманда ON_REGISTERED_MESSAGE. Эта макрокоманда обслуживает сообщения операционной системы Windows, зарегистрированные с помощью функции RegisterWindowMessage . Параметра nMessageVariable этой макрокоманды указывает идентификатор сообщения, для которого будет вызываться метод memberFxn:

Макрокоманда ON_MESSAGE. Данная макрокоманда обрабатывает сообщения, определенные пользователем. Идентификатор сообщения (его имя) указывается параметром message. Метод, который вызывается для обработки сообщения, указывается параметром memberFxn:

Макрокоманда ON_COMMAND. Эти макрокоманды предназначены для обработки командных сообщений. Командные сообщения поступают от меню, кнопок панели управления и клавиш акселераторов. Характерной особенностью командных сообщений является то, что с ними связан идентификатор сообщения.

Макрокоманда ON_COMMAND имеет два параметра. Первый параметр соответствует идентификатору командного сообщения, а второй — имени метода, предназначенного для обработки этого сообщения. Таблица сообщений должна содержать не больше одной макрокоманды для командного сообщения:

Обычно командные сообщения не имеют обработчиков, используемых по умолчанию. Существует только небольшая группа стандартных командных сообщений, имеющих методы-обработчики, вызываемые по умолчанию. Эти сообщения соответствуют стандартным строкам меню приложение. Так например, если строке Open меню File присвоить идентификатор ID_FILE_OPEN, то для его обработки будет вызван метод OnFileOpen, определенный в классе CWinApp.

Макрокоманда ON_COMMAND_RANGE. Макрокоманда ON_COMMAND ставит в соответствие одному командному сообщению один метод-обработчик В некоторых случаях более удобно, когда один и тот же метод-обработчик применяется для обработки сразу нескольких командных сообщений с различными идентификаторами. Для этого предназначена макрокоманда ON_COMMAND_RANGE.

Она назначает один метод-обработчик для обработки нескольких командных сообщений, интервалы которых лежат в интервале от id1 до id2:

Макрокоманда ON_UPDATE_COMMAND_UI . Данная макрокоманда обрабатывает сообщения, предназначенные обновления пользовательского интерфейса, например меню, панелей управления, и позволяет менять их состояние.

Параметр id указывает идентификатор сообщения, а параметр memberFxn — имя метода для его обработки:

Методы, предназначенные для обработки данного класса сообщений, должны быть определены с ключевым словом afx_msg и иметь один параметр — указатель на объект класса CCmdUI . Для удобства имена методов, предназначенных для обновления пользовательского интерфейса, начинаются с OnUpdate:

В качестве параметра pCmdUI методу передается указатель на объект класса CCmdUI . В нем содержится информация об объекте пользовательского интерфейса, который нужно обновить, — строке меню или кнопке панели управления. Класс CCmdUI также включает методы, позволяющие изменить внешний вид представленного им объекта пользовательского интерфейса.

Сообщения, предназначенные для обновления пользовательского интерфейса, передаются, когда пользователь открывает меню приложения, а также во время цикла ожидания приложения, когда очередь сообщений приложения становится пуста.

При этом посылается несколько сообщений, по одному для каждой строке меню. С помощью макрокоманд ON_UPDATE_COMMAND_UI можно определить методы-обработчики, ответственные за обновление внешнего вида каждой строки меню и соответствующие ей кнопки на панели управления. Эти методы могут изменять состояние строки меню — отображать ее серым цветом, запрещать ее выбор, отображать около нее символ «галочка» и т.д.

Если не определить метод для обновления данной строки меню или кнопки панели управления, то выполняется обработка по умолчанию. Выполняется поиск обработчика соответствующего командного сообщения, и, если он не обнаружен, выбор строки запрещается.

Макрокоманда ON_UPDATE_COMMAND_UI_RANGE. Эта макрокоманда обеспечивает обработку сообщений, предназначенных для обновления пользовательского интерфейса, идентификаторы которых лежат в интервале от id1 до id2. Параметр memberFxn указывает метод, используемый для обработки:

Макрокоманда ON_ . Данные макрокоманды предназначены для обработки сообщений от органов управления. Такие сообщения могут передаваться органами управления диалоговой панели. Сообщения от органов управления не имеют обработчиков, используемых по умолчанию. При необходимости их нужно определить самостоятельно.

Все макрокоманды ON_ имеют два параметра. В первом параметре id указывается идентификатор органа управления. Сообщения от этого органа управления будут обрабатываться методом memberFxn. Например:

Макрокоманда ON_CONTROL_RANGE. Эта макрокоманда обрабатывает сообщения от органов управления, идентификаторы которых находятся в интервале от id1 до id2. Параметр wNotifyCode содержит код извещения. Метод-обработчик указывается параметром memberFxn:

Приложение, обрабатывающее сообщения

Предыдущие два рассматриваемых приложения, фактически никак не могли взаимодействовать с пользователем. Они не имели ни меню, ни панели управления. И, самое главное, они не содержали обработчиков сообщений.

Рассмотрим теперь приложение, которое имеет меню и содержит обработчики сообщений, передаваемых приложению, когда пользователь открывает меню и выбирает из него строки. Пусть меню приложения состоит из одного пункта Test. Можно выбрать одну из следующих команд — Beep или Exit.

Файл ресурсов, в который включается описание меню, можно построить либо непосредственным созданием нового файла ресурсов, либо при помощи средств AppWizard. В любом случае при создании меню нужно определить название меню или строки меню. Каждый элемент меню должен иметь уникальный идентификатор, однозначно его определяющий:

Файлы, в которых находятся определение классов приложения и главного окна, представлены ниже:

Чтобы объекты класса могли обрабатывать сообщения, в определении класса необходимо поместить макрокоманду DECLARE_MESSAGE_MAP . По принятым соглашениям эта макрокоманда должна записываться в секцию public .

Кроме этого, необходимо также определить таблицу сообщений. Таблица начинается макрокомандой BEGIN_MESSAGE_MAP и заканчивается макрокомандой END_MESSAGE_MAP . Между этими макрокомандами расположены строки таблицы сообщений, определяющие сообщения, подлежащие обработке данным классом, и методы, которые выполняют такую обработку.

Приложение может содержать несколько классов, обладающих собственными таблицами сообщений. Чтобы однозначно определить класс, к которому относится таблица сообщений, имя этого класса записывается в первый параметр макрокоманды BEGIN_MESSAGE_MAP .

Приложение menu обрабатывает только две команды от меню приложения. Для обработки этих команд используют методы, представленные в определении класса CMainFrame.

Приложению может поступать гораздо больше сообщений и команд, чем указано в таблице сообщений класса CMainFrame. Необработанные сообщения передаются для обработки базовому классу — классу CFrameWnd . Класс, который будет обрабатывать сообщения, не указанные в таблице сообщений, указывается во втором параметре макрокоманды BEGIN_MESSAGE_MAP .

Замечание. Если класс приложения тоже обрабатывает сообщения (т.е. имеет таблицу сообщений), и некоторые из сообщений обрабатываются как окном, так и приложением, то нужно понять, какова очередность обработки сообщений тем или иным объектом. Те команды, которые не имеют обработчика в таблице сообщений класса окна, передаются для обработки в класс приложения. Если же команда может быть обработана и в классе окна, и в классе приложения, она обрабатывается только один раз в классе окна. Обработчик класса приложения в этом случае не вызывается.

Илон Маск рекомендует:  Звук через внутренний динамик
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL