Вернуться наверх
aco.ifmo.ru photonic
вернуться в оглавление предыдущая глава предыдущий параграф следующий параграф следующая глава


2.3. Сообщения и уведомления. ClassWizard.

Основная задача разработчика программ для Windows - связь сообщений с обрабатывающими их функциями . В приложении, не использующем MFC , для этого нужна оконная процедура для каждого зарегистрированного оконного класса. Такая процедура обычно реализуется с помощью оператора switch , получающего идентификатор сообщения. В MFC -приложении сообщения обрабатывают функции-члены классов приложения, созданныx как Вами, так и мастером AppWizard . Чтобы связать сообщение с обработчиком, достаточно карты сообщений .

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

Таблица 1. Типы сообщений в MFC Тип сообщения Описание
Сообщения Windows Эти сообщения посылаются операционной системой. Они информируют приложение о создании окна, о его предстоящем уничтожении, о событиях клавиатуры и мыши, об изменениях системных цветов и обо всем остальном, что способно повлиять на выполнение программы. Идентификаторы этих сообщений обычно начинаются с префикса WM_ . Сообщения Windows как правило обрабатываются окном, которому они посланы. Им может быть и главное окно приложения, и диалоговое окно
Командные сообщения Командные сообщения генерируются в ответ на действия пользователя, например на выбор пункта меню, щелчок кнопки панели инструментов или нажатие "быстрой" клавиши. Когда происходит одно из таких событий, приложению отправляется сообщение WM_COM MAND с параметром, зависящим от команды. Данные сообщения передаются каркасом объекту приложения. Такая маршрутизация команд позволяет приложению обработать сообщение в наиболее подходящем для этого классе
Командные сообщения обновления пользовательского интерфейса Данные сообщения генерируются каркасом приложения, таким образом, они присущи только MFC . Они сигнализируют приложению об изменении состояния элементов интерфейса, таких, как пункты меню и кнопки панелей инструментов. Например, перед отображением меню приложению отправляется соответствующее сообщение, что дает ему возможность изменить состояние этого меню - сделать его доступным, недоступным или помеченным
Уведомления от элементов управления Такие сообщения посылают родительскому окну элементы управления и другие дочерние окна. Они обычно представляют собой сообщения WM_COMMAND с параметрами уведомления. Например, поле ввода генерирует для своего родительского окна сообщение WM_COMMAND , содержащее код уведомления EN_CHANGE , когда пользователь предпринимает действия, которые могут изменить текст в этом поле

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

Создание обработчиков сообщений средствами мастера ClassWizard

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

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

  • Добавление обработчика сообщения Windows.
    1. Вернитесь в проект МуАрр .
    2. Откройте ClassWizard , нажав CTRL+W . Перейдите на вкладку Message Maps .
    3. В списке Class Name выберите элемент CMyAppView . Это показывает, что Вы хотите обработать сообщение, посланное классу представления, который инкапсулирует клиентскую область главного окна.
    4. В списке Object IDs щелкните пункт CMyAppView .
    5. В списке Messages выберите элемент WM_LBUTTONDOWN . Это сообщение будет отправлено приложению, когда Вы щелкнете левой кнопкой мыши в клиентской области окна.

    6. Щелкните кнопку Add Function . Мастер ClassWizard создаст функцию-заглушку, в которую Вы можете добавить свой код. Все сообщения Windows обрабатываются перегруженными виртуальными функциями базового класса CWnd . Их названия начинаются с " On ", после чего следует название сообщения, у которого обрезан префикс WM_ , а заглавными являются только первые буквы слов. В данном случае функция называется OnLButtonDown() .
    7. Щелкните кнопку Edit Code . Откроется файл MyAppView.cpp , a курсор будет помещен в начало функции OnLButtonDown() .

    8. Замените комментарий, начинающийся с //TODO , таким кодом:
      	AfxMessageBox("Щелчок левой кнопкой мыши");
      Теперь эта функция выглядит следующим образом:
      	void CMyAppView::OnLButtonDown(UINT nFlags, CPoint point) 
      	{
      		AfxMessageBox("Щелчок левой кнопкой мыши");
      		CScrollView::OnLButtonDown(nFlags, point);
      	}
    9. Нажмите клавишу F7 , чтобы собрать проект МуАрр , после чего запустите приложение клавишей F5 . Проверьте работу программы, щелкнув левой кнопкой мыши в клиентской области. Закройте приложение МуАрр .
    Теперь добавьте обработчик командного сообщения, посылаемого при выборе пункта Paste в меню Edit .
  • Добавление обработчика командного сообщения .
    1. Открыв проект МуАрр , нажмите клавиши CTRL+W , тем самым Вы вызовите мастер ClassWizard . Перейдите на вкладку Message Maps .
    2. В списке Class Name щелкните СМуАррАрр . Не забывайте, что командные сообщения могут обрабатываться любым классом приложения. Так как Ваша функция очень маленькая, Вы сделаете ее членом такого класса. Сообщения должны обрабатываться классом, который наиболее тесно с ними связан. Например, лучшее место для размещения обработчиков команд, которые изменяют атрибуты главного окна (отображают и скрывают панель инструментов), - класс CMainFrame .
    3. В списке Object IDs щелкните элемент ID_EDIT_PASTE . Это идентификатор команды, передаваемый в качестве параметра сообщения WM_COMMAND , которое генерируется при выборе пункта Paste в меню Edit .
    4. В списке Messages выберите COMMAND . Таким образом Вы указываете, что собираетесь обрабатывать командное сообщение , а не сообщение об обновлении пользовательского интерфейса .
    5. Щелкните кнопку Add Function . Появится диалоговое окно, предлагающее в качестве названия обработчика OnEditPaste() . Это является результатом того, что Вы определяете новую функцию, а не перегружаете уже существующую виртуальную функцию базового класса. Согласитесь с данным названием, щелкнув кнопку ОК .

    6. Щелкните кнопку Edit Code . Откроется файл MyAppView.cpp , курсор будет помещен в начало функции OnEditPaste() .
    7. Замените комментарий, начинающийся с //TODO , таким кодом:
      	AfxMessageBox("Выбрана команда Paste из меню Edit");
      Теперь эта функция выглядит следующим образом:
      	void CMyAppApp::OnEditPaste()
      	{
      		AfxMessageBox("Выбрана команда Paste из меню Edit");
      	}
    8. Соберите и запустите приложение МуАрр . Чтобы проверить его работу, выберите в меню Edit пункт Paste . Обратите внимание: пункты меню, обработчики которых не определены, недоступны.

