Класс QOpenGLWidget
Класс QOpenGLWidget — это виджет для отрисовки графики OpenGL. Подробнее...
| Заголовок: | #include <QOpenGLWidget> |
| CMake: | find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::OpenGLWidgets) |
| qmake: | QT += openglwidgets |
| С тех пор: | Qt 5.4 |
| Наследует: | QWidget |
Типы публичного доступа
| перечисление | UpdateBehavior { NoPartialUpdate, PartialUpdate } |
Функции публичного доступа
| QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) | |
| виртуальный | ~QOpenGLWidget() |
| QOpenGLContext * | context() const |
| GLuint | defaultFramebufferObject() const |
| void | doneCurrent() |
| QSurfaceFormat | format() const |
| QImage | grabFramebuffer() |
| bool | isValid() const |
| void | makeCurrent() |
| void | setFormat(const QSurfaceFormat &format) |
| void | setTextureFormat(GLenum texFormat) |
| void | setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior) |
| GLenum | textureFormat() const |
| QOpenGLWidget::UpdateBehavior | updateBehavior() const |
Сигналы
| void | aboutToCompose() |
| void | aboutToResize() |
| void | frameSwapped() |
| void | resized() |
Защищенные функции
| виртуальный void | initializeGL() |
| виртуальный void | paintGL() |
| виртуальный void | resizeGL(int w, int h) |
Переопределённые защищенные функции
| виртуальный bool | event(QEvent *e) override |
| виртуальный int | metric(QPaintDevice::PaintDeviceMetric metric) const override |
| виртуальный QPaintEngine * | paintEngine() const override |
| виртуальный void | paintEvent(QPaintEvent *e) override |
| виртуальный QPaintDevice * | redirected(QPoint *p) const override |
| виртуальный void | resizeEvent(QResizeEvent *e) override |
Подробное описание
QOpenGLWidget предоставляет функциональность для отображения графики OpenGL, интегрированной в приложение Qt. Его использование очень простое: сделайте свой класс наследником от него и используйте подкласс как любой другой QWidget, за исключением того, что у вас есть выбор между использованием QPainter и стандартными командами рендеринга OpenGL.
QOpenGLWidget предоставляет три удобные виртуальные функции, которые вы можете переопределить в своем подклассе для выполнения типичных задач OpenGL:
- paintGL() — отрисовывает сцену OpenGL. Вызывается всякий раз, когда виджету требуется обновление.
- resizeGL() — настраивает область просмотра OpenGL, проекцию и т. д. Вызывается всякий раз, когда виджет был изменен по размеру (а также при его первом отображении, поскольку все вновь созданные виджеты автоматически получают событие изменения размера).
- initializeGL() — настраивает ресурсы и состояние OpenGL. Вызывается один раз перед первым вызовом resizeGL() или paintGL().
Если вам нужно инициировать перерисовку из мест, отличных от paintGL() (типичный пример — при использовании таймеров для анимации сцен), вы должны вызвать функцию update() виджета, чтобы запланировать обновление.
Контекст рендеринга OpenGL вашего виджета становится текущим, когда вызываются paintGL(), resizeGL() или initializeGL(). Если вам нужно вызвать стандартные функции API OpenGL из других мест (например, в конструкторе вашего виджета или в ваших собственных функциях рисования), вы должны сначала вызвать makeCurrent().
Все рендеринг происходит в объекте буфера OpenGL. makeCurrent() гарантирует, что он привязан к контексту. Помните об этом, создавая и связывая дополнительные объекты буфера в коде рендеринга в paintGL(). Никогда не перепривязывайте буфер с ID 0. Вместо этого, вызовите defaultFramebufferObject(), чтобы получить ID, который должен быть привязан.
QOpenGLWidget позволяет использовать различные версии и профили OpenGL, когда платформа их поддерживает. Просто установите требуемый формат через setFormat(). Однако помните, что наличие нескольких экземпляров QOpenGLWidget в одном окне требует, чтобы все они использовали один и тот же формат или, по крайней мере, форматы, которые не делают контексты несовместимыми. Чтобы обойти эту проблему, предпочитайте использовать QSurfaceFormat::setDefaultFormat() вместо setFormat().
Примечание: Вызов QSurfaceFormat::setDefaultFormat() до создания экземпляра QApplication обязателен на некоторых платформах (например, macOS), когда запрашивается контекст профиля OpenGL core. Это необходимо для обеспечения функциональности совместного использования ресурсов между контекстами, поскольку все внутренние контексты создаются с правильной версией и профилем.
Методы отрисовки
Как описано выше, подклассируйте QOpenGLWidget, чтобы отрисовывать чистый 3D-контент следующим образом:
- Переопределите функции initializeGL() и resizeGL(), чтобы настроить состояние OpenGL и предоставить преобразование перспективы.
- Переопределите paintGL(), чтобы отрисовать 3D-сцену, вызывая только функции OpenGL.
Также можно рисовать 2D-графику на подклассе QOpenGLWidget с помощью QPainter:
- В paintGL(), вместо выдачи команд OpenGL, создайте объект QPainter для использования на виджете.
- Отрисуйте примитивы, используя методы члена QPainter.
- Прямые команды OpenGL по-прежнему могут быть выпущены. Однако вы должны убедиться, что они заключены в вызов beginNativePainting() и endNativePainting() художника.
При выполнении рисования только с помощью QPainter, также можно выполнить отрисовку так, как это делается для обычных виджетов: переопределив paintEvent().
END_OF_DOCUMENT_MARKER- Переопределите функцию paintEvent().
- Создайте объект QPainter, ориентированный на виджет. Передайте виджет в конструктор или используйте функцию QPainter::begin().
- Отрисовывайте примитивы с помощью функций-членов QPainter.
- Отрисовка завершается, когда экземпляр QPainter уничтожается. В качестве альтернативы, явно вызовите QPainter::end().
Вызовы функций OpenGL, заголовочные файлы и QOpenGLFunctions
При выполнении вызовов функций OpenGL настоятельно рекомендуется избегать непосредственного вызова этих функций. Вместо этого предпочтительнее использовать QOpenGLFunctions (при разработке переносимых приложений) или версиированные варианты (например, QOpenGLFunctions_3_2_Core и аналогичные, при нацеливании на современные, только настольные OpenGL). Таким образом, приложение будет работать корректно во всех конфигурациях сборки Qt, включая те, которые выполняют динамическую загрузку реализации OpenGL, что означает, что приложения не связываются напрямую с реализацией GL, и поэтому прямые вызовы функций невозможны.
В функции paintGL() текущий контекст всегда доступен путем вызова QOpenGLContext::currentContext(). Из этого контекста можно получить уже инициализированный, готовый к использованию экземпляр QOpenGLFunctions вызовом QOpenGLContext::functions(). Альтернативой префиксации каждого вызова GL является наследование от QOpenGLFunctions и вызов QOpenGLFunctions::initializeOpenGLFunctions() в initializeGL().
Что касается заголовочных файлов OpenGL, то в большинстве случаев не нужно напрямую включать какие-либо заголовочные файлы, такие как GL.h. Заголовочные файлы Qt, связанные с OpenGL, будут включать qopengl.h, который в свою очередь будет включать соответствующий заголовочный файл для системы. Это может быть заголовочный файл OpenGL ES 3.x или 2.0, самая последняя доступная версия, или системный gl.h. Кроме того, копия заголовочных файлов расширений (называемая glext.h на некоторых системах) предоставляется в составе Qt как для OpenGL, так и для OpenGL ES. Они будут автоматически включены на платформах, где это возможно. Это означает, что константы и определения типов указателей функций из расширений ARB, EXT, OES автоматически доступны.
Примеры кода
Для начала, простейший подкласс QOpenGLWidget может выглядеть следующим образом:
class MyGLWidget : public QOpenGLWidget
{
public:
MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { }
protected:
void initializeGL() override
{
// Set up the rendering context, load shaders and other resources, etc.:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
...
}
void resizeGL(int w, int h) override
{
// Update projection matrix and other size related settings:
m_projection.setToIdentity();
m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);
...
}
void paintGL() override
{
// Draw the scene:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClear(GL_COLOR_BUFFER_BIT);
...
}
}; В качестве альтернативы, можно избежать префиксации каждого вызова OpenGL, унаследовав от QOpenGLFunctions:
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
...
void initializeGL() override
{
initializeOpenGLFunctions();
glClearColor(...);
...
}
...
}; Чтобы получить контекст, совместимый с заданной версией или профилем OpenGL, или чтобы запросить буферы глубины и трафарета, вызовите setFormat():
QOpenGLWidget *widget = new QOpenGLWidget(parent); QSurfaceFormat format; format.setDepthBufferSize(24); format.setStencilBufferSize(8); format.setVersion(3, 2); format.setProfile(QSurfaceFormat::CoreProfile); widget->setFormat(format); // must be called before the widget or its parent window gets shown
В контекстах OpenGL 3.0+, когда переносимость не важна, версиированные варианты QOpenGLFunctions обеспечивают лёгкий доступ ко всем современным функциям OpenGL, доступным в данной версии:
...
void paintGL() override
{
QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
...
f->glDrawArraysInstanced(...);
...
}
... Как описано выше, проще и надёжнее установить требуемый формат глобально, чтобы он применялся ко всем окнам и контекстам в течение всего срока жизни приложения. Ниже приведён пример этого:
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
MyWidget widget;
widget.show();
return app.exec();
} Многократная выборка
Чтобы включить многократную выборку, установите количество запрашиваемых выборок в QSurfaceFormat, который передаётся в setFormat(). На системах, которые её не поддерживают, запрос может быть проигнорирован.
Поддержка многократной выборки требует поддержки буферов рендеринга с многократной выборкой и блинтов фреймбуфера. На реализациях OpenGL ES 2.0, вероятно, их не будет. Это означает, что многократная выборка недоступна. С современными версиями OpenGL и OpenGL ES 3.0 и выше эта проблема обычно уже не актуальна.
Потоки
Выполнение рендеринга вне области видимости на рабочих потоках, например, для генерации текстур, которые затем используются в пользовательском интерфейсе/главном потоке в paintGL(), поддерживается путём экспонирования QOpenGLContext виджета, чтобы на каждом потоке можно было создавать дополнительные контексты, которые с ним делят ресурсы.
Прямой вывод в фреймбуфер QOpenGLWidget вне пользовательского интерфейса/главного потока возможен путём переопределения paintEvent() на пустую функцию. Аффинити потока контекста нужно изменить с помощью QObject::moveToThread(). После этого, makeCurrent() и doneCurrent() будут доступны в рабочем потоке. Убедитесь, что затем контекст возвращается в пользовательский интерфейс/главный поток.
Инициирование обмена буферами только для QOpenGLWidget невозможно, так как нет реальной, отображаемой на экране нативной поверхности для этого. Управление композицией и обменом буферами в потоке пользовательского интерфейса выполняется стеком виджетов. Когда поток завершает обновление фреймбуфера, вызовите update() в пользовательском интерфейсе/главном потоке, чтобы запланировать композицию.
Необходимо проявлять особую осторожность, чтобы не использовать фреймбуфер, когда поток пользовательского интерфейса/главного потока выполняет композицию. Сигналы aboutToCompose() и frameSwapped() будут испускаться при старте и завершении композиции. Они испускаются в потоке пользовательского интерфейса/главного потока. Это означает, что с помощью прямого подключения aboutToCompose() может заблокировать поток пользовательского интерфейса/главного потока, пока рабочий поток не завершит рендеринг. После этого, рабочий поток не должен выполнять дальнейший рендеринг до испускания сигнала frameSwapped(). Если это неприемлемо, рабочий поток должен реализовать механизм двойного буферирования. Это включает в себя рендеринг с помощью альтернативной цели рендеринга, которая полностью контролируется потоком, например, дополнительного объекта фреймбуфера, и блинтинг в фреймбуфер QOpenGLWidget в подходящее время.
Деление контекстов
Если несколько QOpenGLWidgets добавлены в качестве дочерних элементов одному верхнему виджету, их контексты будут совместно использоваться. Это не относится к экземплярам QOpenGLWidget, которые принадлежат различным окнам.
Это означает, что все QOpenGLWidgets в одном окне могут получать доступ к общим ресурсам друг друга, таким как текстуры, и нет необходимости в дополнительном глобальном контексте обмена.
Чтобы настроить совместное использование между экземплярами QOpenGLWidget, принадлежащими различным окнам, установите атрибут приложения Qt::AA_ShareOpenGLContexts перед созданием экземпляра QApplication. Это запустит совместное использование между всеми экземплярами QOpenGLWidget без дополнительных шагов.
Также возможно создание дополнительных экземпляров QOpenGLContext, которые делят ресурсы, такие как текстуры, с контекстом QOpenGLWidget. Просто передайте указатель, возвращённый из context(), в QOpenGLContext::setShareContext() перед вызовом QOpenGLContext::create(). Полученный контекст также можно использовать в другом потоке, что позволяет выполнять генерацию текстур и асинхронную загрузку текстур в потоках.
Обратите внимание, что QOpenGLWidget ожидает стандартной реализации совместного использования ресурсов в отношении драйверов графических процессоров. Например, некоторые драйверы, в особенности для мобильных и встроенных устройств, имеют проблемы с настройкой совместного использования между существующим контекстом и другими контекстами, созданными позже. Другие драйверы могут вести себя непредсказуемым образом при попытке использовать общие ресурсы между разными потоками.
Инициализация и очистка ресурсов
Связанный с QOpenGLWidget контекст OpenGL гарантированно будет текущим при вызове initializeGL() и paintGL(). Не пытайтесь создавать ресурсы OpenGL до вызова initializeGL(). Например, попытка компиляции шейдеров, инициализации объектов буферов вершин или загрузки данных текстур завершится ошибкой, если это выполняется в конструкторе подкласса. Эти операции необходимо отложить до initializeGL(). Некоторые вспомогательные классы Qt для OpenGL, такие как QOpenGLBuffer или QOpenGLVertexArrayObject, имеют аналогичное отложенное поведение: они могут быть созданы без контекста, но вся инициализация откладывается до вызова create() или аналогичного. Это означает, что они могут быть использованы как обычные (не-указательские) члены данных в подклассе QOpenGLWidget, но функция create() или аналогичная может быть вызвана только из initializeGL(). Однако имейте в виду, что не все классы разработаны таким образом. В случае сомнений, сделайте член данных указателем и создайте/уничтожьте экземпляр динамически в initializeGL() и деструкторе соответственно.
Освобождение ресурсов также требует, чтобы контекст был текущим. Поэтому ожидается, что деструкторы, выполняющие такую очистку, вызовут makeCurrent() перед уничтожением любых ресурсов OpenGL или обёртки. Избегайте отложенного удаления через deleteLater() или механизм наследования QObject. Нет гарантии, что правильный контекст будет текущим в момент фактического уничтожения соответствующего экземпляра.
Типичный подкласс, следовательно, часто будет выглядеть следующим образом, когда речь идёт об инициализации и уничтожении ресурсов:
class MyGLWidget : public QOpenGLWidget
{
...
private:
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
QOpenGLShaderProgram *m_program;
QOpenGLShader *m_shader;
QOpenGLTexture *m_texture;
};
MyGLWidget::MyGLWidget()
: m_program(0), m_shader(0), m_texture(0)
{
// No OpenGL resource initialization is done here.
}
MyGLWidget::~MyGLWidget()
{
// Make sure the context is current and then explicitly
// destroy all underlying OpenGL resources.
makeCurrent();
delete m_texture;
delete m_shader;
delete m_program;
m_vbo.destroy();
m_vao.destroy();
doneCurrent();
}
void MyGLWidget::initializeGL()
{
m_vao.create();
if (m_vao.isCreated())
m_vao.bind();
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(...);
m_texture = new QOpenGLTexture(QImage(...));
m_shader = new QOpenGLShader(...);
m_program = new QOpenGLShaderProgram(...);
...
} Это, естественно, не единственное возможное решение. Альтернативой является использование сигнала aboutToBeDestroyed() QOpenGLContext. Подключив слот, используя прямое подключение, к этому сигналу, можно выполнить очистку всякий раз, когда будет освобождаться базовый обработчик нативного контекста или весь экземпляр QOpenGLContext. Следующий фрагмент принципиально эквивалентен предыдущему:
void MyGLWidget::initializeGL()
{
// context() and QOpenGLContext::currentContext() are equivalent when called from initializeGL or paintGL.
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup);
}
void MyGLWidget::cleanup()
{
makeCurrent();
delete m_texture;
m_texture = 0;
...
doneCurrent();
} Примечание: Для виджетов, которые многократно изменяют связанное с ними окно верхнего уровня в течение своего жизненного цикла, необходим комбинированный подход. Всякий раз, когда виджет или его родительское окно переродируются таким образом, что окно верхнего уровня становится другим, связанный с виджетом контекст уничтожается, и создается новый. После этого вызывается initializeGL(), где все ресурсы OpenGL должны быть повторно инициализированы. По этой причине единственный способ выполнить правильную очистку — подключиться к сигналу context's aboutToBeDestroyed(). Обратите внимание, что контекст, о котором идет речь, может быть не текущим, когда сигнал испускается. Поэтому рекомендуется вызвать makeCurrent() в подключенном слоте. Кроме того, те же шаги по очистке должны быть выполнены из деструктора производного класса, так как слот, подключенный к сигналу, не будет вызван при уничтожении виджета.
Примечание: При установке Qt::AA_ShareOpenGLContexts, контекст виджета никогда не изменяется, даже при перерождении, поскольку за текстуру виджета гарантируется доступ из контекста нового окна верхнего уровня.
Правильная очистка особенно важна из-за совместного использования контекста. Несмотря на то, что каждый связанный с QOpenGLWidget контекст уничтожается вместе с QOpenGLWidget, совместные ресурсы в этом контексте, такие как текстуры, останутся валидными до тех пор, пока не будет уничтожено окно верхнего уровня, в котором существовал QOpenGLWidget. Кроме того, настройки, такие как Qt::AA_ShareOpenGLContexts и некоторые модули Qt, могут вызвать более широкий охват совместного использования контекстов, потенциально сохраняя данные ресурсы до конца жизненного цикла приложения. Поэтому наиболее безопасным и надежным методом является выполнение явной очистки всех ресурсов и обёртки ресурсов, используемых в QOpenGLWidget.
Ограничения
Размещение других виджетов под QOpenGLWidget и установка его прозрачности не приведут к ожидаемым результатам: виджеты под ним не будут видны. Это происходит потому, что на практике QOpenGLWidget отрисовывается до всех остальных обычных, не-OpenGL виджетов, поэтому решения с прозрачностью невозможны. Другие типы макетов, например, размещение виджетов поверх QOpenGLWidget, будут работать как ожидается.
В случае крайней необходимости это ограничение можно преодолеть, установив атрибут Qt::WA_AlwaysStackOnTop для QOpenGLWidget. Однако имейте в виду, что это нарушает порядок стека; например, другие виджеты не смогут располагаться поверх QOpenGLWidget, поэтому его следует использовать только в ситуациях, когда требуется полупрозрачный QOpenGLWidget с видимыми виджетами под ним.
Обратите внимание, что это не относится к случаям, когда нет других виджетов под ним и предполагается иметь полупрозрачное окно. В этом случае достаточно традиционного подхода — установить Qt::WA_TranslucentBackground на окне верхнего уровня. Обратите внимание, что если прозрачные области требуются только в QOpenGLWidget, то Qt::WA_NoSystemBackground необходимо вернуть к false после включения Qt::WA_TranslucentBackground. Кроме того, в зависимости от системы, может потребоваться запросить альфа-канал для контекста QOpenGLWidget через setFormat().
QOpenGLWidget поддерживает несколько вариантов поведения при обновлении, аналогично QOpenGLWindow. В режиме сохранения содержимое, отрисованное в предыдущем вызове paintGL(), доступно в следующем, что позволяет выполнять инкрементную отрисовку. В режиме несохранения содержимое теряется, и реализация paintGL() должна перерисовывать всё в представлении.
Перед Qt 5.5 по умолчанию QOpenGLWidget сохранял содержимое, отрисованное между вызовами paintGL(). Начиная с Qt 5.5, поведение по умолчанию — несохранение, так как это обеспечивает лучшую производительность, и большинству приложений не нужен предыдущий контент. Это также соответствует семантике OpenGL-базированного QWindow и совпадает с поведением по умолчанию QOpenGLWindow, при котором цветовые и вспомогательные буферы недействительны для каждого кадра. Чтобы восстановить сохранённое поведение, вызовите setUpdateBehavior() со значением PartialUpdate.
Примечание: Для отображения QOpenGLWidget требуется альфа-канал в буфере хранения связанного с ним окна верхнего уровня из-за способа композиции с другими контентом на основе QWidget. Если альфа-канала нет, содержимое, отрисованное QOpenGLWidget, не будет видно. Это может быть особенно актуально на Linux/X11 в настройках удалённого дисплея (например, с Xvnc), при использовании глубины цвета ниже 24. Например, глубина цвета 16 обычно приводит к использованию изображения буфера хранения с форматом QImage::Format_RGB16 (RGB565), не оставляя места для альфа-канала. Поэтому, если возникают проблемы с корректной композицией содержимого QOpenGLWidget с другими виджетами в окне, убедитесь, что сервер (например, vncserver) настроен на глубину 24 или 32 бита вместо 16.
Альтернативы
Добавление QOpenGLWidget в окно включает OpenGL-композицию для всего окна. В некоторых особых случаях это может быть нежелательно, и желательно старое поведение QGLWidget с отдельным, нативным дочерним окном. Приложения для настольных компьютеров, понимающие ограничения этого подхода (например, при перекрытиях, прозрачности, прокрутке и областях MDI), могут использовать QOpenGLWindow с QWidget::createWindowContainer(). Это современная альтернатива QGLWidget и быстрее QOpenGLWidget благодаря отсутствию дополнительного шага композиции. Сильно рекомендуется ограничивать использование этого подхода случаями, когда нет другого выбора. Обратите внимание, что этот вариант не подходит для большинства встраиваемых и мобильных платформ, а также известны проблемы на некоторых настольных платформах (например, macOS). Устойчивое и кроссплатформенное решение — всегда QOpenGLWidget.
OpenGL — торговая марка Silicon Graphics, Inc. в США и других странах.
См. также QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts и UpdateBehavior.
Документация по типам членов
[since 5.5] перечисление QOpenGLWidget::UpdateBehavior
Это перечисление описывает семантику обновления QOpenGLWidget.
| Постоянная | Значение | Описание |
|---|---|---|
QOpenGLWidget::NoPartialUpdate |
0 |
QOpenGLWidget будет отбрасывать содержимое цветового буфера и вспомогательных буферов после отрисовки QOpenGLWidget на экране. Это то же поведение, которое можно ожидать при вызове QOpenGLContext::swapBuffers с аргументом по умолчанию OpenGL-активный QWindow. NoPartialUpdate может обеспечить некоторые преимущества производительности на определенных аппаратных архитектурах, распространенных в мобильных и встраиваемых системах, когда используется объект framebuffer. Объект framebuffer недействителен между кадрами с glDiscardFramebufferEXT, если поддерживается, или glClear. Подробнее см. документацию по EXT_discard_framebuffer: https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt |
QOpenGLWidget::PartialUpdate |
1 |
Цветовой буфер и вспомогательные буферы объекта framebuffer не делают недействительными между кадрами. |
Это перечисление было введено или изменено в Qt 5.5.
См. также updateBehavior() и setUpdateBehavior().
Документация по функциям-членам
QOpenGLWidget::QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
Конструирует виджет, являющийся потомком parent, с установленными флагами виджета f.
[signal] void QOpenGLWidget::aboutToCompose()
Этот сигнал испускается, когда окно верхнего уровня виджета собирается начать композицию текстур его QOpenGLWidget дочерних элементов и других виджетов.
[signal] void QOpenGLWidget::aboutToResize()
Этот сигнал испускается при изменении размера виджета, и поэтому объект framebuffer будет пересоздан.
[signal] void QOpenGLWidget::frameSwapped()
Этот сигнал испускается после того, как окно верхнего уровня виджета завершило композицию и вернулось из потенциально блокирующего вызова QOpenGLContext::swapBuffers().
[signal] void QOpenGLWidget::resized()
Этот сигнал испускается сразу после пересоздания объекта framebuffer из-за изменения размера виджета.
[virtual] QOpenGLWidget::~QOpenGLWidget()
Уничтожает экземпляр QOpenGLWidget, освобождая его ресурсы.
Контекст QOpenGLWidget делается текущим в деструкторе, что позволяет безопасно уничтожить любой дочерний объект, который может потребовать освобождения ресурсов OpenGL, принадлежащих контексту, предоставляемому этим виджетом.
Предупреждение: Если у вас есть объекты, оборачивающие ресурсы OpenGL (например, QOpenGLBuffer, QOpenGLShaderProgram и т. д.) в качестве членов подкласса OpenGLWidget, вам может потребоваться добавить вызов makeCurrent() и в деструкторе этого подкласса. Из-за правил уничтожения объектов C++, эти объекты будут уничтожены до вызова этой функции (но после того, как выполнится деструктор подкласса), поэтому сделать контекст OpenGL текущим в этой функции происходит слишком поздно для их безопасного удаления.
См. также makeCurrent.
QOpenGLContext *QOpenGLWidget::context() const
Возвращает QOpenGLContext, используемый этим виджетом, или 0, если он ещё не инициализирован.
Примечание: Контекст и объект фреймбуфера, используемые виджетом, изменяются при изменении родительского виджета с помощью setParent().
См. также QOpenGLContext::setShareContext() и defaultFramebufferObject().
GLuint QOpenGLWidget::defaultFramebufferObject() const
Возвращает идентификатор объекта фреймбуфера или 0, если он ещё не инициализирован.
Примечание: Объект фреймбуфера принадлежит контексту, возвращаемому context(), и может быть недоступен из других контекстов.
Примечание: Контекст и объект фреймбуфера, используемые виджетом, изменяются при изменении родительского виджета с помощью setParent(). Кроме того, объект фреймбуфера изменяется при каждом изменении размера.
См. также context().
void QOpenGLWidget::doneCurrent()
Освобождает контекст.
В большинстве случаев вызов этой функции не требуется, так как виджет позаботится о корректном связывании и освобождении контекста при вызове paintGL().
[override virtual protected] bool QOpenGLWidget::event(QEvent *e)
Переопределяет: QWidget::event(QEvent *event).
QSurfaceFormat QOpenGLWidget::format() const
Возвращает формат контекста и поверхности, используемый этим виджетом и его родительским окном.
После создания, изменения размера и отображения виджета и его родительского окна эта функция вернёт фактический формат контекста. Он может отличаться от запрошенного формата, если платформа не смогла его удовлетворить. Также возможно получение большего размера буфера цвета, чем запрошенного.
Когда окно виджета и связанные с ним OpenGL ресурсы ещё не инициализированы, возвращаемое значение — это формат, установленный с помощью setFormat().
См. также setFormat() и context().
QImage QOpenGLWidget::grabFramebuffer()
Отображает и возвращает 32-битное RGB изображение фреймбуфера.
Примечание: Это потенциально дорогостоящая операция, так как она полагается на glReadPixels() для чтения пикселей. Это может быть медленным и замедлять работу конвейера GPU.
[virtual protected] void QOpenGLWidget::initializeGL()
Этот виртуальный метод вызывается один раз перед первым вызовом paintGL() или resizeGL(). Переопределите его в подклассе.
В этом методе следует настроить все необходимые OpenGL ресурсы и состояние.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове данного метода. Однако обратите внимание, что фреймбуфер ещё недоступен на этом этапе, поэтому избегайте выдачи команд отрисовки отсюда. Отложите такие вызовы до paintGL().
См. также paintGL() и resizeGL().
bool QOpenGLWidget::isValid() const
Возвращает true, если виджет и OpenGL ресурсы, такие как контекст, были успешно инициализированы. Обратите внимание, что возвращаемое значение всегда ложно до тех пор, пока виджет не будет отображен.
void QOpenGLWidget::makeCurrent()
Подготавливает отрисовку OpenGL-контента для этого виджета, сделав соответствующий контекст текущим и связав объект фреймбуфера в этом контексте.
В большинстве случаев вызывать эту функцию не нужно, так как она вызывается автоматически перед вызовом paintGL().
См. также context(), paintGL() и doneCurrent().
[override virtual protected] int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
Переопределяет: QWidget::metric(QPaintDevice::PaintDeviceMetric m) const.
[override virtual protected] QPaintEngine *QOpenGLWidget::paintEngine() const
Переопределяет: QWidget::paintEngine() const.
[override virtual protected] void QOpenGLWidget::paintEvent(QPaintEvent *e)
Переопределяет: QWidget::paintEvent(QPaintEvent *event).
Обрабатывает события рисования.
Вызов QWidget::update() приведёт к отправке события рисования e и, следовательно, к вызову этой функции. (Обратите внимание, что это асинхронно и произойдёт в какой-то момент после возврата из update()). Затем эта функция после некоторых подготовительных действий вызовет виртуальный метод paintGL() для обновления содержимого фреймбуфера QOpenGLWidget. После этого окно виджета объединит текстуру фреймбуфера с остальной частью окна.
[virtual protected] void QOpenGLWidget::paintGL()
Этот виртуальный метод вызывается всякий раз, когда виджет нужно перерисовать. Переопределите его в подклассе.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове этого метода.
Перед вызовом этого метода контекст и фреймбуфер привязаны, а область просмотра устанавливается с помощью вызова glViewport(). Никакое другое состояние не устанавливается, и никакое очищение или рисование не выполняется фреймворком.
См. также initializeGL() и resizeGL().
[override virtual protected] QPaintDevice *QOpenGLWidget::redirected(QPoint *p) const
[override virtual protected] void QOpenGLWidget::resizeEvent(QResizeEvent *e)
Переопределяет: QWidget::resizeEvent(QResizeEvent *event).
Обрабатывает события изменения размера, переданные в параметре события e. Вызывает виртуальный метод resizeGL().
Примечание: Избегайте переопределения этой функции в производных классах. Если это невозможно, убедитесь, что реализация QOpenGLWidget также вызывается. В противном случае, подлежащий фреймбуфер и связанные с ним ресурсы не будут правильно изменены размером, что приведёт к некорректной отрисовке.
[virtual protected] void QOpenGLWidget::resizeGL(int w, int h)
Этот виртуальный метод вызывается всякий раз, когда виджет был изменён размером. Переопределите его в подклассе. Новый размер передаётся в w и h.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове данного метода. Кроме того, фреймбуфер также привязан.
См. также initializeGL() и paintGL().
void QOpenGLWidget::setFormat(const QSurfaceFormat &format)
Устанавливает запрашиваемый формат поверхности format.
Если формат не установлен явно с помощью этой функции, будет использован формат, возвращаемый QSurfaceFormat::defaultFormat(). Это означает, что при наличии нескольких виджетов OpenGL, отдельные вызовы этой функции могут быть заменены одним вызовом QSurfaceFormat::setDefaultFormat() перед созданием первого виджета.
Примечание: Запрос буфера альфа с помощью этой функции не приведёт к желаемым результатам, когда цель — сделать видимыми другие виджеты под ним. Вместо этого используйте Qt::WA_AlwaysStackOnTop, чтобы разрешить полупрозрачные экземпляры QOpenGLWidget с видимыми другими виджетами под ними. Имейте в виду, что это нарушает порядок стека, поэтому другие виджеты больше не смогут быть расположены поверх QOpenGLWidget.
См. также format(), Qt::WA_AlwaysStackOnTop и QSurfaceFormat::setDefaultFormat().
[since 5.10] void QOpenGLWidget::setTextureFormat(GLenum texFormat)
Устанавливает пользовательский внутренний формат текстуры texFormat.
При работе с sRGB фреймбуферами необходимо указать формат, например GL_SRGB8_ALPHA8. Это можно сделать, вызвав эту функцию.
Примечание: Эта функция не имеет эффекта, если вызвана после того, как виджет уже был показан и, следовательно, выполнил инициализацию.
Примечание: Обычно эту функцию необходимо использовать в сочетании с вызовом QSurfaceFormat::setDefaultFormat(), который устанавливает цветовое пространство на QSurfaceFormat::sRGBColorSpace.
Эта функция была добавлена в Qt 5.10.
См. также textureFormat().
[since 5.5] void QOpenGLWidget::setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior)
Устанавливает поведение обновления этого виджета в updateBehavior.
Эта функция была добавлена в Qt 5.5.
См. также updateBehavior().
[since 5.10] GLenum QOpenGLWidget::textureFormat() const
Возвращает активный внутренний формат текстуры, если виджет уже инициализирован, запрошенный формат, если он был задан, но виджет ещё не стал видимым, или nullptr если setTextureFormat() не вызывался и виджет ещё не стал видимым.
Эта функция была добавлена в Qt 5.10.
См. также setTextureFormat().
[since 5.5] QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const
Возвращает поведение обновления виджета.
Эта функция была добавлена в Qt 5.5.
См. также setUpdateBehavior().
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qopenglwidget.html