QGLGUI: Интеграция QT в OpenGL приложение с использованием QPA (часть 2)

В первой части статьи было кратко рассмотрено, как запустить 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 используется один метод:

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

  • 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 — видимо, количество нажатий

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

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

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

  • 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).

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

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

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

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

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

 


Comments are closed.