В данной статье я попытаюсь рассказать о том как передавать события мыши и клавиатуры в QQuickWindow, в случае его использования в связке с QQuickRenderControl. Причиной того, что этому необходимо уделять специальное внимание, является то, что в случае использования QQuickRenderControl, никакого окна на самом деле не создается, соответственно у QQuickWindow нет абсолютно никакой возможности получать какие либо события, и их приходится эмулировать. То же самое касается изменения размеров — об этой операции так же необходимо оповещать в явном виде.
Для тех кто пропустил предыдущие части:
Как инициируютя события в Qt
Отправка события в Qt осуществляется с помощью метода
где,bool QCoreApplication::sendEvent(QObject* receiver, QEvent* event)
- receiver — получатель сообщения, в нашем случае это экземпляр QQuickWindow (или его потомка);
- event — это экземпляр конкретного типа события;
Передача событий мыши
Для корректного функционирования достаточно реализовать 3 события мыши:
QEvent::MouseButtonPress:
QPointF mousePoint( 150, 201 );
Qt::MouseButton button = Qt::LeftButton;
Qt::MouseButton buttons = Qt::LeftButton | Qt::RightButton;
Qt::KeyboardModifiers modifiers = Qt::AltModifier;
QMouseEvent mouseEvent( QEvent::MouseButtonPress, mousePoint, mousePoint, button, buttons, modifiers );
QCoreApplication::sendEvent( quickWindow, &mouseEvent );
где,
- mousePoint — текущая позиция мыши в координатах QQuickWindow;
- button — кнопка мыши вызвавшая данное событие;
- buttons — все кнопки мыши нажатые в момент генерации события;
- modifiers — нажатые на клавиатуре клавиши-модификаторы (Ctrl, Alt, Shift и т.д.);
mousePoint используется дважды, поскольку в первый раз передается в координатах QQuckWindow, второй раз в screen координатах. Но поскольку окно на самом не создается, трактуется всегда как окно верхнего уровня, и его позицией мы управляем самостоятельно, то передаем одно и то же значение (как будто окно находится всегда в верхнем левом углу экрана), а при установке позиции окна, просто будем этот факт учитывать.
QEvent::MouseMove:
QPointF mousePoint( 170, 198 );
Qt::MouseButton button = Qt::NoButton;
Qt::MouseButton buttons = Qt::LeftButton | Qt::RightButton;
Qt::KeyboardModifiers modifiers = Qt::AltModifier;
QMouseEvent mouseEvent( QEvent::MouseMove, mousePoint, mousePoint, button, buttons, modifiers );
QCoreApplication::sendEvent( quickWindow, &mouseEvent );
Поскольку причиной события передвижения мыши является сам факт передвижения мыши, а не какая-либо из кнопок, переменной button присваивается значение Qt::NoButton.
QEvent::MouseButtonRelease:
QPointF mousePoint( 160, 251 );
Qt::MouseButton button = Qt::LeftButton;
Qt::MouseButton buttons = Qt::LeftButton;
Qt::KeyboardModifiers modifiers = Qt::AltModifier;
QMouseEvent mouseEvent( QEvent::MouseButtonRelease, mousePoint, mousePoint, button, buttons, modifiers );
QCoreApplication::sendEvent( quickWindow, &mouseEvent );
button в данном случае означает кнопку являвшуюся причиной данного события, но в данном случае кнопка была отпущена, соответственно buttons она присутствовать уже не может (иначе Qt начинает обрабатывать это событие неверно).
Передача событий клавиатуры
Аналогично, для корректной обработки событий клавиатуры, достаточно реализовать 2 события:
QEvent::KeyPress:
Qt::Key qtKey = Qt::Key_Space;
QKeyEvent keyEvent( QEvent::KeyPress, qtKey, Qt::NoModifier );
QCoreApplication::sendEvent( quickWindow, &keyEvent );
QEvent::KeyRelease:
Qt::Key qtKey = Qt::Key_Space;
QKeyEvent keyEvent( QEvent::KeyRelease, qtKey, Qt::NoModifier );
QCoreApplication::sendEvent( quickWindow, &keyEvent );
Изменение размеров
Как уже упомяналось выше, offscreen окна в Qt трактутся как окна верхнего уровня, поэтому используем соответствующий метод:
QSize newSize( 320, 240 );
quickWindow->setGeometry( 0, 0, newSize.width(), newSize.height() );
Помимо изменения размеров собственно окна, желательно так же изменить размеры FBO, т.к. в противном случае либо получим пикселизацию (при увеличении размера), либо бессмысленное расходование ресурсов (т.к. размер FBO будет больше чем требуется):
if( context->makeCurrent( offscreenSurface ) ) {
destroyFbo();
createFbo();
context->doneCurrent();
}
Поскольку изменить размер FBO невозможно, просто удаляем текущий и создаем новый ( см. детали в Первой части ).
На этом все.
Примеры реализации, как обычно, доступены на GitHub
Ну и как и прежде, коментарии, вопросы, здоровая критика — приветствуются.
Продолжение следует...
Автор: RSATom