04 focusNextChild;
05 } else {
06 QLineEdit::keyPressEvent(event);
07 }
08 }
Этот подход имеет один основной недостаток: если мы используем в форме несколько различных видов виджетов (например, QComboBox и QSpinBox), мы должны также создать их подклассы для обеспечения единообразного поведения. Лучшее решение заключается в перехвате виджетом CustomerInfoDialog событий нажатия клавиш клавиатуры своих дочерних виджетов и в обеспечении необходимого поведения в его программном коде. Это можно сделать при помощи фильтров событий. Настройка фильтров событий сострит из двух этапов:
1. Зарегистрируйте объект—перехватчик с целевым объектом посредством вызова функции installEventFilter для целевого объекта.
2. Выполните обработку событий целевого объекта в функции eventFilter перехватчика.
Регистрацию объекта контроля удобно выполнять в конструкторе CustomerInfoDialog:
01 CustomerInfoDialog::CustomerInfoDialog(QWidget *parent)
02 : QDialog(parent)
03 {
04 firstNameEdit->installEventFilter(this);
05 lastNameEdit->installEventFilter(this);
06 cityEdit->installEventFilter(this);
07 phoneNumberEdit->installEvehtFilter(this);
08 }
После регистрации фильтра события те из них, которые посылаются виджетам firstNameEdit, lastNameEdit, cityEdit и phoneNumberEdit, сначала будут переданы функции eventFilter виджета CustomerInfoDialog и лишь затем дойдут по своему прямому назначению. (Если для одного объекта установлено несколько фильтров событий, они вызываются по очереди, начиная с установленного последним и последовательно возвращаясь к первому.)
Ниже приводится функция eventFilter, которая перехватывает события:
01 bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)
02 {
03 if (target == firstNameEdit || target == lastNameEdit
04 || target == cityEdit || target == phoneNumberEdit) {
05 if (event->type == QEvent::KeyPress) {
06 QKeyEvent *keyEvent = static_cast(event);
07 if (keyEvent->key == Qt::Key_Space) {
08 focusNextChild;
09 return true;
10 }
11 }
12 }
13 return QDialog::eventFilter(target, event);
14 }
Во-первых, мы проверяем, является ли целевой виджет строкой редактирования QLineEdit. Если событие вызвано нажатием клавиши клавиатуры, мы преобразуем его тип в QKeyEvent и проверяем, какая клавиша нажата. Если нажата клавиша пробела Space, мы вызываем функрию focusNextChild для перехода фокуса на следующий виджет в фокусной цепочке и возвращаем true для уведомления Qt о завершении нами обработки события. Если бы мы вернули false, Qt отослала бы событие по его прямому назначению,что привело бы к вставке лишнего пробела в строку редактирования QLineEdit.
Если целевым виджетом не является QLineEdit или если событие не вызвано нажатием клавиши Space, мы передаем управление функции базового класса eventFilter. Целевым виджетом мог бы быть также некоторый виджет, базовый класс которого QDialog осуществляет контроль. (В Qt 4.1 этого не происходит с QDialog. Однако другие классы виджетов в Qt, например QScrollArea, контролируют по различным причинам некоторые свои дочерние виджеты.)
Qt предусматривает пять уровней обработки и фильтрации событий:
1. Мы можем переопределять конкретный обработчик событий.
Переопределение таких обработчиков событий, как mousePressEvent, keyPressEvent и paintEvent, представляет собой очень распространенный способ обработки событий. Мы уже видели много примеров такой обработки.
2. Мы можем переопределять функцию QObject::event.