В первой части статьи было кратко рассмотрено, как запустить QT в своем приложении, однако, не было сказано ни одного слово о том, как передавать в QT разнообразные события, чтобы GUI начал работать.

Также в первой части статьи вскользь упоминалась библиотека qglgui (https://github.com/Kvalme/qglgui). Эта библиотека предназначена для интеграции QT в свое приложение.

Передача сообщений от клавиатуры/мышки в QT

Первое желание, которое возникает после реализации рендеринга QT — потыкать в кнопочки. Первый метод которым хочется воспользоваться — запихнуть события непосредственно в  QApplication::event, что разумеется не работает. Покопавшись чуть дальше, мы увидим, что события надо подсовывать непосредственно в eventloop QT и периодически дергать его.

Для работы с eventLoop у QApplication есть два метода:

  • Можно вызвать QApplication::exec и больше ни о чем не думать. Из данного метода QApplication вернется только при закрытии. Так что этот метод не подходит, если мы хотим сохранить контроль над тредом QT, либо вообще делать что-либо кроме рисования UI в однопоточном случае.
  • QApplication::processEvents — данный метод обрабатывает все имеющиеся на данный момент события и возвращает управление. Именно его я и предлагаю использовать.

После организации цикла с QApplication::processEvents в нашем приложении смогут работать сигналы, например, от таймера.

Для передачи событий в QT из QPA есть специальный класс: QWindowSystemInterface.

QWindowSystemInterface

Данный класс предназначен для получения событий от оконной системы. К сожалению, на него, как и почти на все классы QPA, нет никакой документации, поэтому все приходится узнавать либо методом тыка, либо смотря исходники QT.

Из того, что было найдено, наиболее важная вещь — методы данного класса могут вызываться не из основного потока QT приложения.

События от клавиатуры

От клавиатуры у нас есть всего два вида событий — нажатие и отпускание кнопки. Для передачи этих событий в QT используется один метод:

static void handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);

Кратко по списку параметров:

  • w — окно которому передать события. Если передать NULL — уйдет текущему активному окну
  • t — тип события. QEvent::KeyPress либо QEvent::KeyRelease
  • k — кнопка с которой произошло событие (одна из Qt::Key)
  • mods — состояние модификаторов (Qt::NoModifier, Qt::AltModifier, Qt::ShiftModifier, Qt::ControlModifier, Qt::MetaModier, есть еще экзотические типа: Qt::KeypadModifier, Qt::GroupSwitchModifier)
  • text — символ, который соответствует нажатой кнопке. Если этот параметр пустой — отрабатывает нажатие кнопки, если не пустой — кнопка игнорируется и отрабатывается только печать символа
  • autorep — по всей видимости что-то, связанное с автоповтором кнопки. Я реализую автоповтор с вызывающей стороны, поэтому не экспериментировал с этим параметром
  • count — видимо, количество нажатий

События от мышки

Данная группа несколько объемней, и имеет некоторые тонкости в обработке. Рассмотрим методы по порядку.

static void handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier);

Данный метод занимается работой с событиями от кнопок мыши и передвижения мыши.

  • w — окно которому нужно передать событие.
  • local — локальные (оконные) координаты точки в которой произошло событие. Можно получить используя wnd->mapFromGlobal(global)
  • global — глобальные (экранные) координаты точки в которой произошло событие.
  • b — нажатые кнопки. Если кнопка была отпущена — не передаем флаг, соответствующий отпущенной кнопке.
  • mods — состояние модификаторов клавиатуры (Qt::NoModifier, Qt::AltModifier, Qt::ShiftModifier, Qt::ControlModifier, Qt::MetaModier, есть еще экзотические типа: Qt::KeypadModifier, Qt::GroupSwitchModifier)
  • source — не трогаем. Назначение не известно.

Особенность обработки нажатий кнопок состоит в том, что необходимо после передачи события в QT, еще и вручную активировать окно (w->requestActivate).

static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::ScrollPhase phase = Qt::ScrollUpdate);

Данный метод занимается работой с событиями от колесиков мыши.Параметры в целом совпадают с теми, что были рассмотрены выше. Два новых параметра(pixelDelta и angleDelta) отвечают за 2 координаты колесиков. Я заполняю их так:

QPoint angleDelta(deltax, deltay);
QPoint pixelDelta(angleDelta * 10);

Возможно, есть нормальный метод перевода угла поворота в пиксельное значение, но я его не нашел.

Обработка событий в QGLGUI

QGLGUI реализует как однопоточную схему работы с QT, так и многопоточную. Для передачи событий выделены несколько методов в классе GlGui:

/**
 * Injects mouse move event into QT event queue
 * 
 * @param screenId idientifyer of the screen on which event happened
 * @param positon current mouse position
 * @param buttons pressed mouse buttons
 * @param modifiers active keyboard modifiers
 */
virtual void InjectMouseMoveEvent(int screenId, QPoint position, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers) = 0;
 
/**
 * Injects mouse button event into QT event queue
 * 
 * @param screenId idientifyer of the creen on which event happened
 * @param position current mouse position
 * @param button pressed button
 * @param modifiers active keyboard modifiers
 */
virtual void InjectMouseButtonEvent(int screenId, QPoint position, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) = 0;
 
/**
 * Injects mouse wheel event into QT event queue
 * 
 * @param screenId identifyer of the screen on which event happened
 * @param position current mouse position
 * @param deltax offset of mouse wheel on X axis
 * @param deltay offset of mousewheel on Y axis
 * @param modifiers active keyboard modifiers
 */
virtual void InjectMouseWheelEvent(int screenId, QPoint position, double deltax, double deltay, Qt::KeyboardModifiers modifiers) = 0;
 
/**
 * Injects keyboard event into QT event queue
 * Always passes key to current active window
 * 
 * @param eventType Qt::KeyPress or Qt::KeyRelease
 * @param key key
 * @param modifiers modifiers state (shift, meta, ctrl)
 */
virtual void InjectKeyboardEvent(QEvent::Type eventType, Qt::Key key, Qt::KeyboardModifiers modifiers) = 0;
 
/**
 * Injects character event into QT event queue
 * Always passes character to current active window
 * 
 * @param character character to inject
 */
virtual void InjectCharacterEvent(QChar character) = 0;

Данные методы могут быть вызваны из любого треда. Также, для упрощения интеграции с GLFW, имеется вспомогательная библиотека — glfwhelper.

 

Tags: , ,

This entry was posted on Понедельник, Июнь 9th, 2014 at 23:00 and is filed under OpenGL, QT. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.

Comments are closed at this time.