Источник: http://docs.wxwidgets.org/3.1/overview_events.html
Как и в прочих системах GUI, управление вычислительным потоком в приложениях wxWidgets основано на событиях. Сие означает, что программа обычно выполняет большинство своих действий в ответ на события, созданные пользователем.
Эти события могут запускаться как устройствами ввода (клавиатура, мышь, джойстик) напрямую, так и стандартным элементом управления, который превращает простые события от устройства ввода в события более высокого уровня: например, кнопка wxButton может генерировать событие click, когда пользователь нажимает на ней левой кнопкой мыши, а затем отпускает ее (не нажав ESC). Существуют также события, которые генерируются не действиями пользователя, например, wxTimerEvent(событие таймера) или wxSocketEvent (событие сокета сетевого интерфейса).
Во всех случаях wxWidgets представляет эти события единым способом и позволяет обрабатывать их с учетом условий их возникновения. И, хотя события обычно генерируются самими wxWidgets, вы также можете их сгенерировать самостоятельно, что особенно полезно при использовании настраиваемых событий (см. "Список пользовательских событий").
Во всех случаях wxWidgets представляет эти события единым способом и позволяет обрабатывать их с учетом условий их возникновения. И, хотя события обычно генерируются самими wxWidgets, вы также можете их сгенерировать самостоятельно, что особенно полезно при использовании настраиваемых событий (см. "Список пользовательских событий").
- Типом события: это просто значение типа wxEventType, который однозначно идентифицирует тип события. Например, если нажать на кнопку, выбрать элемент из списка или нажать клавишу на клавиатуре - во этих случаях генерируются события разного типа.
- Классом события: это информация, содержащаяся в самом событии. Эти данные представляются объектом класса, наследованного от wxEvent . События разных типов могут использовать один и тот же класс событий, например, события выбора кнопки и выбора списка используют класс wxCommandEvent (как и все другие простые события управления). А вот событие нажатия клавиши использует wxKeyEvent, поскольку связанная с этим событием информация отличается.
- Источником события: wxEvent хранит объект, который сгенерировал событие. Если источником является окно, то источником является идентификатор окна(см. Идентификаторы окон). Поскольку обычно существует более одного объекта, генерирующего события одного типа (например, окно часто содержит несколько кнопок, все генерируют одно и то же событие нажатия кнопки), информация об источнике события или идентификаторе окна позволяет различать их.
- Смотрите также
- wxEvtHandler , wxWindow , wxEvent
Обработка событий. Введение.
Существует два основных способа обработки событий в wxWidgets.
Один из них использует макросы таблицы событий и позволяет определять привязку между событиями и их обработчиками только статически, т. е., во время компиляции программы.
Другой использует вызов wxEvtHandler :: Bind <> () и может использоваться для связывания и "развязывания" обработчиков динамически, то есть во время выполнения в зависимости от некоторых условий. Он также позволяет прямое связывание событий с:
- Методом обработчика в другом объекте.
- Обычной функцией, такой как статический метод или глобальной функцией.
- Произвольным функтором, такой как boost :: function <> или (в C ++ 11) std :: function <> или с лямбда-выражением.
Статические таблицы событий могут обрабатывать события только в объекте, где они определены, поэтому использование Bind <> () более гибко, чем использование таблиц событий. С другой стороны, таблицы событий более компактны и централизуют все привязки обработчиков событий в одном месте. Можно выбрать один подход, или свободно сочетать оба метода в своей программе в разных классах или даже в одном и том же классе, хотя это, вероятно, сделает код более запутанным.
Кроме того, в большинстве существующих тестовых примерах, статьях, книгах и форумах wxWidgets используются таблицы событий, поскольку они исторически предшествовали появлению динамической обработки событий в wxWidgets. Но это абсолютно не означает, что использование таблиц событий является предпочтительным: обработка событий динамически лучше в нескольких аспектах. Если вы новичок в WxWidgets, возможно, следует использовать метод связывания. С другой стороны, о таблицах событий нужно знать хотя бы потому, что они используются во многих примерах.
Поэтому, прежде чем делать выбор между статическими таблицами и динамическим подключением обработчиков, следует рассмотреть оба эти два способа более подробно.
Обработка событий с использованием таблицы событий.
Чтобы использовать таблицу событий, прежде всего следует решить, в каком классе мы хотим обрабатывать события. Единственное требование, предъявляемое wxWidgets, состоит в том, чтобы этот класс должен быть наследником класса wxEvtHandler, и поэтому, учитывая, что wxWindow тоже является его наследником, обрабатывать события можно в любом классе, представляющем окна. Простые события, такие как команды меню, обычно обрабатываются на уровне окна верхнего уровня, содержащего меню, поэтому давайте предположим, что нужно обрабатывать некоторые события в MyFrame, наследованном от wxFrame .
Сначала объявляем один или несколько обработчиков событий . Это просто простые методы класса, которые принимают в качестве параметра ссылку на объект класса wxEvent и имеют тип void, т.е. не возвращаемого значения (любая возвращаемая информация передается через аргумент, поэтому он не является константой).
Далее нужно вставить макрос
- где-то в объявлении класса. Несущественно, в каком месте, но принято ставить его в конце, потому что макрос внутри себя меняет тип доступа к членам класса, поэтому он будет безопасен, если за ним ничего не следует. Полное объявление класса может выглядеть так:
{
public:
MyFrame(...) : wxFrame(...) { }
...
protected:
int m_whatever;
private:
// Замечание: так как обработчики обычно не вызываются извне класса,
// их помещают в private секцию класса.
void OnButton1(wxCommandEvent& event);
void OnSize(wxSizeEvent& event);
// Обычно обработчики называют OnЧтоНибудьПроизошло(), но это не обязательно.
// Например, DoTest() - тоже обработчик:
void DoTest(wxCommandEvent& event);
};
Затем следует определить таблицу событий и, как и любое определение, она должна быть помещена в файл реализации. Таблица событий сообщает wxWidgets, как сопоставлять события с функциями-членами, и конкретно в нашем примере она может выглядеть так:
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
EVT_MENU(DO_TEST, MyFrame::DoTest)
EVT_SIZE(MyFrame::OnSize)
EVT_BUTTON(BUTTON1, MyFrame::OnButton1)
Таким образом, каждому событию ставится в соответствие метод-обработчик.
Рассмотри таблицу событий более детально.
Первая строка означает, что мы определяем таблицу событий для класса MyFrame и что ее базовый класс - wxFrame , поэтому события, которые не обрабатываются в MyFrame, по умолчанию будут обрабатываться в wxFrame . Следующие четыре строки привязывают отдельные события к их обработчикам. Первые два из них (макрос EVT_MENU) вызываются при выборе пунктов меню с идентификаторами, указанными в качестве первого параметра макроса.
Далее, макрос
EVT_SIZE
означает, что любые изменения в размере окна приведут к вызову метода OnSize(). Обратите внимание, что для этого макроса не нужен идентификатор окна, так как обычно нас интересуют только события именно текущего окна.
Макрос EVT_BUTTON демонстрирует случай, когда источником события является не оконный класс, в котором реализуется таблица событий: если источником события является кнопка на панели, размещенной в окне, это все равно будет работать, так как для командных событий (наследников класса wxCommandEvent) таблицы событий ищутся вверх по иерархии окна (но только для командных событий, поэтому, например, нет возможности перехватывать события перемещения мыши в дочернем элементе управления в родительском окне таким же образом, потому что wxMouseEvent не наследуется от wxCommandEvent - см. ниже, это все же можно сделать). В данном случае, будет выполнен поиск таблицы событий для кнопки, затем для родительской панели, затем для окна.
Наконец, нужно реализовать сами обработчики событий. Как упоминалось ранее, все обработчики событий принимают аргумент wxEvent, конкретный класс которого зависит от типа события и класса исходного окна. Для событий изменения размера используется wxSizeEvent . Для команд меню и большинства команд управления (например, нажатия кнопок) используется класс wxCommandEvent . Когда элементы управления становятся более сложными, могут использоваться более конкретные классы событий, унаследованные от wxCommandEvent, которые предоставляют дополнительную информацию, специфичную для контрола, например wxTreeEvent для событий окон класса wxTreeCtrl .
В самом простом случае обработчик события может вообще не использовать параметр event. Например:
void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event))
{
// Когда пользователь выбрал пункт меню "Exit", нужно закрыть приложение
Close(true);
}
В других случаях может потребоваться дополнительная информация из аргумента
event
argument, как здесь:
void MyFrame::OnSize(wxSizeEvent& event)
{
wxSize size = event.GetSize();
... привести окно к новому размеру size ...
}
Подробную информацию о макросах таблицы событий и соответствующих им наследникам класса wxEven можно найти в описаниях соответствующих элементов управления в разделе "генерируемые события".
Продолжение - здесь: Динамическая обработка событий
Комментариев нет:
Отправить комментарий