![]() |
Главная · Все классы · Основные классы · Классы по группам · Модули · Функции | ![]() |
В Qt события являются объектами, унаследованными от абстрактного класса QEvent, который представляет вещи, которые произошли или внутри приложения, или как результат внешней активности, о которой нужно знать приложению. События могут быть приняты и обработаны любым экземпляром подкласса QObject, но они особенно относятся к виджетам. Этот документ описывает, как события доставляются и обрабатываются в обычном приложении.
Когда происходит событие, чтобы представить его Qt создаёт объект события, создавая экземпляр соответствующего подкласса QEvent, и доставляет его отдельному экземпляру класса QObject (или одного из его подклассов) вызывая его функцию event().
Эта функция не обрабатывает событие сама; основываясь на тип доставленного события, она вызывает обработчик событий для этого определённого типа события, и отправляет ответ на основе того будет ли событие принято или проигнорировано.
Некоторые события, например, QMouseEvent и QKeyEvent, поступают из оконной системы; некоторые, например, QTimerEvent, поступают из других источников; некоторые поступают из самого приложения.
Большинство типов событий имеют специальные классы, а именно QResizeEvent, QPaintEvent, QMouseEvent, QKeyEvent и QCloseEvent. Каждый класс создан как подкласс QEvent и добавлены функции зависимы от события. Например, QResizeEvent добавляет size() и oldSize(), чтобы разрешить виджетам узнать как их изменились их размеры.
Некоторые классы поддерживают более одного реального типа событий. QMouseEvent поддерживает щелчок кнопкой мыши, двойные щелчки, перемещение и другие связанные операции.
Каждое событие имеет связанный с ним тип, определённого в QEvent::Type, и он может быть использован в качестве удобным источником информации о типах в процессе исполнения для быстрого определения, какой подкласс данного объекта события был создан.
Поскольку программам нужно реагировать разными и сложными способами, механизмы доставки событий Qt являются гибким. Документация для QCoreApplication::notify() кратко сообщает подробности; заметка из Qt Quarterly - "Another Look at Events" сжато переформулирует её. Изложенного здесь достаточно для примерно 95% приложений.
Обычный способ доставки события - вызов виртуальной функции. Например, QPaintEvent доставляется вызовом QWidget::paintEvent(). Эта виртуальная функция отвечает за соответствующее взаимодействие, обычно перерисовывая виджет. Если в своей реализации виртуальной функции вы не выполнили всю необходимую работу, вам может понадобиться вызывать реализацию из базового класса.
Например, следующий код обрабатывает щелчки левой кнопкой мыши на пользовательском виджете флажка наряду с тем, что все остальные щелчки кнопками передаются в базовый класс QCheckBox:
void MyCheckBox::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { // здесь обрабатываем левую кнопку мыши } else { // передаём кнопки базовому классу QCheckBox::mousePressEvent(event); } }
Если вы хотите заменить функцию базового класса, вы должны реализовать её самостоятельно. Тем не менее, если вы хотите только расширить функциональность базового класса, тогда реализуйте то что вы хотите и вызовите базовый класс чтобы получить поведение по умолчанию для любых случаев, которые вы не хотите обрабатывать.
Иногда такой зависимой от события функции нет или зависимая от события функция не адекватна. Наиболее распространённый пример касается нажатия клавиши Tab. Обычно, QWidget перехватывает это для перемещения фокуса ввода с клавиатуры, но нескольким виджетам самим нужна клавиша Tab.
Эти объекты могут повторно реализовать основной обработчик событий QObject::event() и либо проводить свою обработку событий до или после обычной обработки, или они могут заменить функцию полностью. Очень необычный виджет, который и перхватывает Tab и имеет специфичное событие приложения может содержать следующую функцию event():
bool MyWidget::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent *>(event); if (ke->key() == Qt::Key_Tab) { // здесь обрабатывается специальная табуляция return true; } } else if (event->type() == MyCustomEventType) { MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event); // здесь обрабатывается пользовательское событие return true; } return QWidget::event(event); }
Обратите внимание на то, что QWidget::event() по-прежнему вызывается для всех не обрабатываемых случаев, и что возвращаемое значение служит признаком обрабатывалось ли событие; значение true предупреждает от отправки события другим объектам.
Иногда объекту нужно ознакомиться - и, возможно, перехватить - события, которые доставлены другому объекту. Например, диалоги обычно хотят фильтровать нажатия клавиш для некоторых виджетов; например, для изменения обработки клавиши Return.
Функция QObject::installEventFilter() даёт такую возможность, установив фильтр события, заставляя предложенный объект фильтра получать события для объекта-приёмника в его функцию QObject::eventFilter(). Фильтр событий получает возможность обработать события до того, как это сделает объект-приёмник, позволяя обследовать и, по требованию, отбрасывать событие. Существующий фильтр событий можно удалить используя функцию QObject::removeEventFilter().
Когда вызывается реализация объект фильтра eventFilter(), она может принять или отвергнуть событие, и позволить или запретить дальнейшую обработку события. Если фильтры событий позволяют дальнейшую обработку события (каждый возвратил false), событие отправляется объекту-приёмнику. Если один из них остановил обработку (вернул true), приёмник и любые другие фильтры событий не получат возможность получить событие.
bool FilterObject::eventFilter(QObject *object, QEvent *event)
{
if (object == target && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
// Обработка специальной табуляции
return true;
} else
return false;
}
return false;
}
Вышеприведённый код показывает другой способ перехвата событий нажатия клавиши Tab, отправленных отдельному виджету-приёмнику. В этом случае, фильтр обрабатывает соответствующие события и возвращает true, чтобы остановить их дальнейшую обработку. Все остальные события игнорируются, а фильтр возвращает false чтобы позволить их отправку виджету-приёмнику, через какие-либо другие фильтры событий, которые на нём установлены.
Возможно также фильтровать все события для всего приложения, установив фильтр событий на объект QApplication или QCoreApplication. Такие глобальные фильтры событий вызываются перед фильтрами, связанными с объектами. Это очень действенно, но также замедляет доставку каждого отдельного события во всём приложении; остальные обсуждаемые приёмы обычно используются взамен.
Многие приложения хотят создать и отправить свои собственные события. Вы можете отправить события точно таким же способами как собственный цикл обработки событий Qt создаёт соответствующие объекты событий и отправляет их с QCoreApplication::sendEvent() и QCoreApplication::postEvent().
sendEvent() обрабатывает событие немедленно. Когда оно возвращается, фильтры событий и/или сам объект уже обработали событие. Для многих классов событий имеется функция с именем isAccepted(), которая сообщает вам принято было или отклонено событие последним обработчиком, который вызывался.
postEvent() отправляет событие в очередь для последующей координации. В следующий раз основной цикл обработки событий Qt работает, он координирует все отправленные события, с некоторой оптимизацией. Например, если имеется несколько событий изменения размера, они сжимаются в одно. То же самое относится к событиям рисования: QWidget::update() вызывает postEvent(), который устраняет мерцание и увеличивает скорость избегая многократного перерисовывания.
postEvent() также используется во время инициализации объекта, поскольку отправленное событие будет обычно отправляются очень скоро после завершения инициализации объекта. При реализации виджета, важно понимать, что события могут быть доставлены очень рано в их время существования, в его конструкторе, убедитесь для инициализации переменных-членах сразу, перед любым шансом, что могло получить событие.
Чтобы создать события пользовательского типа, вам нужно определить номер события, который должен быть больше, чем QEvent::User, и вам может понадобиться создать подкласс QEvent для того, чтобы передать определённую информацию о вашем пользовательском событии. Подробности смотрите в документации класса QEvent.
Copyright © 2008 Trolltech | Торговые марки | Qt 4.3.5 |