You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt6+OpenGL绘制三角形:窗口无显示无报错问题及解决

PyQt6 OpenGL Triangle Example: Fix for No Window Display Issue

I recently ran into a problem when converting a working Qt6 C++ OpenGL triangle example to PyQt6: the program would run without any errors, but no window would show up. After troubleshooting, I've fixed the issue and wanted to share the details and solution.

Original Qt6 C++ Code

First, here's the original C++ code that works perfectly on browsers and Android:

.pro File

QT += core gui openglwidgets
win32: LIBS += -lopengl32
CONFIG += c++17
SOURCES += \
    main.cpp

main.cpp

#include <QtGui/QOpenGLFunctions>
#include <QtOpenGL/QOpenGLBuffer>
#include <QtOpenGL/QOpenGLShader>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtOpenGLWidgets/QOpenGLWidget>
#include <QtWidgets/QApplication>

class OpenGLWindow : public QOpenGLWidget, private QOpenGLFunctions {
public:
    OpenGLWindow() {
        setWindowTitle("OpenGL ES 2.0, Qt6, C++");
        resize(350, 350);
    }
    void initializeGL() override {
        initializeOpenGLFunctions();
        glClearColor(48.f / 255.f, 56.f / 255.f, 65.f / 255.f, 1.f);
        QString vertShaderSrc = "attribute vec2 aPosition;\n"
                                "void main()\n"
                                "{\n"
                                "  gl_Position = vec4(aPosition, 0.0, 1.0);\n"
                                "}\n";
        QString fragShaderSrc = "#ifdef GL_ES\n"
                                "precision mediump float;\n"
                                "#endif\n"
                                "void main()\n"
                                "{\n"
                                "  gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);\n"
                                "}\n";
        m_program.create();
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vertShaderSrc);
        m_program.addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, fragShaderSrc);
        m_program.link();
        m_program.bind();
        float vertPositions[] = { -0.5f, -0.5f, 0.5f, -0.5f, 0.f, 0.5f };
        m_vertPosBuffer.create();
        m_vertPosBuffer.bind();
        m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions));
    }
    void paintGL() override {
        glClear(GL_COLOR_BUFFER_BIT);
        m_program.bind();
        m_vertPosBuffer.bind();
        m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2);
        m_program.enableAttributeArray("aPosition");
        glDrawArrays(GL_TRIANGLES, 0, 3);
    }
private:
    QOpenGLShaderProgram m_program;
    QOpenGLBuffer m_vertPosBuffer;
};

int main(int argc, char *argv[]) {
    QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
    QApplication app(argc, argv);
    OpenGLWindow w;
    w.show();
    return app.exec();
}

Fixed PyQt6 Code

Here's the corrected PyQt6 version that matches the C++ structure and works properly:

import sys
import numpy as np
from OpenGL.GL import (GL_COLOR_BUFFER_BIT, GL_FLOAT, GL_TRIANGLES, glClear, glClearColor, glDrawArrays)
from PyQt6.QtCore import Qt
from PyQt6.QtOpenGL import QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from PyQt6.QtWidgets import QApplication

class OpenGLWindow(QOpenGLWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("OpenGL ES 2.0, PyQt6, Python")
        self.resize(350, 350)

    def initializeGL(self):
        glClearColor(48 / 255, 56 / 255, 65 / 255, 1)
        vertShaderSrc = """
        attribute vec2 aPosition;
        void main() {
            gl_Position = vec4(aPosition, 0.0, 1.0);
        }
        """
        fragShaderSrc = """
        #ifdef GL_ES
        precision mediump float;
        #endif
        void main() {
            gl_FragColor = vec4(0.2, 0.7, 0.3, 1.0);
        }
        """
        # Pass self as parent to manage object lifecycle
        self.program = QOpenGLShaderProgram(self)
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
        self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
        self.program.link()
        self.program.bind()
        # Use numpy array for correct float32 type
        vertPositions = np.array([ -0.5, -0.5, 0.5, -0.5, 0, 0.5], dtype=np.float32)
        self.vertPosBuffer = QOpenGLBuffer()
        self.vertPosBuffer.create()
        self.vertPosBuffer.bind()
        # Calculate buffer size correctly (each float32 is 4 bytes)
        self.vertPosBuffer.allocate(vertPositions, len(vertPositions) * 4)

    # Explicitly implement resizeGL (even empty) to ensure proper context setup
    def resizeGL(self, w, h):
        pass

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT)
        self.program.bind()
        self.vertPosBuffer.bind()
        self.program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 2)
        self.program.enableAttributeArray("aPosition")
        glDrawArrays(GL_TRIANGLES, 0, 3)

if __name__ == "__main__":
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)
    w = OpenGLWindow()
    w.show()
    sys.exit(app.exec())

Key Fixes Explained

  • Object Lifecycle Management: In PyQt6, QOpenGLShaderProgram needs a parent object (here, self) to ensure it isn't garbage-collected prematurely, which was causing the window to fail to initialize.
  • Vertex Data Handling: Using a numpy array with dtype=np.float32 ensures the vertex data is in the correct format, and calculating the buffer size as len(vertPositions)*4 accounts for each float32 taking 4 bytes.
  • ResizeGL Implementation: Even an empty resizeGL method is necessary to follow the QOpenGLWidget lifecycle correctly, ensuring the OpenGL context is properly set up before rendering.

内容的提问来源于stack exchange,提问作者8Observer8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:32:51