На этом шаге рассмотрим возможность искусственного создания событий из самой программы.
Иногда возникает необходимость в событиях, созданных искусственно. Например, это полезно при отладке вашей программы, для того чтобы имитировать действия пользователя.
Для генерации события можно воспользоваться одним из двух статических методов класса QCoreApplication — sendEvent() или postEvent(). Оба метода получают в качестве параметров указатель на объект, которому посылается событие, и адрес объекта события. Разница между ними состоит в том, что метод sendEvent() отправляет событие без задержек, т. е. его вызов приводит к немедленному вызову метода события, в то время как метод postEvent() помещает его в очередь для дальнейшей обработки.
Рассмотрим это на примере приложения, имитирующего нажатие пользователем клавиш от <0> до <9> (рис. 1).

Рис.1. Программа, демонстрирующая подмену события клавиатуры
Приведем содержимое файла приложения, имитирующего события клавиатуры.
QApplication app (argc, argv);
app.setApplicationDisplayName("Имитация");
//Создается объект txt класса QLineEdit,
//который будет выступать в качестве поля ввода
QLineEdit txt("Пользователь ввел: ");
txt.show();
txt.resize(280, 20);
int i;
for (i = 0; i < Qt::Key_9 - Qt::Key_0 + 1; ++i) {
QChar ch = 48 + i;
int nKey = Qt::Key_0 + i;
//В цикле происходит создание событий типа QKeyEvent.
//Первый параметр, передаваемый конструктору, задает тип события клавиатуры
//(здесь он соответствует событию нажатия клавиши клавиатуры QEvent::KeyPress).
//Второй параметр задает саму нажатую клавишу.
//Третий — указывает на клавиши-модификаторы, которые могли быть совместно
//нажаты, в нашем случае это значение равно Qt::NoModifier и означает,
//что никаких клавиш-модификаторов нажато не было.
//Четвертый параметр указывает на представление клавиши в ASCII-коде
//(в примере это число начинается с 48, что соответствует цифре "0",
//и циклически увеличивается на единицу)
QKeyEvent* pePress =
new QKeyEvent(QEvent::KeyPress, nKey, Qt::NoModifier, ch);
QApplication::sendEvent(&txt, pePress);
//Если хотим имитировать клавиатуру, то после каждого события KeyPress
//должно следовать событие KeyRelease (событие отпускания клавиши клавиатуры)
//в противном случае много виджетов, которым будет послано только одно событие
//нажатия, будут вести себя неправильно, например в QLineEdit
//перестает мигать курсор ввода
QKeyEvent* peRelease =
new QKeyEvent(QEvent::KeyRelease, nKey, Qt::NoModifier, ch);
QApplication::sendEvent(&txt, peRelease);
}Файлы приложения можно взять здесь.
Если бы нам понадобилось симулировать нажатие мыши на какой-либо виджет, то реализация функций для этого могла бы выглядеть следующим образом:
//Первым параметром принимаем указатель на виджет, с которым мы хотим //провести симуляцию нажатия, вторым и третьим идут координаты позиции, //в которой было выполнено нажатие. //Четвертый и пятый параметры не обязательные и по умолчанию инициализируются //нажатием на левую кнопку, что является самым частым действием при нажатии void mousePress(QWidget* pwgt, int x, int y, Qt::MouseButton bt = Qt::LeftButton, Qt::MouseButtons bts = Qt::LeftButton ) { //Внутри функции проверяем действительность указателя на объект виджета, //после чего создаем объект события QmouseEvent, инициализируем переданными //в функцию параметрами if (pwgt) { QMouseEvent* pePress = new QMouseEvent(QEvent::MouseButtonPress, QPoint(x, y), bt, bts, Qt::NoModifier ); //пересылаем событие виджету (указатель pwgt) вызовом метода postEvent() QApplication::postEvent(pwgt, pePress); } }
Модифицировать объекты событий возможно не всегда. При совместном создании искусственных событий с фильтрами можно осуществить подмену самих объектов событий. В качестве показательного примера использования подобного перехвата события с целью его подмены можно назвать изменение назначения клавиш клавиатуры. Так как класс события клавиатуры не обладает методами, позволяющими его модифицировать, то каждое сообщение клавиатуры можно получить в объекте фильтра и перед передачей дальше подменить его другим.
В следующем примере происходит подмена клавиши <9> на клавишу <0> (рис. 2). Таким образом, нажатие пользователем клавиши <9> повлечет за собой отображение цифры 0 в поле ввода. Таким образом можно, например, имитировать измененную раскладку клавиатуры.

Рис.2. Программа, демонстрирующая подмену символа
Рассмотрим текст заголовочного файла:
class KeyFilter : public QObject {
protected:
bool eventFilter(QObject* pobj, QEvent* pe)
{
//в методе eventFilter() отслеживается идентификатор события QEvent::KeyPress,
//который соответствует событию нажатия клавиши клавиатуры.
if (pe->type() == QEvent::KeyPress) {
//При обнаружении этого события его объект преобразовывается к типу
//QKeyEvent, чтобы иметь возможность вызова метода key(), который
//определен в этом классе и позволяет получить код нажатой клавиши.
if (((QKeyEvent*)pe)->key() == Qt::Key_9) {
//Затем создается и высылается новое событие нажатия клавиши <0>.
QKeyEvent* pe = new QKeyEvent(QEvent::KeyPress,
Qt::Key_0,
Qt::NoModifier,
"0"
);
QApplication::sendEvent(pobj, pe);
//После этого возвращается значение true, и это означает,
//что событие не должно передаваться дальше.
return true;
}
}
//Если событие, переданное в параметрах
//метода eventFilter(), не удовлетворяет двум поставленным условиям,
//то этот метод вернет значение false, и, тем самым, событие будет передано дальше
return false;
}
public:
KeyFilter(QObject* pobj = 0)
: QObject(pobj)
{
}
};Приведем часть текста программы с комментариями:
//создается объект класса QLineEdit и вызывается метода show() QLineEdit txt; txt.show(); //создается объект фильтра событий клавиатуры pFilter, в конструктор которого //в качестве объекта-предка передается адрес на однострочное //текстовое поле txt KeyFilter* pFilter = new KeyFilter(&txt); //созданный фильтр привязывается к текстовому полю методом installEventFilter() txt.installEventFilter(pFilter);
Файлы приложения можно взять здесь.
На следующем шаге рассмотрим правила создания диалоговых окон.