Главная :: Программы для программирования :: wxWidgets :: Перевод книги "Programming with wxWidgets" :: Глава III – Обработка сообщений. Часть 5
Plug&Pray

Глава III – Обработка сообщений. Часть 5

Определение собственных сообщений

Если вы хотите хотите определить свои собственный класс сообщения и макрос для него, то вам необходимо выполнить следующие действия:

Наследуйте ваш класс от подходящего класса, объявив информацию о динамическом типе и включив функцию Clone. Вы можете, если хотите, добавить в этот класс дополнительные поля и функции для доступа к ним. Наследование вашего класса от wxCommandEvent позволит ему перемещаться вверх по иерархии окон, а наследование от wxNotifyEvent дополнительно к этому позволит пользоваться функцией Veto.

Определите typedef для функции-обработчика вашего события.

Определите таблицу типов сообщения, которые поддерживает ваш класс. Эта таблица объявляется в заголовочном файле конструкцией BEGIN_DECLARE_EVENT_TYPES()~\ldots~END_DECLARE_EVENT_TYPES(). Каждый тип объявляется с помощью DECLARE_EVENT_TABLE(имя, целое_число). Далее в файле с реализацией напишите DEFINE_EVENT_TYPE(имя).

Определите макрос для таблицы сообщений для каждого типа сообщения.

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

Мы объявим новый класс сообщения wxFontSelectorCtrlEvent. Приложение должно быть в состоянии манипулировать этим сообщением и направлять его правильному обработчику с помощью нашего макроса EVT_FONT_SELECTION_CHANGED(id, func), который использует единственный тип сообщения wxEVT_COMMAND_FONT_SELECTION_CHANGED. Вот почему нам необходим заголовочный файл с описанием всего необходимого для создаваемого сообщения, в дополнение к объявлению собственно самого элемента управления (здесь код последнего не приводится):

/*! * Класс сообщения о выборе шрифта */ class wxFontSelectorCtrlEvent : public wxNotifyEvent { public: wxFontSelectorCtrlEvent(wxEventType commandType = wxEVT_NULL, int id = 0): wxNotifyEvent(commandType, id) {} wxFontSelectorCtrlEvent(const wxFontSelectorCtrlEvent& event): wxNotifyEvent(event) {} virtual wxEvent *Clone() const { return new wxFontSelectorCtrlEvent(*this); } DECLARE_DYNAMIC_CLASS(wxFontSelectorCtrlEvent); }; typedef void (wxEvtHandler::*wxFontSelectorCtrlEventFunction) (wxFontSelectorCtrlEvent&); /*! * Сообщение о выборе шрифта и макрос для его обработки */ BEGIN_DECLARE_EVENT_TYPES() DECLARE_EVENT_TYPE(wxEVT_COMMAND_FONT_SELECTION_CHANGED, 801) END_DECLARE_EVENT_TYPES() #define EVT_FONT_SELECTION_CHANGED(id, fn) DECLARE_EVENT_TABLE_ENTRY( \ wxEVT_COMMAND_FONT_SELECTION_CHANGED, id, -1, \ (wxObjectEventFunction) (wxEventFunction) \ (wxFontSelectorCtrlEventFunction) & fn, (wxObject *) NULL ),

В нашем файле с реализацией мы пишем

DEFINE_EVENT_TYPE(wxEVT_COMMAND_FONT_SELECTION_CHANGED) IMPLEMENT_DYNAMIC_CLASS(wxFontSelectorCtrlEvent, wxNotifyEvent)

Чтобы послать созданное сообщение диалог выбора шрифта может вызвать метод ProcessEvent, когда будет зафиксировано соответствующее изменение внутри обработчика сообщения от мыши:

wxFontSelectorCtrlEvent event( wxEVT_COMMAND_FONT_SELECTION_CHANGED, GetId()); event.SetEventObject(this); GetEventHandler()->ProcessEvent(event);

Теперь приложение может обрабатывать наше сообщение о выборе шрифта:

BEGIN_EVENT_TABLE(MyDialog, wxDialog) EVT_FONT_SELECTION_CHANGED(ID_FONTSEL, MyDialog::OnChangeFont) END_EVENT_TABLE() void MyDialog::OnChangeFont(wxFontSelectorCtrlEvent& event) { // Подходящее действие, когда меняется шрифт ... }

Значение идентификатора сообщения ($801$) не используется в последних версиях библиотеки wxWidgets и оставлено исключительно для совместимости с wxWidgets версии 2.4.

Давайте посмотрим на код макроса для обработчика сообщения:

#define EVT_FONT_SELECTION_CHANGED(id, fn) DECLARE_EVENT_TABLE_ENTRY( \ wxEVT_COMMAND_FONT_SELECTION_CHANGED, id, -1, \ (wxObjectEventFunction) (wxEventFunction) \ (wxFontSelectorCtrlEventFunction) & fn, (wxObject *) NULL ),

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

Полный текст примера определения собственного сообщения расположена в папке examples/chap03 и включает в себя реализацию собственного диалога выбора шрифта и удобный класс-валидатор, который вы можете использовать в своих программах. Еще одним источником для вдохновения может стать файл include/wx/event.h из вашего дистрибутива wxWidgets.

Итоги

В этой главе мы обсудили каким образом сообщения передаются через дерево наследования и иерархию окон, рассмотрели подключаемые и динамические обработчики сообщений, поговорили о идентификаторах окон и описали последовательность объявления собственных классов и макросов для сообщений. Если вы хотите получить более подробное описание механики работы приложений обратитесь к Приложению 8 Как wxWidgets обрабатывает сообщения. В Приложении 9 Классы и макросы для сообщений приведены наиболее часто используемые классы и макросы для них. Вы также можете найти несколько полезных примеров в дистрибутиве wxWidgets, по большей части в папке samples/event. В следующей главе мы рассмотрим важнейшие GUI-компоненты, которые можно использовать в своих приложениях.