Класс QOpenGLWidget
Класс QOpenGLWidget — это виджет для отрисовки графики OpenGL. Подробнее...
| Заголовок: | #include <QOpenGLWidget> |
| qmake: | QT += widgets |
| С тех пор: | Qt 5.4 |
| Наследует: | QWidget |
Типы публичного доступа
| перечисление | UpdateBehavior { NoPartialUpdate, PartialUpdate } |
Функции публичного доступа
| QOpenGLWidget(QWidget *parent = Q_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 | setUpdateBehavior(UpdateBehavior updateBehavior) |
| UpdateBehavior | updateBehavior() const |
- 211 функций публичного доступа, унаследованных от QWidget
- 31 функция публичного доступа, унаследованная от QObject
- 14 функция публичного доступа, унаследованная от QPaintDevice
Сигналы
| void | aboutToCompose() |
| void | aboutToResize() |
| void | frameSwapped() |
| void | resized() |
Защищённые функции
| virtual void | initializeGL() |
| virtual void | paintGL() |
| virtual void | resizeGL(int w, int h) |
Переопределённые защищённые функции
| virtual void | paintEvent(QPaintEvent *e) |
| virtual void | resizeEvent(QResizeEvent *e) |
- 35 защищённых функций, унаследованных от QWidget
- 9 защищённых функций, унаследованных от QObject
- 1 защищённая функция, унаследованная от QPaintDevice
Дополнительные унаследованные члены
- 58 свойств, унаследованных от QWidget
- 1 свойство, унаследованное от QObject
- 19 публичных слотов, унаследованных от QWidget
- 1 публичный слот, унаследованный от QObject
- 5 статических публичных членов, унаследованных от QWidget
- 11 статических публичных членов, унаследованных от QObject
- 1 защищённый слот, унаследованный от QWidget
Подробное описание
Класс QOpenGLWidget — это виджет для отрисовки графики OpenGL.
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(). Никогда не перепривязывайте буфер кадров с идентификатором 0. Вместо этого вызовите defaultFramebufferObject(), чтобы получить идентификатор, который нужно привязать.
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().
- Переопределите функцию 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()
{
// 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)
{
// 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()
{
// Draw the scene:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClear(GL_COLOR_BUFFER_BIT);
...
}
}; В качестве альтернативы, можно избежать префиксации каждого вызова OpenGL, унаследовав от QOpenGLFunctions вместо этого:
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
...
void initializeGL()
{
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()
{
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();
} Отношение к QGLWidget
Устаревший модуль QtOpenGL (классы с префиксом QGL) предоставляет виджет под названием QGLWidget. QOpenGLWidget призван быть современным аналогом. Поэтому, особенно в новых приложениях, рекомендуется использовать QOpenGLWidget.
Хотя API очень похож, есть важное различие между ними: QOpenGLWidget всегда выполняет отрисовку вне экрана, используя объекты фреймбуфера. QGLWidget, с другой стороны, использует родное окно и поверхность. Последнее вызывает проблемы при использовании в сложных пользовательских интерфейсах, так как в зависимости от платформы такие родные дочерние виджеты могут иметь различные ограничения, например, касательно порядков стекирования. QOpenGLWidget избегает этого, не создавая отдельного родного окна.
Благодаря тому, что он поддерживается объектом фреймбуфера, поведение QOpenGLWidget очень похоже на QOpenGLWindow с поведением обновления, установленным в PartialUpdateBlit или PartialUpdateBlend. Это означает, что содержимое сохраняется между вызовами paintGL(), что позволяет выполнять инкрементную отрисовку. С QGLWidget (и, естественно, QOpenGLWindow с поведением обновления по умолчанию) это обычно не так, потому что переключение буферов оставляет задний буфер с неопределённым содержимым.
Примечание: Большинству приложений не нужна инкрементная отрисовка, потому что они будут отрисовывать всё в представлении при каждом вызове отрисовки. В этом случае важно вызвать glClear() как можно раньше в paintGL(). Это помогает мобильным графическим процессорам, использующим архитектуру на основе тайлов, распознать, что буфер тайла не нужно перезагружать содержимым предыдущего фреймбуфера. Пропуск вызова clear может привести к существенному снижению производительности на таких системах.
Примечание: Избегайте вызова winId() на QOpenGLWidget. Эта функция вызывает создание родного окна, что приводит к снижению производительности и возможным проблемам с отрисовкой.
Отличия от QGLWidget
Помимо основного концептуального различия, заключающегося в том, что он поддерживается объектом фреймбуфера, есть ряд небольших внутренних различий между QOpenGLWidget и более старым QGLWidget:
- Состояние OpenGL при вызове paintGL(). QOpenGLWidget устанавливает viewport через glViewport(). Он не выполняет очистку.
- Очистка при начале рисования через QPainter. В отличие от обычных виджетов, QGLWidget по умолчанию принимал значение
trueдля autoFillBackground. Затем он выполнял очистку до фонового цвета палитры каждый раз, когда использовалась QPainter::begin(). QOpenGLWidget не следует этому правилу: autoFillBackground по умолчанию имеет значение false, как и для любого другого виджета. Исключением является использование в качестве viewport для других виджетов, таких как QGraphicsView. В этом случае autoFillBackground будет автоматически установлен в значение true для обеспечения совместимости с viewport на основе QGLWidget.
Многообразная выборка
Для включения многообразной выборки установите количество запрашиваемых выборок в QSurfaceFormat, которое передаётся в setFormat(). На системах, которые её не поддерживают, запрос может быть проигнорирован.
Поддержка многообразной выборки требует поддержки многообразных renderbuffer и фреймбуферных blit. В реализациях OpenGL ES 2.0 маловероятно, что они будут присутствовать. Это означает, что многообразная выборка не будет доступна. С современными версиями OpenGL и OpenGL ES 3.0 и выше это обычно уже не проблема.
Потоки
Поддерживается выполнение отрисовки вне экрана в потоках задач, например, для генерации текстур, которые затем используются в GUI/главном потоке в paintGL(), путём экспонирования QOpenGLContext виджета, чтобы на каждом потоке можно было создать дополнительные контексты, использующие совместное использование с ним.
Рисование непосредственно в фреймбуфере QOpenGLWidget вне GUI/главного потока возможно путём переопределения paintEvent() на пустую функцию. Сродство потока контекста необходимо изменить с помощью QObject::moveToThread(). После этого, makeCurrent() и doneCurrent() будут доступны в потоке задач. Будьте осторожны, чтобы вернуть контекст обратно в GUI/главный поток.
В отличие от QGLWidget, триггер переключения буферов только для QOpenGLWidget невозможен, так как для него нет реальной, отображаемой родной поверхности. Вместо этого управление композицией и переключением буферов на потоке GUI/главного потока выполняется стеком виджетов. Когда поток завершит обновление фреймбуфера, вызовите update() в GUI/главном потоке, чтобы запланировать композицию.
Необходимо проявлять особую осторожность, чтобы избежать использования фреймбуфера, когда GUI/главный поток выполняет композицию. Сигналы aboutToCompose() и frameSwapped() будут генерироваться при начале и завершении композиции. Они генерируются в GUI/главном потоке. Это означает, что с помощью непосредственной связи aboutToCompose() можно заблокировать GUI/главный поток до тех пор, пока рабочий поток не завершит свою отрисовку. После этого рабочий поток не должен выполнять дальнейшей отрисовки до выдачи сигнала frameSwapped(). Если это неприемлемо, рабочий поток должен реализовать механизм двойного буферирования. Это включает рисование с использованием альтернативного целевого объекта отрисовки, полностью контролируемого потоком, например, дополнительного объекта фреймбуфера, и перерисовку в фреймбуфер QOpenGLWidget в подходящее время.
Совместное использование контекста
Когда несколько QOpenGLWidget добавляются в качестве дочерних элементов к одному верхнему виджету, их контексты будут совместно использоваться. Это не относится к экземплярам QOpenGLWidget, которые принадлежат разным окнам.
Это означает, что все QOpenGLWidget в одном окне могут получать доступ к общим ресурсам друг друга, таким как текстуры, и нет необходимости в дополнительном глобальном контексте совместного использования, как это было с QGLWidget.
Чтобы установить совместное использование между экземплярами QOpenGLWidget, относящимися к разным окнам, установите атрибут приложения Qt::AA_ShareOpenGLContexts перед созданием QApplication. Это вызовет совместное использование между всеми экземплярами QOpenGLWidget без дополнительных шагов.
END_OF_DOCUMENT_MARKERСоздание дополнительных экземпляров QOpenGLContext, которые совместно используют ресурсы, такие как текстуры, с контекстом QOpenGLWidget, также возможно. Просто передайте указатель, возвращённый из context(), в QOpenGLContext::setShareContext() перед вызовом QOpenGLContext::create(). Полученный контекст также может быть использован в другом потоке, что позволит выполнять генерацию текстур и асинхронные загрузки текстур в потоках.
Обратите внимание, что QOpenGLWidget ожидает стандартной реализации совместного использования ресурсов, когда речь идёт об основных графических драйверах. Например, некоторые драйверы, в частности для мобильных и встроенных устройств, имеют проблемы с настройкой совместного использования между существующим контекстом и другими, созданными позже. Другие драйверы могут вести себя непредсказуемо при попытке использовать общие ресурсы между различными потоками.
Инициализация и очистка ресурсов
Контекст OpenGL, связанный с QOpenGLWidget, гарантированно является текущим всякий раз, когда вызываются 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 должны быть повторно инициализированы. В связи с этим единственный вариант для надлежащей очистки – подключение к сигналу о уничтожении контекста aboutToBeDestroyed(). Обратите внимание, что контекст может не быть текущим при отправке сигнала. Поэтому рекомендуется вызывать makeCurrent() в подключённом слоте. Кроме того, те же шаги очистки должны выполняться из деструктора производного класса, так как слот, подключённый к сигналу, не будет вызван при уничтожении виджета.
Примечание: Если установлен Qt::AA_ShareOpenGLContexts, контекст виджета никогда не меняется, даже при перерождении, так как текстура, связанная с виджетом, гарантированно доступна и из контекста нового главного окна.
Надлежащая очистка особенно важна из-за совместного использования контекстов. Несмотря на то, что контекст, связанный с каждым QOpenGLWidget, уничтожается вместе с QOpenGLWidget, общие ресурсы в этом контексте, такие как текстуры, останутся действительными до тех пор, пока не будет уничтожено главное окно, в котором жил QOpenGLWidget. Кроме того, такие настройки, как Qt::AA_ShareOpenGLContexts и некоторые модули Qt, могут привести к более широкому охвату совместного использования контекстов, потенциально сохраняя ресурсы до конца работы приложения. Поэтому наиболее безопасным и надёжным всегда остаётся явная очистка всех ресурсов и обёртки ресурсов, используемых в QOpenGLWidget.
Ограничения
Размещение других виджетов под 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 в окно включает OpenGL-композитинг для всего окна. В некоторых особых случаях это может быть нежелательно, и требуется старое поведение QGLWidget со отдельным родственным системным окном. Приложения для настольных компьютеров, понимающие ограничения этого подхода (например, при перекрытиях, прозрачности, прокрутке и областях MDI), могут использовать QOpenGLWindow с QWidget::createWindowContainer(). Это современная альтернатива QGLWidget и быстрее, чем QOpenGLWidget, из-за отсутствия дополнительного шага композиции. Настоятельно рекомендуется ограничивать использование этого подхода случаями, когда нет другого выбора. Обратите внимание, что этот вариант не подходит для большинства встроенных и мобильных платформ, и известно, что он имеет проблемы на определённых настольных платформах (например, macOS). Стабильное и кроссплатформенное решение – всегда QOpenGLWidget.
OpenGL является товарным знаком Silicon Graphics, Inc. в Соединённых Штатах и других странах.
См. также QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts и UpdateBehavior.
Документация по типам-членам
enum QOpenGLWidget::UpdateBehavior
Этот перечисление описывает семантику обновления QOpenGLWidget.
| Постоянная | Значение | Описание |
|---|---|---|
QOpenGLWidget::NoPartialUpdate |
0 |
QOpenGLWidget отбросит содержимое буфера цвета и вспомогательных буферов после отрисовки QOpenGLWidget на экран. Это то же поведение, которое можно ожидать, вызвав QOpenGLContext::swapBuffers с аргументом по умолчанию QWindow с включённым OpenGL. NoPartialUpdate может иметь некоторые преимущества в производительности на некоторых архитектурах оборудования, распространённых в мобильных и встроенных системах, когда используется фреймбуфер в качестве целевого объекта отрисовки. Фреймбуфер недействителен между кадрами с помощью glDiscardFramebufferEXT, если поддерживается, или glClear. Подробнее см. документацию к EXT_discard_framebuffer: https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt |
QOpenGLWidget::PartialUpdate |
1 |
Буферы цвета и вспомогательные буферы фреймбуфера не делаются недействительными между кадрами. |
Этот перечисление был добавлен или изменён в Qt 5.5.
См. также updateBehavior() и setUpdateBehavior().
Документация функций-членов
QOpenGLWidget::QOpenGLWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags())
Создаёт виджет, являющийся дочерним элементом parent, с флагами виджета, установленными в f.
QOpenGLWidget::~QOpenGLWidget()
Уничтожает экземпляр QOpenGLWidget, освобождая его ресурсы.
Контекст QOpenGLWidget делается текущим в деструкторе, позволяя безопасно уничтожить любой дочерний объект, которому может потребоваться освободить ресурсы OpenGL, принадлежащие контексту, предоставляемому этим виджетом.
Предупреждение: если у вас есть объекты, оборачивающие ресурсы OpenGL (такие как QOpenGLBuffer, QOpenGLShaderProgram и т. д.) в качестве членов подкласса OpenGLWidget, вам может потребоваться добавить вызов makeCurrent() в деструкторе этого подкласса тоже. Из-за правил уничтожения объектов C++, эти объекты будут уничтожены до вызова этой функции (но после того, как выполнится деструктор подкласса), поэтому установка текущего контекста OpenGL в этой функции происходит слишком поздно для их безопасного удаления.
См. также makeCurrent.
[signal] void QOpenGLWidget::aboutToCompose()
Этот сигнал испускается, когда верхнеуровневое окно виджета собирается начать композицию текстур своих дочерних элементов QOpenGLWidget и других виджетов.
[signal] void QOpenGLWidget::aboutToResize()
Этот сигнал испускается, когда размер виджета изменяется, и поэтому объект фреймбуфера собирается пересоздать.
QOpenGLContext *QOpenGLWidget::context() const
Возвращает QOpenGLContext, используемый этим виджетом, или 0, если он ещё не инициализирован.
Примечание: контекст и объект фреймбуфера, используемые виджетом, изменяются при изменении родителя виджета с помощью setParent().
См. также QOpenGLContext::setShareContext() и defaultFramebufferObject().
GLuint QOpenGLWidget::defaultFramebufferObject() const
Возвращает дескриптор объекта фреймбуфера или 0, если он ещё не инициализирован.
Примечание: объект фреймбуфера принадлежит контексту, возвращаемому context(), и может быть недоступен из других контекстов.
Примечание: контекст и объект фреймбуфера, используемые виджетом, изменяются при изменении родителя виджета с помощью setParent(). Кроме того, объект фреймбуфера изменяется при каждом изменении размера.
См. также context().
void QOpenGLWidget::doneCurrent()
Освобождает контекст.
В большинстве случаев вызывать эту функцию не нужно, так как виджет позаботится о корректном связывании и освобождении контекста при вызове paintGL().
QSurfaceFormat QOpenGLWidget::format() const
Возвращает контекст и формат поверхности, используемые этим виджетом и его верхнеуровневым окном.
После создания виджета и его верхнего уровня, изменения размера и отображения, эта функция вернёт фактический формат контекста. Это может отличаться от запрошенного формата, если платформа не смогла выполнить запрос. Также возможно получить большие размеры буфера цвета, чем запрошено.
Когда окно виджета и связанные ресурсы OpenGL ещё не инициализированы, возвращаемое значение — формат, установленный с помощью setFormat().
См. также setFormat() и context().
[signal] void QOpenGLWidget::frameSwapped()
Этот сигнал испускается после того, как верхнеуровневое окно виджета завершило композицию и вернулось из потенциально блокирующего вызова QOpenGLContext::swapBuffers().
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().
[virtual protected] void QOpenGLWidget::paintEvent(QPaintEvent *e)
Переопределена из QWidget::paintEvent().
Обрабатывает события рисования.
Вызов QWidget::update() приведёт к отправке события рисования e и, следовательно, вызову этой функции. (Примечание: это асинхронно и произойдёт в какой-то момент после возвращения из update()). Эта функция затем, после некоторой подготовки, вызовет виртуальную paintGL() для обновления содержимого фреймбуфера QOpenGLWidget. Затем верхнеуровневое окно виджета объединит текстуру фреймбуфера со всем остальным окном.
[virtual protected] void QOpenGLWidget::paintGL()
Эта виртуальная функция вызывается всякий раз, когда виджету нужно выполнить рисование. Переопределите её в подклассе.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове этой функции.
Перед вызовом этой функции контекст и фреймбуфер привязываются, а область просмотра устанавливается с помощью вызова glViewport(). Никакое другое состояние не устанавливается, и никакое очищение или рисование не выполняется фреймворком.
См. также initializeGL() и resizeGL().
[virtual protected] void QOpenGLWidget::resizeEvent(QResizeEvent *e)
Переопределена из QWidget::resizeEvent().
Обрабатывает события изменения размера, переданные в параметре события e. Вызывает виртуальную функцию resizeGL().
Примечание: Избегайте переопределения этой функции в производных классах. Если это невозможно, убедитесь, что реализация QOpenGLWidget также вызывается. В противном случае подлежащий фреймбуфер и связанные ресурсы не будут должным образом изменены по размеру и приведут к некорректному рендерингу.
[virtual protected] void QOpenGLWidget::resizeGL(int w, int h)
Эта виртуальная функция вызывается всякий раз, когда размер виджета изменяется. Переопределите её в подклассе. Новый размер передаётся в w и h.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове этой функции. Кроме того, фреймбуфер также привязан.
См. также initializeGL() и paintGL().
[signal] void QOpenGLWidget::resized()
Этот сигнал испускается сразу после того, как объект фреймбуфера был пересоздан из-за изменения размера виджета.
void QOpenGLWidget::setFormat(const QSurfaceFormat &format)
Устанавливает запрошенный формат поверхности format.
Если формат не установлен явно с помощью этой функции, будет использован формат, возвращаемый QSurfaceFormat::defaultFormat(). Это означает, что при наличии нескольких виджетов OpenGL отдельные вызовы этой функции можно заменить одним вызовом QSurfaceFormat::setDefaultFormat() перед созданием первого виджета.
Примечание: Запрос альфа-буфера с помощью этой функции не приведет к желаемому результату, если цель — сделать другие виджеты ниже видимыми. Вместо этого используйте Qt::WA_AlwaysStackOnTop, чтобы включить полупрозрачные экземпляры QOpenGLWidget с другими виджетами, видимыми под ними. Однако имейте в виду, что это нарушает порядок стекирования, поэтому другие виджеты больше не смогут располагаться поверх QOpenGLWidget.
См. также format(), Qt::WA_AlwaysStackOnTop и QSurfaceFormat::setDefaultFormat().
void QOpenGLWidget::setUpdateBehavior(UpdateBehavior updateBehavior)
Устанавливает поведение обновления этого виджета на updateBehavior.
Эта функция была добавлена в Qt 5.5.
См. также updateBehavior().
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/archives/qt-5.6/qopenglwidget.html