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,
QOpenGLShaderProgramneeds 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.float32ensures the vertex data is in the correct format, and calculating the buffer size aslen(vertPositions)*4accounts for each float32 taking 4 bytes. - ResizeGL Implementation: Even an empty
resizeGLmethod is necessary to follow the QOpenGLWidget lifecycle correctly, ensuring the OpenGL context is properly set up before rendering.
内容的提问来源于stack exchange,提问作者8Observer8
相关产品推荐
相关产品推荐

