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

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

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

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

Файл resource.h #define IDR_MENU 101 #define ID_TEST_BEEP 40001 #define ID_TEST_EXIT 40002Файл resource.rc #include "resource.h" IDR_MENU MENU DISCARDABLE BEGIN POPUP "Test" BEGIN MENUITEM "Beep", ID_TEST_BEEP MENUITEM SEPARATOR MENUITEM "Exit", ID_TEST_EXIT END END

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

Файл menu.h #include <afxwin.h> class CMenuApp: public CWinApp { public: virtual BOOL InitInstance(); };Файл menu.cpp #include <afxwin.h> #include "menu.h" #include "menum.h" BOOL CMenuApp::InitInstance() { m_pMainWnd= new CMainWindow(); m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } CMenuApp theApp;Файл menum.h #include <afxwin.h> class CMainWindow : public CFrameWnd { public: CMainWindow(); afx_msg void TestBeep(); afx_msg void TestExit(); // макрокоманда необходима, так как класс обрабатывает сообщения DECLARE_MESSAGE_MAP() };Файл menum.cpp #include <afxwin.h> #include "menum.h" #include "resource.h" // Таблица сообщений класса BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd) ON_COMMAND(ID_TEST_BEEP,TestBeep) ON_COMMAND(ID_TEST_EXIT,TestExit) END_MESSAGE_MAP() CMainWindow::CMainWindow() { Create(NULL,"Hello",WS_OVERLAPPEDWINDOW,rectDefault, NULL,MAKEINTRESOURCE(IDR_MENU)); } void CMainWindow::TestBeep()// Метод TestBeep - обрабатывает команду меню { MessageBeep(0); } void CMainWindow::TestExit()// Метод TestExit - обрабатывает команду меню { DestroyWindow(); }

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

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

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

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

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

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