A minimal OpenGL example in PyQt6 does not work. Error: "invalid operation" in glClearColor
Question:
I try to run a very simple OpenGL example:
import sys
from OpenGL import GL as gl
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from PyQt6.QtWidgets import QApplication
class Widget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt6, OpenGL 3.3")
self.resize(400, 400)
def initializeGL(self):
gl.glClearColor(0.5, 0.5, 0.5, 1)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec())
But I have this error:
Traceback (most recent call last):
File "main.py", line 16, in initializeGL
gl.glClearColor(0, 0, 0, 1)
File "E:ProgramFilesPythonPython38libsite-packagesOpenGLplatformbaseplatform.py", line 415, in __call__
return self( *args, **named )
File "E:ProgramFilesPythonPython38libsite-packagesOpenGLerror.py", line 230, in glCheckError
raise self._errorClass(
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glClearColor,
cArguments = (0, 0, 0, 1)
)
It is the same example but in PyQt5 that works:
import sys
from OpenGL import GL as gl
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
class Widget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt5, OpenGL 3.3")
self.resize(400, 400)
def initializeGL(self):
gl.glClearColor(0.5, 0.5, 0.5, 1)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
if __name__ == "__main__":
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
There are two differences:
-
- QOpenGLWidget was moved to PyQt6.QtOpenGLWidgets
-
- the line in the PyQt5 example:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
Answers:
This line:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
should be replaced with this:
QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
These changes also apply to PySide6:
- OpenGL classes have been moved to a separate PyQt6.QtOpenGL namespace:
PyQt5:
from PyQt5.QtGui import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram,
QOpenGLTexture)
PyQt6:
from PyQt6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram,
QOpenGLTexture)
- The QOpenGLWidget class has been moved to the PyQt6.QtOpenGLWidgets namespace:
PyQt5:
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
PyQt6:
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
- Changed enum for shader types:
PyQt5:
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
PyQt6:
self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
- Changed enum Target texture:
PyQt5:
self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
PyQt6:
self.texture = QOpenGLTexture(QOpenGLTexture.Target.Target2D)
- Changed enum for setting texture filters:
PyQt5:
self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
PyQt6:
self.texture.setMinMagFilters(QOpenGLTexture.Filter.Linear, QOpenGLTexture.Filter.Linear)
- Changed enum for WrapMode:
PyQt5:
self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
PyQt6:
self.texture.setWrapMode(QOpenGLTexture.WrapMode.ClampToEdge)
- Changed enum to set application attributes:
PyQt5:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
PyQt6:
QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
A few basic non-graphical changes:
- Changed enum for file open mode:
PyQt5:
file = QFile(path)
if not file.open(QIODevice.ReadOnly):
print("Failed to open the file: " + path)
PyQt6:
file = QFile(path)
if not file.open(QIODevice.OpenModeFlag.ReadOnly):
print("Failed to open the file: " + path)
- The QApplication.exec_() method has been renamed to QApplication.exec()
PyQt5:
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
sys.exit(app.exec_())
PyQt6:
import sys
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)
sys.exit(app.exec())
Falling Collada Cube with Bullet Physics, OpenGL 3.3:
- PyQt6: https://github.com/8Observer8/falling-collada-cube-bullet-physics-opengl33-pyqt6
- PySide6: https://github.com/8Observer8/falling-collada-cube-bullet-physics-opengl33-pyside6
You should install these packages:
- pip install PyQt6 (or PySide6)
- pip install PyOpenGL
- pip install numpy
- pip install Panda3D (for Bullet Physics)
I try to run a very simple OpenGL example:
import sys
from OpenGL import GL as gl
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from PyQt6.QtWidgets import QApplication
class Widget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt6, OpenGL 3.3")
self.resize(400, 400)
def initializeGL(self):
gl.glClearColor(0.5, 0.5, 0.5, 1)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec())
But I have this error:
Traceback (most recent call last):
File "main.py", line 16, in initializeGL
gl.glClearColor(0, 0, 0, 1)
File "E:ProgramFilesPythonPython38libsite-packagesOpenGLplatformbaseplatform.py", line 415, in __call__
return self( *args, **named )
File "E:ProgramFilesPythonPython38libsite-packagesOpenGLerror.py", line 230, in glCheckError
raise self._errorClass(
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glClearColor,
cArguments = (0, 0, 0, 1)
)
It is the same example but in PyQt5 that works:
import sys
from OpenGL import GL as gl
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
class Widget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt5, OpenGL 3.3")
self.resize(400, 400)
def initializeGL(self):
gl.glClearColor(0.5, 0.5, 0.5, 1)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
if __name__ == "__main__":
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
There are two differences:
-
- QOpenGLWidget was moved to PyQt6.QtOpenGLWidgets
-
- the line in the PyQt5 example:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
- the line in the PyQt5 example:
This line:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
should be replaced with this:
QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
These changes also apply to PySide6:
- OpenGL classes have been moved to a separate PyQt6.QtOpenGL namespace:
PyQt5:
from PyQt5.QtGui import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram,
QOpenGLTexture)
PyQt6:
from PyQt6.QtOpenGL import (QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram,
QOpenGLTexture)
- The QOpenGLWidget class has been moved to the PyQt6.QtOpenGLWidgets namespace:
PyQt5:
from PyQt5.QtWidgets import QApplication, QOpenGLWidget
PyQt6:
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
- Changed enum for shader types:
PyQt5:
self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, fragShaderSrc)
PyQt6:
self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Vertex, vertShaderSrc)
self.program.addShaderFromSourceCode(QOpenGLShader.ShaderTypeBit.Fragment, fragShaderSrc)
- Changed enum Target texture:
PyQt5:
self.texture = QOpenGLTexture(QOpenGLTexture.Target2D)
PyQt6:
self.texture = QOpenGLTexture(QOpenGLTexture.Target.Target2D)
- Changed enum for setting texture filters:
PyQt5:
self.texture.setMinMagFilters(QOpenGLTexture.Linear, QOpenGLTexture.Linear)
PyQt6:
self.texture.setMinMagFilters(QOpenGLTexture.Filter.Linear, QOpenGLTexture.Filter.Linear)
- Changed enum for WrapMode:
PyQt5:
self.texture.setWrapMode(QOpenGLTexture.ClampToEdge)
PyQt6:
self.texture.setWrapMode(QOpenGLTexture.WrapMode.ClampToEdge)
- Changed enum to set application attributes:
PyQt5:
QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
PyQt6:
QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
A few basic non-graphical changes:
- Changed enum for file open mode:
PyQt5:
file = QFile(path)
if not file.open(QIODevice.ReadOnly):
print("Failed to open the file: " + path)
PyQt6:
file = QFile(path)
if not file.open(QIODevice.OpenModeFlag.ReadOnly):
print("Failed to open the file: " + path)
- The QApplication.exec_() method has been renamed to QApplication.exec()
PyQt5:
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
sys.exit(app.exec_())
PyQt6:
import sys
from PyQt6.QtWidgets import QApplication
app = QApplication(sys.argv)
sys.exit(app.exec())
Falling Collada Cube with Bullet Physics, OpenGL 3.3:
- PyQt6: https://github.com/8Observer8/falling-collada-cube-bullet-physics-opengl33-pyqt6
- PySide6: https://github.com/8Observer8/falling-collada-cube-bullet-physics-opengl33-pyside6
You should install these packages:
- pip install PyQt6 (or PySide6)
- pip install PyOpenGL
- pip install numpy
- pip install Panda3D (for Bullet Physics)