I'm writing a GUI for displaying a 6-Axis Motion sensor's output using Python.
The Window is supposed to have an OpenGL Widget displaying the rotation in realtime. Normally I would write a separate class for my openGLWidget
but since my UI has quite a lot of elements it doesn't seem reasonable to construct it from scratch. Instead I just load the .ui File, find everything I need and that's it. However, the glRotate()
Function is updated only once and then never again, and I have no clue what might be causing this Problem.
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import *
import OpenGL.GL as gl
import OpenGL.GLU as glu
import sys
class Ui(QtWidgets.QWidget):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('gl_test.ui', self)
self.openGLWidget = self.findChild(QtWidgets.QOpenGLWidget, 'openGLWidget')
self.openGLWidget.initializeGL()
self.openGLWidget.paintGL = self.paintGL
self.openGLWidget.initializeGL = self.initializeGL
self.object = None
self.rotation = 45.0
# QTimer for updating the GL Viewport
self.GLtimer = QTimer()
self.GLtimer.setInterval(100)
self.GLtimer.timeout.connect(self.openGLWidget.paintGL)
self.GLtimer.start()
def paintGL(self):
try:
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
x, y, width, height = gl.glGetDoublev(gl.GL_VIEWPORT)
glu.gluPerspective(
45, # field of view in degrees
width / float(height or 1), # aspect ratio
.25, # near clipping plane
200, # far clipping plane
)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity()
gl.glTranslated(0.0, 0.0, -10.0)
self.rotation += 1
print(self.rotation)
gl.glRotate(self.rotation, 1, 0, 0) # works only once for some reason?
gl.glCallList(self.object)
except Exception as exc:
print(exc)
pass
def initializeGL(self):
try:
# making an example cube
self.object = gl.glGenLists(1)
gl.glNewList(self.object, gl.GL_COMPILE)
gl.glBegin(gl.GL_QUADS)
gl.glColor3f(0.0, 1.0, 0.0)
gl.glVertex3f(1.0, 1.0, -1.0)
gl.glVertex3f(-1.0, 1.0, -1.0)
gl.glVertex3f(-1.0, 1.0, 1.0)
gl.glVertex3f(1.0, 1.0, 1.0)
gl.glColor3f(0.0, 1.0, 0.0)
gl.glVertex3f(1.0, -1.0, 1.0)
gl.glVertex3f(-1.0, -1.0, 1.0)
gl.glVertex3f(-1.0, -1.0, -1.0)
gl.glVertex3f(1.0, -1.0, -1.0)
gl.glColor3f(0.0, 1.0, 0.0)
gl.glVertex3f(1.0, 1.0, 1.0)
gl.glVertex3f(-1.0, 1.0, 1.0)
gl.glVertex3f(-1.0, -1.0, 1.0)
gl.glVertex3f(1.0, -1.0, 1.0)
gl.glColor3f(0.0, 1.0, 0.0)
gl.glVertex3f(1.0, -1.0, -1.0)
gl.glVertex3f(-1.0, -1.0, -1.0)
gl.glVertex3f(-1.0, 1.0, -1.0)
gl.glVertex3f(1.0, 1.0, -1.0)
gl.glColor3f(0.0, 1.0, 0.0)
gl.glVertex3f(-1.0, 1.0, 1.0)
gl.glVertex3f(-1.0, 1.0, -1.0)
gl.glVertex3f(-1.0, -1.0, -1.0)
gl.glVertex3f(-1.0, -1.0, 1.0)
gl.glColor3f(0.0, 1.0, 0.0)
gl.glVertex3f(1.0, 1.0, -1.0)
gl.glVertex3f(1.0, 1.0, 1.0)
gl.glVertex3f(1.0, -1.0, 1.0)
gl.glVertex3f(1.0, -1.0, -1.0)
gl.glEnd()
gl.glEndList()
gl.glEnable(gl.GL_CULL_FACE)
except Exception as exc:
print(exc)
pass
def main():
app = QtWidgets.QApplication(sys.argv)
window = Ui()
window.show()
app.exec_()
main()
This is the part that doesn't work. With self.rotation increasing every time paintGl()
and therefore glRotate()
are called I'd expect the Cube to rotate, but for some reason it doesn't.
The issue is the timer event:
self.GLtimer.timeout.connect(self.openGLWidget.paintGL)
It is not suggested to call .paintGL
directly. Note, that OpenGL can't draw anything, the OpenGL Context has tobe made current before and after drawing, the window has to be updated. You can see the initial drawing, because the first call to .paintGL
is done by the framework. The following calls, which are sourced by the timer event don't generate a valid output.
You've to call .update()
, which makes the context current and triggers .paintGL()
to be called e.g.:
class Ui(QtWidgets.QWidget):
def __init__(self):
# [...]
self.GLtimer = QTimer()
self.GLtimer.setInterval(100)
self.GLtimer.timeout.connect(self.redraw)
self.GLtimer.start()
def redraw(self):
# updated the widget - triggers paintGL to be called
self.openGLWidget.update()
The animation is generated by you original code, except that I've switched to line drawing mode by glPolygonMode
.
gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)