Класс 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() — настраивает viewport, проекцию OpenGL и т. д. Вызывается всякий раз, когда виджет был изменён по размеру (а также при его первом отображении, поскольку все недавно созданные виджеты автоматически получают событие изменения размера).
- initializeGL() — настраивает ресурсы и состояние OpenGL. Вызывается один раз перед первым вызовом resizeGL() или paintGL().
Если вам нужно инициировать перерисовку из мест, отличных от paintGL() (типичный пример — при использовании таймеров для анимации сцен), вы должны вызвать функцию update() виджета, чтобы запланировать обновление.
Контекст OpenGL вашего виджета становится текущим при вызове paintGL(), resizeGL() или initializeGL(). Если вам нужно вызвать стандартные функции API OpenGL из других мест (например, в конструкторе виджета или в собственных функциях рисования), вы должны сначала вызвать makeCurrent().
Весь рендеринг происходит в объекте framebuffer OpenGL. makeCurrent() гарантирует, что он привязан к контексту. Имейте это в виду при создании и привязке дополнительных объектов framebuffer в коде рендеринга в paintGL(). Никогда не перепривязывайте framebuffer с ID 0. Вместо этого используйте defaultFramebufferObject(), чтобы получить ID, который нужно привязать.
QOpenGLWidget позволяет использовать различные версии и профили OpenGL, если платформа их поддерживает. Просто задайте требуемый формат с помощью setFormat(). Однако имейте в виду, что наличие нескольких экземпляров QOpenGLWidget в одном окне требует, чтобы все они использовали один и тот же формат или, по крайней мере, форматы, которые не делают контексты несовместимыми для совместного использования. Для решения этой проблемы предпочитайте использовать QSurfaceFormat::setDefaultFormat() вместо setFormat().
Примечание: Вызов QSurfaceFormat::setDefaultFormat() до создания экземпляра QApplication обязателен на некоторых платформах (например, macOS), когда запрашивается контекст OpenGL с ядром профиля. Это для обеспечения функциональности совместного использования ресурсов между контекстами, поскольку все внутренние контексты создаются с использованием правильной версии и профиля.
Техники рисования
Как описано выше, подклассируйте 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, не будет видно. Это может стать особенно актуальным в средах удалённого отображения (например, с Xvnc) на Linux/X11 при использовании глубины цвета ниже 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 с аргументом по умолчанию QWindow, для которого включён OpenGL. НетPartialUpdate может иметь некоторые преимущества в производительности на определённых аппаратных архитектурах, распространённых в мобильных и встроенных системах, когда в качестве целевого объекта рендеринга используется объект фреймбуфера. Объект фреймбуфера делает недействительным между кадрами 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 = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
Создаёт виджет, который является дочерним элементом parent, с флагами виджета, установленными в f.
[signal] void QOpenGLWidget::aboutToCompose()
Этот сигнал генерируется, когда окно верхнего уровня виджета начинает композицию текстур его дочерних элементов QOpenGLWidget и других виджетов.
[signal] void QOpenGLWidget::aboutToResize()
Этот сигнал генерируется, когда изменяется размер виджета, и поэтому объект фреймбуфера будет пересоздан.
[signal] void QOpenGLWidget::frameSwapped()
Этот сигнал генерируется после того, как окно верхнего уровня виджета завершит композицию и вернётся из потенциально блокирующего вызова QOpenGLContext::swapBuffers().
[signal] void QOpenGLWidget::resized()
Этот сигнал генерируется сразу после пересоздания объекта фреймбуфера из-за изменения размера виджета.
[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-ресурсы, такие как контекст, успешно инициализированы. Обратите внимание, что возвращаемое значение всегда false до отображения виджета.
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.1/qopenglwidget.html