Долгий путь сообщения
Долгий путь сообщения
В предыдущем примере мы изучили основы метода обработки сообщений, рассмотрели принципы построения таблицы сообщений класса. Теперь мы приступим к более детальному рассмотрению механизма обработки сообщений для приложений MFC.
Создайте новый проект под названием MFMessage. В качестве типа приложения выберите из списка Type строку Application (рис. 4.1). Наберите в редакторе исходный текст приложения и сохраните его в файле MFMessage.cpp (листинг 2.10). Чтобы быстрее набрать текст приложения, вы можете модифицировать исходный текст приложения MFMenu.
Листинг 2.10. Файл MFMessage.cpp
// Включаемый файл для MFC
#include <afxwin.h>
#include "resource.h"
//=====================================================
// Класс CMFMessageApp – главный класс приложения
//=====================================================
class CMFMessageApp : public CWinApp {
public:
// Мы будем переопределять метод InitInstance,
// предназначенный для инициализации приложения
virtual BOOL InitInstance();
afx_msg void AppMessageCommand();
// Макрокоманда необходима, так как класс
// CMFMessageWindow обрабатывает сообщения
DECLARE_MESSAGE_MAP()
};
// Создаем объект приложение класса CMFMessageApp
CMFMessageApp MFMessageApp;
//=====================================================
// Класс CMFMessageWindow – представляет главное окно
//=====================================================
class CMFMessageWindow : public CFrameWnd {
public:
// Объявляем конструктор класса CMFMessageWindow
CMFMessageWindow();
// Объявляем методы для обработки команд меню
afx_msg void FrameMessageCommand();
afx_msg void ExitApp();
// Макрокоманда необходима, так как класс
// CMFMessageWindow обрабатывает сообщения
DECLARE_MESSAGE_MAP()
};
//=====================================================
// Метод MessageCommand
// Обрабатывает команду ID_TEST_BEEP
//=====================================================
void CMFMessageWindow::FrameMessageCommand() {
::MessageBox(NULL, "Command received in CMFMessageWindow Message Map", "Message", MB_OK);
}
//=====================================================
// Метод MessageCommand
// Обрабатывает команду ID_TEST_BEEP
//=====================================================
void CMFMessageApp::AppMessageCommand() {
::MessageBox(NULL, "Command received in CMFMessageApp Message Map", "Message", MB_OK);
}
//=====================================================
// Таблица сообщений класса CMFMessageWindow
//=====================================================
BEGIN_MESSAGE_MAP(CMFMessageWindow, CFrameWnd)
ON_COMMAND(ID_TEST_INFRAMECLASS, FrameMessageCommand)
ON_COMMAND(ID_TEST_INBOTHCLASS, FrameMessageCommand)
END_MESSAGE_MAP()
//=====================================================
// Таблица сообщений класса CMFMessageApp
//=====================================================
BEGIN_MESSAGE_MAP(CMFMessageApp, CWinApp)
ON_COMMAND(ID_TEST_INAPPCLASS, AppMessageCommand)
ON_COMMAND(ID_TEST_INBOTHCLASS, AppMessageCommand)
END_MESSAGE_MAP()
//=====================================================
// Метод InitInstance класса CMFMessageApp
//=====================================================
BOOL CMFMessageApp::InitInstance() {
// Создаем объект класса CMFMessageWindow
m_pMainWnd = new CMFMessageWindow();
// Отображаем окно на экране
m_pMainWnd–>ShowWindow(m_nCmdShow);
// Обновляем содержимое окна
m_pMainWnd–>UpdateWindow();
return TRUE;
}
//=====================================================
// Конструктор класса CMFMessageWindow
//=====================================================
CMFMessageWindow::CMFMessageWindow() {
// Создаем окно приложения, соответствующее
// данному объекту класса CMFMessageWindow
Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU));
}
Используя редактор ресурсов, создайте файл ресурсов и включите в него меню Test, содержащее четыре строки, имеющие идентификаторы, описанные в следующей таблице. Присвойте меню идентификатор IDR_MENU. Затем включите файл ресурсов в проект.
Строка меню Test Идентификатор In Frame Class ID_TEST_INFRAMECLASS In App Class ID_TEST_INAPPCLASS In Both Class ID_TEST_INBOTHCLASS Exit ID_APP_EXITВ листинге 2.11 представлен фрагмент файла ресурсов MFMessage.rc, в котором определяется меню приложения. Чтобы ускорить разработку меню, вы можете скопировать меню приложения MFMenu и изменить его соответствующим образом.
Листинг 2.11. Фрагмент файла MFMessage.rc
//////////////////////////////////////////////////////////////
// Меню
//
IDR_MENU MENU DISCARDABLE
BEGIN
POPUP "Test"
BEGIN
MENUITEM "In Frame Class", ID_TEST_INFRAMECLASS
MENUITEM "In App Class", ID_TEST_INAPPCLASS
MENUITEM "In Both Class", ID_TEST_INBOTHCLASS
MENUITEM "Exit", ID_APP_EXIT
END
END
Идентификаторы, необходимые для файла ресурсов, записываются в файл resource.h, показанный в листинге 2.12. Этот файл создается автоматически редактором ресурсов. Все что вы должны сделать – это включить его в исходный текст приложения – файл MFMessage.cpp.
Листинг 2.12. Файл resource.h
//{{NO_DEPENDENCIES}}
// Включаемый файл, созданный Microsoft Developer Studio
// Используется в файле ресурсов MFMessage.rc
//
#define IDR_MENU 101
#define ID_TEST_BEEP 40001
#define ID_TEST_EXIT 40002
#define ID_TEST_INAPPCLASS 40003
#define ID_TEST_INFRAMECLASS 40004
#define ID_TEST_INBOTHCLASS 40006
// Следующие значения идентификаторов используются по
// умолчанию для новых объектов
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40007
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Укажите в проекте MFMessage, что приложение использует библиотеку классов MFC и постройте проект. Запустите полученный выполнимый файл. На экране появится главное окно приложение, имеющее меню Test (рис. 2.26).
![](https://storage.yandexcloud.net/wr4img/187210_73_image085.png)
Рис. 2.26. Приложение MFMessage
Когда вы выбираете строки из меню Test, приложению передаются команды с соответствующими идентификаторами. Обратите внимание, что команда ID_TEST_INFRAMECLASS обрабатывается в классе окна CMFMessageWindow, команда ID_TEST_INAPPCLASS в главном классе приложения CMFMessageApp. Команда ID_TEST_INBOTHCLASS содержит два обработчика – один в классе окна, другой в классе приложения, зато команда ID_APP_EXIT не имеет обработчика совсем.
Попробуйте последовательно выбирать все строки из меню Test. При выборе первых трех строк на экране появляется сообщение, содержащее название класса в котором обработано сообщение. Если выбрать из меню Test строку Exit приложение завершится не смотря на то, что команда ID_APP_EXIT, соответствующая этой строке меню вообще не имеет обработчика в исходном тексте нашего приложения.
Поэкспериментируйте с приложением MFMessage. Очень скоро вы обнаружите, что команды обрабатываются не только классом окна, как это было в приложении MFMenu, но также и главным классом приложения. Те команды которые не имеют обработчика в таблице сообщений класса окна, передаются для обработке в класс приложения.
Если же команда может быть обработана и в классе окна и в классе приложения, она обрабатывается только один раз в классе окна. Обработчик класса приложения в этом случае не вызывается.
Широкие возможности для управления обработкой сообщений предоставляет ClassWizard. Мы расскажем более подробно об обработке сообщений и средствах ClassWizard в следующей главе.