Код карты сообщений

    При добавлении функции-обработчика мастер ClassWizard выполняет следующие действия:

  • объявляет функцию в заголовочном файле класса;
  • создает функцию-заглушку в файле реализации класса;
  • добавляет соответствующую запись в карту сообщений.

    Посмотрим, что представляют собой тексты объявления функции CMyAppApp::OnEditPaste() и ее карты сообщений.

  • Просмотр объявления функции CMyAppApp::OnEditPaste() .
    1. Перейдите к объявлению класса СМуАррАрр , находящемуся в файле МуАррApp.h , дважды щелкнув название этого класса в окне ClassView .
    2. Найдите следующий код в самом конце файла:
      	//{{AFX_MSG(CMyAppApp) 
      	afx_msg void OnAppAbout(); 
      	afx_msg void OnEditPaste(); 
      	//}}AFX_MSG
      	DECLARE_MESSAGE_MAP()

        Обратите внимание на макрос DECLARE_MESSAGE_MAP . Он представляет собой основную часть карты сообщений и добавлен к коду мастером AppWizard или ClassWizard . Изучим записи карты сообщений.

  • Просмотр записи карты сообщений для функции СМуАррАрр::ОnEditPaste() .
    1. Вернитесь к файлу СМуАрр.срр . Если он закрыт, откройте его, дважды щелкнув значок функции OnEditPaste() в окне ClassView (находится под значком класса СМуАррАрр ).
    2. Практически в самом верху файла СМуАрр.срр находится карта сообщений:
      	BEGIN_MESSAGE_MAP(CMyAppApp, CWinApp)
      		//{{AFX_MSG_MAP(CMyAppApp)
      		ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
      		ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
      		//}}AFX_MSG_MAP
      		// Стандартные команды для работы с файлами документов
      		ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
      		ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) 
      		// Стандартная команда настройки принтера
      		ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) 
      	END_MESSAGE_MAP() 

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

Объявление функции OnLButtonDown() , обрабатывающей сообщение WM_ LBUTTONDOWN , выглядит следующим образом (оно находится в файле MyAppView.h ):

	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

Соответствующая ей запись в карте сообщений в файле AppView.cpp такова:

	ON_WM_LBUTTONDOWN()

Так как сообщения Windows обрабатываются перегруженными виртуальными функциями базового класса CWnd , нет необходимости передавать название обработчика в качестве параметра. Каркас MFC -приложения автоматически связывает такие сообщения с соответствующей виртуальной функцией. Как правило, сообщения Windows имеют дополнительную информацию, передаваемую в виде параметров. Все эти данные передаются в обработчик каркасом приложения. Внимательно посмотрите на объявление функции CMyApp::OnLButtonDown . Наверняка Вы заметили, что она принимает два параметра (производные от параметров сообщения WM_LBUTTONDOWN ), один из которых содержит координаты текущего положения указателя мыши, а другой - флаг, который "отвечает" за нажатие "виртуальных" клавиш (например CTRL или SHIFT ).