QOpenGLWidget Class
QOpenGLWidget 클래스는 OpenGL 그래픽을 렌더링하기 위한 위젯입니다. 더 보기...
헤더: | #include <QOpenGLWidget> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS OpenGLWidgets) target_link_libraries(mytarget PRIVATE Qt6::OpenGLWidgets) |
qmake: | QT += openglwidgets |
상속합니다: | QWidget |
공용 타입
(since 6.5) enum | TargetBuffer { LeftBuffer, RightBuffer } |
enum | UpdateBehavior { NoPartialUpdate, PartialUpdate } |
공용 함수
QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) | |
virtual | ~QOpenGLWidget() |
QOpenGLContext * | context() const |
(since 6.5) QOpenGLWidget::TargetBuffer | currentTargetBuffer() const |
GLuint | defaultFramebufferObject() const |
(since 6.5) GLuint | defaultFramebufferObject(QOpenGLWidget::TargetBuffer targetBuffer) const |
void | doneCurrent() |
QSurfaceFormat | format() const |
QImage | grabFramebuffer() |
(since 6.5) QImage | grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer) |
bool | isValid() const |
void | makeCurrent() |
(since 6.5) void | makeCurrent(QOpenGLWidget::TargetBuffer targetBuffer) |
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() |
보호된 함수
virtual void | initializeGL() |
virtual void | paintGL() |
virtual void | resizeGL(int w, int h) |
재구현된 보호 함수
virtual bool | event(QEvent *e) override |
virtual int | metric(QPaintDevice::PaintDeviceMetric metric) const override |
virtual QPaintEngine * | paintEngine() const override |
virtual void | paintEvent(QPaintEvent *e) override |
virtual QPaintDevice * | redirected(QPoint *p) const override |
virtual void | resizeEvent(QResizeEvent *e) override |
상세 설명
QOpenGLWidget은 Qt 어플리케이션에 통합된 OpenGL 그래픽을 표시하는 기능을 제공합니다. 사용법은 매우 간단합니다: 클래스를 상속하고 다른 QWidget 처럼 서브클래스를 사용하면 됩니다(단, QPainter 과 표준 OpenGL 렌더링 명령어 중 하나를 선택할 수 있습니다).
QOpenGLWidget은 서브클래스에서 재구현하여 일반적인 OpenGL 작업을 수행할 수 있는 세 가지 편리한 가상 함수를 제공합니다:
- paintGL() - OpenGL 장면을 렌더링합니다. 위젯을 업데이트해야 할 때마다 호출됩니다.
- resizeGL() - OpenGL 뷰포트, 투영 등을 설정합니다. 위젯의 크기가 조정될 때마다 호출됩니다(새로 생성된 모든 위젯은 자동으로 크기 조정 이벤트를 받기 때문에 처음 표시될 때에도 호출됩니다).
- initializeGL() - OpenGL 리소스와 상태를 설정합니다. resizeGL () 또는 paintGL()가 처음 호출되기 전에 한 번 호출됩니다.
paintGL() 이외의 위치에서 다시 그리기를 트리거해야 하는 경우(일반적인 예로 timers 을 사용하여 장면에 애니메이션을 적용하는 경우) 위젯의 update() 함수를 호출하여 업데이트를 예약해야 합니다.
paintGL(), resizeGL() 또는 initializeGL()를 호출하면 위젯의 OpenGL 렌더링 컨텍스트가 최신 상태로 유지됩니다. 위젯의 생성자나 자체 페인트 함수 등 다른 위치에서 표준 OpenGL API 함수를 호출해야 하는 경우 makeCurrent()를 먼저 호출해야 합니다.
모든 렌더링은 OpenGL 프레임버퍼 객체에서 이루어집니다. makeCurrent()를 호출하여 컨텍스트에 바인딩되어 있는지 확인합니다. paintGL ()의 렌더링 코드에서 추가 프레임버퍼 객체를 생성하고 바인딩할 때 이 점을 염두에 두세요. 프레임버퍼를 ID 0으로 다시 바인딩하지 마세요. 대신 defaultFramebufferObject()를 호출하여 바인딩해야 하는 ID를 가져옵니다.
플랫폼에서 지원하는 경우 QOpenGLWidget을 사용하면 다양한 OpenGL 버전과 프로필을 사용할 수 있습니다. setFormat ()를 통해 요청된 형식을 설정하기만 하면 됩니다. 그러나 동일한 창에 여러 개의 QOpenGLWidget 인스턴스를 사용하려면 모두 동일한 형식 또는 적어도 컨텍스트를 공유할 수 없는 형식을 사용해야 한다는 점에 유의하세요. 이 문제를 해결하려면 setFormat() 대신 QSurfaceFormat::setDefaultFormat()를 사용하는 것이 좋습니다.
참고: 일부 플랫폼(예: macOS)에서는 OpenGL 코어 프로필 컨텍스트가 요청될 때 QApplication 인스턴스를 구성하기 전에 QSurfaceFormat::setDefaultFormat()를 호출해야 합니다. 이는 모든 내부 컨텍스트가 올바른 버전과 프로필을 사용하여 생성되므로 컨텍스트 간 리소스 공유가 계속 작동하도록 하기 위한 것입니다.
페인팅 기법
위에서 설명한 대로 QOpenGLWidget 서브클래스를 다음과 같은 방식으로 순수 3D 콘텐츠를 렌더링합니다:
- initializeGL() 및 resizeGL() 함수를 다시 구현하여 OpenGL 상태를 설정하고 원근 변환을 제공합니다.
- paintGL() 함수를 다시 구현하여 OpenGL 함수만 호출하여 3D 장면을 그립니다.
QPainter 을 사용하여 QOpenGLWidget 서브클래스에 2D 그래픽을 그릴 수도 있습니다:
- 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을 대상으로 하는 경우)을 사용하는 것이 좋습니다. 이렇게 하면 애플리케이션이 GL 구현에 직접 연결되지 않아 직접 함수 호출이 불가능한 동적 OpenGL 구현 로딩을 수행하는 경우를 포함한 모든 Qt 빌드 구성에서 애플리케이션이 올바르게 작동합니다.
paintGL()에서 현재 컨텍스트는 항상 QOpenGLContext::currentContext()을 호출하여 액세스할 수 있습니다. 이 컨텍스트에서 이미 초기화되어 바로 사용할 수 있는 QOpenGLFunctions 인스턴스는 QOpenGLContext::functions()을 호출하여 검색할 수 있습니다. 모든 GL 호출에 접두사를 붙이는 대신 QOpenGLFunctions 에서 상속하여 initializeGL()에서 QOpenGLFunctions::initializeOpenGLFunctions()을 호출하는 방법도 있습니다.
OpenGL 헤더의 경우, 대부분의 경우 GL.h와 같은 헤더를 직접 포함할 필요가 없습니다. OpenGL 관련 Qt 헤더는 시스템에 적합한 헤더를 포함하는 qopengl.h를 포함할 것입니다. 이것은 사용 가능한 가장 높은 버전인 OpenGL ES 3.x 또는 2.0 헤더일 수도 있고, 시스템에서 제공하는 gl.h일 수도 있습니다. 또한 확장 헤더의 복사본(일부 시스템에서는 glext.h라고 함)이 OpenGL 및 OpenGL ES용 Qt의 일부로 제공됩니다. 이는 가능한 경우 플랫폼에 자동으로 포함됩니다. 즉, ARB, EXT, OES 확장의 상수 및 함수 포인터 typedef를 자동으로 사용할 수 있습니다.
코드 예제
시작하기 위해 가장 간단한 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); ... } };
또는 QOpenGLFunctions 에서 파생하여 모든 OpenGL 호출의 접두사를 피할 수 있습니다:
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
참고: 기본 윈도우 시스템 인터페이스에서 뎁스 및 스텐실 버퍼를 요청하는 것은 애플리케이션에 달려 있습니다. 0이 아닌 뎁스 버퍼 크기를 요청하지 않으면 뎁스 버퍼를 사용할 수 있다는 보장이 없으며, 그 결과 뎁스 테스트 관련 OpenGL 작업이 예상대로 작동하지 않을 수 있습니다. 일반적으로 사용되는 뎁스 및 스텐실 버퍼 크기 요청은 각각 24와 8입니다.
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(); }
멀티샘플링
멀티샘플링을 사용하려면 setFormat()에 전달되는 QSurfaceFormat 에서 요청된 샘플 수를 설정합니다. 이를 지원하지 않는 시스템에서는 요청이 무시될 수 있습니다.
멀티샘플링을 지원하려면 멀티샘플링 렌더버퍼와 프레임버퍼 블릿이 지원되어야 합니다. OpenGL ES 2.0 구현에서는 이러한 기능이 없을 가능성이 높습니다. 즉, 멀티샘플링을 사용할 수 없습니다. 최신 OpenGL 버전과 OpenGL ES 3.0 이상에서는 일반적으로 더 이상 문제가 되지 않습니다.
스레딩
예를 들어 작업자 스레드에서 오프스크린 렌더링을 수행하여 텍스처를 생성한 다음 paintGL()의 GUI/메인 스레드에서 사용하는 경우 위젯의 QOpenGLContext 을 노출하여 각 스레드에서 공유되는 추가 컨텍스트를 만들 수 있도록 지원합니다.
아무 작업도 하지 않고 paintEvent()를 다시 구현하면 GUI/메인 스레드 외부에서 QOpenGLWidget의 프레임버퍼에 직접 그리는 것이 가능합니다. 컨텍스트의 스레드 선호도는 QObject::moveToThread()를 통해 변경해야 합니다. 그 후에는 makeCurrent() 및 doneCurrent()를 작업자 스레드에서 사용할 수 있습니다. 나중에 컨텍스트를 GUI/메인 스레드로 다시 이동하도록 주의하세요.
실제 화면상의 네이티브 표면이 없기 때문에 QOpenGLWidget에 대해서만 버퍼 스왑을 트리거하는 것은 불가능합니다. 위젯 스택에서 구성 및 버퍼 스왑을 관리하는 것은 위젯 스레드에 달려 있습니다. 스레드에서 프레임버퍼 업데이트가 완료되면 GUI/메인 스레드에서 update()를 호출하여 컴포지션을 예약합니다.
GUI/메인 스레드가 합성을 수행할 때 프레임버퍼를 사용하지 않도록 각별히 주의해야 합니다. aboutToCompose () 및 frameSwapped() 신호는 컴포지션이 시작되고 끝날 때 발생합니다. 이 신호는 GUI/메인 스레드에서 발신됩니다. 즉, 직접 연결 aboutToCompose()을 사용하면 작업자 스레드가 렌더링을 완료할 때까지 GUI/메인 스레드를 차단할 수 있습니다. 그 후 작업자 스레드는 frameSwapped() 신호가 전송될 때까지 더 이상 렌더링을 수행하지 않아야 합니다. 이것이 허용되지 않는 경우 작업자 스레드는 이중 버퍼링 메커니즘을 구현해야 합니다. 여기에는 스레드가 완전히 제어하는 대체 렌더링 대상(예: 추가 프레임버퍼 객체)을 사용하여 렌더링하고 적절한 시점에 QOpenGLWidget의 프레임버퍼로 블리트하는 것이 포함됩니다.
컨텍스트 공유
동일한 최상위 위젯에 여러 QOpenGL위젯을 자식으로 추가하면 해당 컨텍스트가 서로 공유됩니다. 이는 다른 창에 속한 QOpenGLWidget 인스턴스에는 적용되지 않습니다.
즉, 같은 창에 있는 모든 QOpenGL위젯은 텍스처와 같은 서로의 공유 가능한 리소스에 액세스할 수 있으며 별도의 "글로벌 공유" 컨텍스트가 필요하지 않습니다.
서로 다른 창에 속한 QOpenGLWidget 인스턴스 간에 공유를 설정하려면 QApplication 을 인스턴스화하기 전에 Qt::AA_ShareOpenGLContexts 애플리케이션 속성을 설정합니다. 이렇게 하면 추가 단계 없이 모든 QOpenGLWidget 인스턴스 간에 공유가 트리거됩니다.
텍스처와 같은 리소스를 QOpenGLWidget의 컨텍스트와 공유하는 QOpenGLContext 인스턴스를 추가로 생성하는 것도 가능합니다. QOpenGLContext::create ()를 호출하기 전에 context()에서 반환된 포인터를 QOpenGLContext::setShareContext()로 전달하기만 하면 됩니다. 결과 컨텍스트는 다른 스레드에서도 사용할 수 있으므로 텍스처의 스레드 생성 및 비동기 텍스처 업로드가 가능합니다.
QOpenGLWidget은 기본 그래픽 드라이버와 관련하여 표준에 부합하는 리소스 공유 구현을 기대합니다. 예를 들어 일부 드라이버, 특히 모바일 및 임베디드 하드웨어용 드라이버는 기존 컨텍스트와 나중에 생성되는 다른 컨텍스트 간의 공유 설정에 문제가 있습니다. 일부 다른 드라이버는 다른 스레드 간에 공유 리소스를 활용하려고 할 때 예기치 않은 방식으로 작동할 수 있습니다.
리소스 초기화 및 정리
initializeGL() 및 paintGL()이 호출될 때마다 QOpenGLWidget의 연결된 OpenGL 컨텍스트는 최신 상태로 유지됩니다. initializeGL ()가 호출되기 전에 OpenGL 리소스를 만들려고 시도하지 마세요. 예를 들어 셰이더 컴파일, 버텍스 버퍼 오브젝트 초기화 또는 텍스처 데이터 업로드 시도는 서브클래스의 생성자에서 수행하면 실패합니다. 이러한 작업은 initializeGL()로 연기해야 합니다. QOpenGLBuffer 또는 QOpenGLVertexArrayObject 과 같은 Qt의 OpenGL 헬퍼 클래스 중 일부는 컨텍스트 없이 인스턴스화할 수 있지만 모든 초기화는 create() 또는 이와 유사한 호출이 있을 때까지 지연됩니다. 즉, QOpenGLWidget 서브클래스에서 일반(포인터가 아닌) 멤버 변수로 사용할 수 있지만 create() 또는 유사한 함수는 initializeGL()에서만 호출할 수 있습니다. 하지만 모든 클래스가 이렇게 설계된 것은 아니라는 점에 유의하세요. 확실하지 않은 경우 멤버 변수를 포인터로 만들고 initializeGL() 및 소멸자에서 각각 인스턴스를 동적으로 생성 및 소멸하세요.
리소스를 해제하려면 컨텍스트도 최신 상태여야 합니다. 따라서 이러한 정리를 수행하는 소멸자는 OpenGL 리소스나 래퍼를 삭제하기 전에 makeCurrent()를 호출해야 합니다. 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(...); ... }
이는 대부분의 경우에 적합하지만 일반적인 솔루션으로 완전히 이상적이지는 않습니다. 위젯이 완전히 다른 최상위 창에 위치하도록 부모를 다시 지정하는 경우에는 QOpenGLContext 의 aboutToBeDestroyed() 신호에 연결하여 OpenGL 컨텍스트가 해제될 때마다 정리를 수행할 수 있는 방법이 더 필요합니다.
참고: 수명 기간 동안 연결된 최상위 창을 여러 번 변경하는 위젯의 경우 아래 코드 스니펫에 설명된 대로 결합된 정리 방식이 필수적입니다. 위젯 또는 위젯의 부모가 부모를 변경하여 최상위 창이 달라질 때마다 위젯의 연결된 컨텍스트가 파괴되고 새 컨텍스트가 만들어집니다. 그런 다음 initializeGL()를 호출하여 모든 OpenGL 리소스를 다시 초기화해야 합니다. 따라서 적절한 정리를 수행할 수 있는 유일한 옵션은 컨텍스트의 aboutToBeDestroyed() 신호에 연결하는 것입니다. 신호가 발생했을 때 해당 컨텍스트가 현재 컨텍스트가 아닐 수도 있습니다. 따라서 연결된 슬롯에서 makeCurrent()를 호출하는 것이 좋습니다. 또한 위젯이 소멸될 때 신호에 연결된 슬롯이나 람다가 호출되지 않을 수 있으므로 파생 클래스의 소멸자에서도 동일한 정리 단계를 수행해야 합니다.
MyGLWidget::~MyGLWidget() { cleanup(); } void MyGLWidget::initializeGL() { ... connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup); } void MyGLWidget::cleanup() { makeCurrent(); delete m_texture; m_texture = 0; ... doneCurrent(); disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup); }
참고: Qt::AA_ShareOpenGLContexts 가 설정되면 위젯의 컨텍스트는 변경되지 않으며, 위젯의 연관된 텍스처는 새 최상위 레벨의 컨텍스트에서도 액세스할 수 있으므로 부모를 다시 지정해도 위젯의 컨텍스트는 변경되지 않습니다. 따라서 이 플래그가 설정된 경우 컨텍스트의 aboutToBeDestroyed() 신호에 따라 동작하는 것은 필수가 아닙니다.
컨텍스트 공유로 인해 적절한 정리가 특히 중요합니다. 각 QOpenGL위젯의 연관된 컨텍스트가 QOpenGL위젯과 함께 소멸되더라도 텍스처와 같은 해당 컨텍스트의 공유 가능한 리소스는 QOpenGL위젯이 있던 최상위 창이 소멸될 때까지 유효하게 유지됩니다. 또한 Qt::AA_ShareOpenGLContexts 및 일부 Qt 모듈과 같은 설정은 컨텍스트 공유 범위를 훨씬 더 넓게 트리거하여 해당 리소스가 애플리케이션의 전체 수명 동안 유지될 수 있습니다. 따라서 가장 안전하고 강력한 방법은 항상 QOpenGLWidget에서 사용되는 모든 리소스와 리소스 래퍼에 대해 명시적인 정리를 수행하는 것입니다.
제한 사항 및 기타 고려 사항
다른 위젯을 아래에 배치하고 QOpenGLWidget을 투명하게 만들면 예상한 결과를 얻을 수 없습니다: 그 아래의 위젯은 보이지 않습니다. 이는 실제로 QOpenGLWidget이 다른 모든 일반 위젯보다 먼저 그려지기 때문에 시스루 타입의 솔루션은 불가능하기 때문입니다. QOpenGLWidget 위에 위젯을 배치하는 것과 같은 다른 유형의 레이아웃은 예상대로 작동합니다.
꼭 필요한 경우 QOpenGLWidget에 Qt::WA_AlwaysStackOnTop 속성을 설정하여 이 제한을 극복할 수 있습니다. 그러나 이렇게 하면 스태킹 순서가 깨지는데, 예를 들어 다른 위젯을 QOpenGLWidget 위에 놓을 수 없으므로 다른 위젯이 아래에 보이는 반투명 QOpenGLWidget이 필요한 경우에만 사용해야 한다는 점에 유의하세요.
아래에 다른 위젯이 없고 반투명 창을 만들려는 의도가 있는 경우에는 적용되지 않는다는 점에 유의하세요. 이 경우 최상위 창에 Qt::WA_TranslucentBackground 을 설정하는 기존 방식으로 충분합니다. QOpenGLWidget에서 투명 영역만 원하는 경우 Qt::WA_TranslucentBackground 을 활성화한 후 Qt::WA_NoSystemBackground 을 false
으로 다시 설정해야 합니다. 또한 시스템에 따라 setFormat()를 통해 QOpenGLWidget의 컨텍스트에 대한 알파 채널을 요청해야 할 수도 있습니다.
QOpenGLWidget은 QOpenGLWindow 과 같이 여러 업데이트 동작을 지원합니다. 보존 모드에서는 이전 paintGL() 호출에서 렌더링된 콘텐츠를 다음 호출에서 사용할 수 있으므로 증분 렌더링이 가능합니다. 비보존 모드에서는 콘텐츠가 손실되고 paintGL() 구현은 뷰의 모든 것을 다시 그려야 합니다.
Qt 5.5 이전에는 paintGL() 호출 사이에 렌더링된 내용을 보존하는 것이 QOpenGLWidget의 기본 동작이었습니다. Qt 5.5부터는 기본 동작이 보존되지 않는데, 이는 더 나은 성능을 제공하고 대부분의 애플리케이션에서 이전 콘텐츠가 필요하지 않기 때문입니다. 이는 OpenGL 기반 QWindow 의 의미와 유사하며 각 프레임마다 색상 및 보조 버퍼가 무효화된다는 점에서 QOpenGLWindow 의 기본 동작과도 일치합니다. 보존된 동작을 복원하려면 PartialUpdate
과 함께 setUpdateBehavior()를 호출하세요.
참고: 위젯 계층 구조에 위젯을 동적으로 추가할 때(예: 해당 최상위 위젯이 이미 화면에 표시되어 있는 위젯에 새 QOpenGL위젯을 부모로 삼는 경우), QOpenGL위젯이 해당 창 내에서 첫 번째인 경우 연결된 기본 창이 암시적으로 파괴되고 다시 생성될 수 있습니다. 이는 창 유형이 RasterSurface 에서 OpenGLSurface 로 변경되어 플랫폼에 따라 영향을 미치기 때문입니다. 이 동작은 Qt 6.4에 새로 추가되었습니다.
위젯 계층 구조에 QOpenGLWidget이 추가되면 최상위 창의 콘텐츠가 OpenGL 기반 렌더링을 통해 플러시됩니다. QOpenGLWidget 이외의 위젯은 소프트웨어 기반 페인터를 사용하여 콘텐츠를 계속 그리지만 최종 구성은 3D API를 통해 이루어집니다.
참고: 다른 QWidget 기반 콘텐츠와의 컴포지션 작동 방식 때문에 QOpenGLWidget을 표시하려면 연결된 최상위 창의 백킹 스토어에 알파 채널이 필요합니다. 알파 채널이 없으면 QOpenGLWidget이 렌더링한 콘텐츠가 표시되지 않습니다. 이는 특히 24보다 낮은 색 농도를 사용하는 원격 디스플레이 설정(예: Xvnc 사용)에서 Linux/X11과 관련이 있을 수 있습니다. 예를 들어 색심도가 16이면 일반적으로 QImage::Format_RGB16 (RGB565) 형식의 백킹 스토어 이미지를 사용하는 것과 매핑되므로 알파 채널을 위한 공간이 남지 않습니다. 따라서 QOpenGL위젯의 콘텐츠가 창의 다른 위젯과 올바르게 합성되는 데 문제가 있는 경우 서버(예: vncserver)가 16이 아닌 24 또는 32비트 심도로 구성되었는지 확인하세요.
대안
QOpenGL위젯을 창에 추가하면 전체 창에 대해 OpenGL 기반 합성이 켜집니다. 일부 특수한 경우에는 이것이 이상적이지 않을 수 있으며, 별도의 기본 자식 창을 사용하는 이전 QGLWidget 스타일 동작이 바람직합니다. 이 접근 방식의 한계를 이해하는 데스크톱 애플리케이션(예: 오버랩, 투명도, 스크롤 보기 및 MDI 영역)은 QWidget::createWindowContainer()와 함께 QOpenGLWindow 을 사용할 수 있습니다. 이는 QGLWidget의 최신 대안이며 추가 구성 단계가 없기 때문에 QOpenGLWidget보다 빠릅니다. 이 방법은 다른 선택의 여지가 없는 경우에만 사용하는 것이 좋습니다. 이 옵션은 대부분의 임베디드 및 모바일 플랫폼에는 적합하지 않으며, 특정 데스크톱 플랫폼(예: macOS)에서도 문제가 있는 것으로 알려져 있습니다. 안정적인 크로스 플랫폼 솔루션은 항상 QOpenGLWidget입니다.
스테레오스코픽 렌더링
6.5부터 QOpenGLWidget은 스테레오스코픽 렌더링을 지원합니다. 이를 활성화하려면 창을 만들기 전에 QSurfaceFormat::SetDefaultFormat()을 사용하여 전역적으로 QSurfaceFormat::StereoBuffers 플래그를 설정합니다.
참고: 내부적으로 플래그가 처리되는 방식 때문에 setFormat()를 사용하면 반드시 작동하지 않을 수 있습니다.
이렇게 하면 paintGL()가 각 프레임마다 QOpenGLWidget::TargetBuffer 에 대해 한 번씩 두 번 호출됩니다. paintGL ()에서 currentTargetBuffer()을 호출하여 현재 어느 쪽에 그려지고 있는지 쿼리합니다.
참고: 왼쪽 및 오른쪽 색상 버퍼를 보다 세밀하게 제어하려면 QOpenGLWindow + QWidget::createWindowContainer()를 대신 사용하는 것이 좋습니다.
참고: 이 유형의 3D 렌더링에는 그래픽 카드가 스테레오를 지원하도록 설정해야 하는 등 특정 하드웨어 요구 사항이 있습니다.
OpenGL은 미국 및 기타 국가에서 Silicon Graphics, Inc.의 상표입니다.
QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts, UpdateBehavior 을참조하세요 .
멤버 유형 문서
[since 6.5]
enum QOpenGLWidget::TargetBuffer
스테레오스코픽 렌더링이 활성화될 때 사용할 버퍼를 지정하며, QSurfaceFormat::StereoBuffers 을 설정하여 전환할 수 있습니다.
참고: 좌측 버퍼는 항상 기본값이며 스테레오스코픽 렌더링이 비활성화되거나 그래픽 드라이버에서 지원하지 않을 때 폴백 값으로 사용됩니다.
상수 | 값 |
---|---|
QOpenGLWidget::LeftBuffer | 0 |
QOpenGLWidget::RightBuffer | 1 |
이 열거형은 Qt 6.5에 도입되었습니다.
enum QOpenGLWidget::UpdateBehavior
이 열거형은 QOpenGLWidget 의 업데이트 시맨틱을 설명합니다.
Constant | 값 | Description |
---|---|---|
QOpenGLWidget::NoPartialUpdate | 0 | QOpenGLWidget 은 QOpenGLWidget 이 화면에 렌더링된 후 컬러 버퍼와 보조 버퍼의 내용을 삭제합니다. 이는 기본 opengl이 활성화된 QWindow 을 인수로 사용하여 QOpenGLContext::swapBuffers 을 호출할 때 예상할 수 있는 동작과 동일합니다. 프레임버퍼 객체를 렌더링 대상으로 사용하는 경우 모바일 및 임베디드 공간에서 흔히 사용되는 특정 하드웨어 아키텍처에서 NoPartialUpdate가 성능상의 이점을 제공할 수 있습니다. 프레임버퍼 객체는 glInvalidateFramebuffer(지원되는 경우) 또는 폴백으로 glDiscardFramebufferEXT(지원되는 경우) 또는 glClear 호출을 통해 프레임 간에 무효화됩니다. |
QOpenGLWidget::PartialUpdate | 1 | 프레임버퍼 객체의 컬러 버퍼와 보조 버퍼는 프레임 간에 무효화되지 않습니다. |
updateBehavior() 및 setUpdateBehavior()도 참조하십시오 .
멤버 함수 문서
[explicit]
QOpenGLWidget::QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
위젯 플래그가 f 으로 설정된 parent 의 자식인 위젯을 생성합니다.
[virtual noexcept]
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()도 참조하세요 .
[since 6.5]
QOpenGLWidget::TargetBuffer QOpenGLWidget::currentTargetBuffer() const
현재 활성화된 타겟 버퍼를 반환합니다. 기본적으로 왼쪽 버퍼가 사용되며 오른쪽 버퍼는 QSurfaceFormat::StereoBuffers 이 활성화된 경우에만 사용됩니다. 스테레오스코픽 렌더링이 활성화된 경우 paintGL()에서 쿼리하여 현재 어떤 버퍼가 사용 중인지 알 수 있습니다. paintGL()는 각 대상에 대해 한 번씩 두 번 호출됩니다.
이 함수는 Qt 6.5에 도입되었습니다.
paintGL()도 참조하세요 .
GLuint QOpenGLWidget::defaultFramebufferObject() const
프레임버퍼 객체 핸들을 반환하거나 아직 초기화되지 않은 경우 0
을 반환합니다.
참고: 프레임버퍼 객체는 context()에서 반환한 컨텍스트에 속하며 다른 컨텍스트에서는 액세스할 수 없습니다.
참고: setParent()를 통해 위젯의 부모를 변경하면 위젯이 사용하는 컨텍스트와 프레임버퍼 객체가 변경됩니다. 또한 크기를 조정할 때마다 프레임버퍼 객체가 변경됩니다.
context()도 참조하세요 .
[since 6.5]
GLuint QOpenGLWidget::defaultFramebufferObject(QOpenGLWidget::TargetBuffer targetBuffer) const
지정된 대상 버퍼의 프레임버퍼 객체 핸들을 반환하거나 아직 초기화되지 않은 경우 0
을 반환합니다.
이 오버로드를 호출하는 것은 QSurfaceFormat::StereoBuffers 가 하드웨어에서 활성화되고 지원되는 경우에만 의미가 있습니다. 그렇지 않은 경우, 이 메서드는 기본 버퍼를 반환합니다.
참고: 프레임버퍼 객체는 context()가 반환한 컨텍스트에 속하며 다른 컨텍스트에서는 액세스할 수 없습니다. setParent ()를 통해 위젯을 다시 부모로 지정하면 위젯이 사용하는 컨텍스트와 프레임버퍼 객체가 변경됩니다. 또한 프레임버퍼 객체는 크기를 조정할 때마다 변경됩니다.
이 함수는 Qt 6.5에 도입되었습니다.
context()도 참조하세요 .
void QOpenGLWidget::doneCurrent()
컨텍스트를 해제합니다.
paintGL()를 호출할 때 위젯이 컨텍스트가 제대로 바인딩되고 해제되었는지 확인하므로 대부분의 경우 이 함수를 호출할 필요가 없습니다.
[override virtual protected]
bool QOpenGLWidget::event(QEvent *e)
다시 구현합니다: QWidget::event(QEvent * 이벤트).
QSurfaceFormat QOpenGLWidget::format() const
이 위젯과 그 최상위 창에서 사용하는 컨텍스트 및 표면 형식을 반환합니다.
위젯과 해당 최상위 레벨이 모두 생성되고 크기가 조정되어 표시된 후 이 함수는 컨텍스트의 실제 형식을 반환합니다. 플랫폼에서 요청을 이행할 수 없는 경우 요청된 형식과 다를 수 있습니다. 요청된 것보다 더 큰 색상 버퍼 크기를 가져올 수도 있습니다.
위젯의 창과 관련 OpenGL 리소스가 아직 초기화되지 않은 경우 반환 값은 setFormat()를 통해 설정된 형식입니다.
setFormat() 및 context()도 참조하세요 .
[signal]
void QOpenGLWidget::frameSwapped()
이 신호는 위젯의 최상위 창이 구성을 완료하고 잠재적으로 차단할 수 있는 QOpenGLContext::swapBuffers() 호출에서 반환된 후에 발생합니다.
QImage QOpenGLWidget::grabFramebuffer()
프레임버퍼의 32비트 RGB 이미지를 렌더링하고 반환합니다.
참고: 이 함수는 픽셀을 다시 읽어오기 위해 glReadPixels()에 의존하기 때문에 잠재적으로 비용이 많이 드는 작업입니다. 속도가 느려지고 GPU 파이프라인이 지연될 수 있습니다.
[since 6.5]
QImage QOpenGLWidget::grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer)
지정된 대상 버퍼의 프레임버퍼의 32비트 RGB 이미지를 렌더링하고 반환합니다. 이 오버로드는 QSurfaceFormat::StereoBuffers 가 활성화된 경우에만 호출하는 것이 합리적입니다. 스테레오스코픽 렌더링이 비활성화되어 있거나 하드웨어에서 지원하지 않는 경우 올바른 대상 버퍼의 프레임버퍼를 가져오면 기본 이미지가 반환됩니다.
참고: 이 작업은 픽셀을 다시 읽기 위해 glReadPixels()에 의존하기 때문에 잠재적으로 비용이 많이 드는 작업입니다. 속도가 느려지고 GPU 파이프라인이 지연될 수 있습니다.
이 함수는 Qt 6.5에 도입되었습니다.
[virtual protected]
void QOpenGLWidget::initializeGL()
이 가상 함수는 paintGL() 또는 resizeGL()를 처음 호출하기 전에 한 번 호출됩니다. 서브클래스에서 다시 구현합니다.
이 함수는 필요한 OpenGL 리소스를 설정해야 합니다.
이 함수가 호출될 때 이미 설정이 완료되었으므로 makeCurrent()를 호출할 필요가 없습니다. 하지만 이 단계에서는 프레임버퍼를 아직 사용할 수 없으므로 여기에서 드로우 호출을 실행하지 마세요. 대신 paintGL()로 호출을 연기하세요.
paintGL() 및 resizeGL()도 참조하세요 .
bool QOpenGLWidget::isValid() const
위젯과 컨텍스트와 같은 OpenGL 리소스가 성공적으로 초기화되면 참을 반환합니다. 위젯이 표시될 때까지 반환값은 항상 거짓입니다.
void QOpenGLWidget::makeCurrent()
해당 컨텍스트를 최신으로 만들고 해당 컨텍스트에서 프레임버퍼 객체를 바인딩하여 이 위젯에 대한 OpenGL 콘텐츠 렌더링을 준비합니다.
paintGL()를 호출하기 전에 자동으로 호출되므로 대부분의 경우 이 함수를 호출할 필요가 없습니다.
context(), paintGL() 및 doneCurrent()도 참조하세요 .
[since 6.5]
void QOpenGLWidget::makeCurrent(QOpenGLWidget::TargetBuffer targetBuffer)
전달된 버퍼의 컨텍스트를 현재로 만들고 해당 컨텍스트에 프레임버퍼 객체를 바인딩하여 이 위젯에 대한 OpenGL 콘텐츠 렌더링을 준비합니다.
참고: 이 함수는 스테레오스코픽 렌더링이 활성화된 경우에만 호출하는 것이 합리적입니다. 비활성화되었을 때 올바른 버퍼를 요청하면 아무 일도 일어나지 않습니다.
paintGL()를 호출하기 전에 자동으로 호출되므로 대부분의 경우 이 함수를 호출할 필요가 없습니다.
이 함수는 Qt 6.5에 도입되었습니다.
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 * 이벤트).
페인트 이벤트를 처리합니다.
QWidget::update()를 호출하면 페인트 이벤트 e 를 전송하여 이 함수를 호출합니다. (참고로 이 함수는 비동기식이며 update()에서 반환된 후 어느 시점에 발생합니다.) 이 함수는 약간의 준비 과정을 거친 후 가상의 paintGL()를 호출하여 QOpenGLWidget 의 프레임버퍼의 내용을 업데이트합니다. 그러면 위젯의 최상위 창이 프레임버퍼의 텍스처를 나머지 창과 합성합니다.
[virtual protected]
void QOpenGLWidget::paintGL()
이 가상 함수는 위젯을 칠해야 할 때마다 호출됩니다. 서브클래스에서 다시 구현하세요.
이 함수가 호출될 때 이미 작업이 완료되었으므로 makeCurrent()를 호출할 필요가 없습니다.
이 함수를 호출하기 전에 컨텍스트와 프레임버퍼가 바인딩되고 glViewport()를 호출하여 뷰포트가 설정됩니다. 다른 상태는 설정되지 않으며 프레임워크에서 지우거나 그리는 작업은 수행되지 않습니다.
기본 구현은 glClear()를 수행합니다. 서브클래스는 기본 클래스 구현을 호출하지 않아야 하며 자체적으로 지우기를 수행해야 합니다.
참고: 이식성을 보장하기 위해 initializeGL()에 설정된 상태가 지속될 것으로 기대하지 마세요. 그 대신 paintGL()에서 glEnable()을 호출하는 등 필요한 모든 상태를 설정하세요. WebGL을 사용하는 WebAssembly와 같은 일부 플랫폼은 상황에 따라 OpenGL 컨텍스트에 제한이 있을 수 있으며, 이로 인해 QOpenGLWidget 에 사용된 컨텍스트를 다른 용도로도 사용할 수 있기 때문입니다.
QSurfaceFormat::StereoBuffers 을 활성화하면 이 함수는 각 버퍼에 대해 한 번씩 두 번 호출됩니다. currentTargetBuffer ()를 호출하여 현재 어떤 버퍼가 바인딩되어 있는지 쿼리합니다.
참고: 하드웨어에서 스테레오스코픽 렌더링이 지원되지 않는 경우에도 각 대상의 프레임버퍼가 그려집니다. 실제로는 왼쪽 버퍼만 창에 표시됩니다.
initializeGL(), resizeGL() 및 currentTargetBuffer()도 참조하세요 .
[override virtual protected]
QPaintDevice *QOpenGLWidget::redirected(QPoint *p) const
[override virtual protected]
void QOpenGLWidget::resizeEvent(QResizeEvent *e)
다시 구현합니다: QWidget::resizeEvent(QResizeEvent * 이벤트).
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::setTextureFormat(GLenum texFormat)
사용자 정의 내부 텍스처 형식을 texFormat 로 설정합니다.
sRGB 프레임버퍼로 작업할 때는 GL_SRGB8_ALPHA8
와 같은 형식을 지정해야 합니다. 이 함수를 호출하여 이를 수행할 수 있습니다.
참고: 이 함수는 위젯이 이미 표시되어 초기화를 수행한 후에 호출하면 효과가 없습니다.
참고: 이 함수는 일반적으로 색 공간을 QSurfaceFormat::sRGBColorSpace 으로 설정하는 QSurfaceFormat::setDefaultFormat() 호출과 함께 사용해야 합니다.
textureFormat()도 참조하세요 .
void QOpenGLWidget::setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior)
이 위젯의 업데이트 동작을 updateBehavior 로 설정합니다.
updateBehavior()도 참조하세요 .
GLenum QOpenGLWidget::textureFormat() const
위젯이 이미 초기화된 경우 활성 내부 텍스처 포맷을, 포맷이 설정되었지만 위젯이 아직 표시되지 않은 경우 요청된 포맷을, setTextureFormat()이 호출되지 않았고 위젯이 아직 표시되지 않은 경우 nullptr
을 반환합니다.
setTextureFormat()도 참조하세요 .
QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const
위젯의 업데이트 동작을 반환합니다.
setUpdateBehavior()도 참조하세요 .
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.