События уведомляют объекты о себе при помощи своих функций event, унаследованных от класса QObject. Реализация event в QWidget передает большинство обычных событий конкретным обработчикам событий, например mousePressEvent, keyPressEvent и paintEvent.
Мы уже ознакомились в предыдущих главах со многими обработчиками событий при реализации MainWindow, IconEditor и Plotter. Существует много других типов событий, приводимых в справочной документации по QEvent, и можно также самому создавать и генерировать события. В данной главе мы рассмотрим два распространенных типа событий, заслуживающих более детального обсуждения, а именно события клавиатуры и события таймера.
События клавиатуры обрабатываются путем переопределения функций keyPressEvent и keyReleaseEvent. Виджет Plotter переопределяет keyPressEvent. Обычно нам требуется переопределить только keyPressEvent, поскольку отпускание клавиш важно только для клавиш—модификаторов, то есть для клавиш Ctrl, Shift и Alt, а их можно проконтролировать в keyPressEvent при помощи функции QKeyEvent::modifiers. Например, если бы нам пришлось реализовывать виджет CodeEditor (редактор программного кода), общий вид его функции keyPressEvent с различной обработкой клавиш Home и Ctrl+Home был бы следующим:
01 void CodeEditor::keyPressEvent(QKeyEvent *event)
02 {
03 switch (event->key) {
04 case Qt::Key_Home:
05 if (event->modifiers & Qt::ControlModifier) {
06 goToBeginningOfDocument;
07 } else {
08 goToBeginningOfLine;
09 }
10 break;
11 case Qt::Key_End:
12 …
13 default:
14 QWidget::keyPressEvent(event);
15 }
16 }
Клавиши Tab и Backtab (Shift+Tab) представляют собой особый случай. Они обрабатываются функцией QWidget::event до вызова keyPressEvent c установкой фокуса на следующий или предыдущий виджет в фокусной цепочке. Обычно нам нужен именно такой режим работы, но в виджете CodeEditor мы, возможно, предпочтем использовать клавишу табуляции Tab для обеспечения отступа в начале строки. Переопределение функции event выглядело бы следующим образом:
01 bool CodeEditor::event(QEvent *event)
02 {
03 if (event->type == QEvent::KeyFress) {
04 QKeyEvent *keyEvent = static_castevent;
05 if (keyEvent->key == Qt::Key_Tab) {
06 insertAtCurrentPosition('\t');
07 return true;
08 }
09 }
10 return QWidget::event(event);
11 }
Если событие сгенерировано нажатием клавиши клавиатуры, мы преобразуем объект типа QEvent в QKeyEvent и проверяем, какая клавиша была нажата. Если это клавиша Tab, мы выполняем некоторую обработку и возвращаем true, чтобы уведомить Qt об обработке нами события. Если бы мы вернули false, Qt передала бы cобытие родительскому виджету.
Высокоуровневый метод обработки клавиш клавиатуры заключается в применении класса QAction. Например, если goToBeginningOfLine и goToBeginningOfDocument являются открытыми слотами виджета CodeEditor и CodeEditor применяется в качестве центрального виджета класса MainWindow, мы могли бы обеспечить обработку клавиш при помощи следующего программного кода:
01 MainWindow::MainWindow
02 {
03 editor = new CodeEditor;
04 setCentralWidget(editor);
05 goToBeginningOfLineAction =
06 new QAction(tr("Go to Beginning of Line"), this);
07 goToBeginningOfLineAction->setShortcut(tr("Home"));
08 connect(goToBeginningOfLineAction, SIGNAL(activated),
09 editor, SLOT(goToBeginningOfLine));
10 goToBeginningOfDocumentAction =