GLViewWidget is layout doesn't work

140 views
Skip to first unread message

Hassan Bahrami

unread,
Jan 17, 2022, 10:16:49 PM1/17/22
to pyqtgraph
Hi all,

I'm trying to test a 3D simulation in pyqtgraph, so I implemented a quick example in pyqtgrph using GLViewWidget based on this video in youtube with a little difference, and it works perfectly. The source code is:
```
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
import pyqtgraph.opengl as gl
import OpenGL.GL as GL
import numpy as np
import sys

class GLWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(GLWidget, self).__init__(parent)
self.w = gl.GLViewWidget()
self.w.setGeometry(0, 110, 1080, 780)
self.w.show()
self.w.setWindowTitle('Physics-based simulation')
self.w.setCameraPosition(distance=50, elevation=8)

# self.initializeGL()
self.paintGL()
# self.w.setBackgroundColor(255, 255, 255, 255)


def initializeGL(self):
# glewInit()
GL.glClearColor(0.0, 0.0, 0.0, 0.0)
GL.glEnable(GL.GL_LIGHTING)
GL.glEnable(GL.GL_LIGHT0)
GL.glEnable(GL.GL_NORMALIZE)
GL.glEnable(GL.GL_COLOR_MATERIAL)
GL.glEnable(GL.GL_CULL_FACE)
GL.glEnable(GL.GL_DEPTH_TEST)


def paintGL(self):
grid = gl.GLGridItem()
grid.scale(2, 2, 2)
self.w.addItem(grid)

self.nsteps = 1
self.ypoint = range(-20, 22, self.nsteps)
self.xpoint = range(-20, 22, self.nsteps)
self.nfaces = len(self.ypoint)
self.offset = 0

verts = np.array([
[
x, y, np.random.normal(1)
] for n, x in enumerate(self.xpoint) for m, y in enumerate(self.ypoint)
], dtype=np.float32)
# create the faces and colors arrays
faces = []
colors = []
for m in range(self.nfaces - 1):
yoff = m * self.nfaces
for n in range(self.nfaces - 1):
faces.append([n + yoff, yoff + n + self.nfaces, yoff + n + self.nfaces + 1])
faces.append([n + yoff, yoff + n + 1, yoff + n + self.nfaces + 1])
colors.append([0, 0, 0, 0])
colors.append([0, 0, 0, 0])

faces = np.array(faces)
colors = np.array(colors)

self.m1 = gl.GLMeshItem(
vertexes=verts,
faces=faces, faceColors=colors,
smooth=False, drawEdges=True
)

self.m1.setGLOptions('additive')
self.w.addItem(self.m1)


def update(self):
verts = np.array([
[
x, y, np.random.normal(1)
] for n, x in enumerate(self.xpoint) for m, y in enumerate(self.ypoint)
], dtype=np.float32)

faces = []
colors = []
for m in range(self.nfaces - 1):
yoff = m * self.nfaces
for n in range(self.nfaces - 1):
faces.append([n + yoff, yoff + n + self.nfaces, yoff + n + self.nfaces + 1])
faces.append([n + yoff, yoff + n + 1, yoff + n + self.nfaces + 1])
colors.append([n / self.nfaces, 1 - n / self.nfaces, m / self.nfaces, 0.7])
colors.append([n / self.nfaces, 1 - n / self.nfaces, m / self.nfaces, 0.8])

faces = np.array(faces)
colors = np.array(colors)

self.m1.setMeshData(
vertexes = verts, faces = faces, faceColors = colors
)

def start(self):
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtWidgets.QApplication.instance().exec_()


def aimation(self):
timer = QtCore.QTimer()
timer.timeout.connect(self.update)
timer.start(10)
self.start()
self.update()


if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
t = GLWidget()
t.aimation()
```

but when I want to create a layout to add push button or other widgets like below:

```
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
import pyqtgraph.opengl as gl
import OpenGL.GL as GL
import numpy as np
import sys


class GLWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(GLWidget, self).__init__(parent)

self.w = QtWidgets.QWidget()
self.w.setGeometry(0, 110, 1080, 780)
self.w.show()
self.w.setWindowTitle('Physics-based simulation')

self.plot = gl.GLViewWidget()
self.plot.setCameraPosition(distance=50, elevation=8)

## Create a grid layout to manage the widgets size and position
btn = QtWidgets.QPushButton('Run')
text = QtWidgets.QLineEdit('enter text')
listw = QtWidgets.QListWidget()

self.layout = QtWidgets.QGridLayout()
self.w.setLayout(self.layout)

self.layout.addWidget(btn, 0, 0) # button goes in upper-left
self.layout.addWidget(text, 1, 0) # text edit goes in middle-left
self.layout.addWidget(listw, 2, 0) # list widget goes in bottom-left
self.layout.addWidget(self.plot, 0, 1, 3, 1) # plot goes on right side, spanning 3 rows

self.plot.initializeGL()
self.plot.paintGL()
# self.w.setBackgroundColor(255, 255, 255, 255)


def initializeGL(self):
GL.glClearColor(0.0, 0.0, 0.0, 0.0)
GL.glEnable(GL.GL_LIGHTING)
GL.glEnable(GL.GL_LIGHT0)
GL.glEnable(GL.GL_NORMALIZE)
GL.glEnable(GL.GL_COLOR_MATERIAL)
GL.glEnable(GL.GL_CULL_FACE)
GL.glEnable(GL.GL_DEPTH_TEST)


def paintGL(self):
grid = gl.GLGridItem()
grid.scale(2, 2, 2)
self.plot.addItem(grid)

self.nsteps = 1
self.ypoint = range(-20, 22, self.nsteps)
self.xpoint = range(-20, 22, self.nsteps)
self.nfaces = len(self.ypoint)
self.offset = 0

verts = np.array([
[
x, y, np.random.normal(1)
] for n, x in enumerate(self.xpoint) for m, y in enumerate(self.ypoint)
], dtype=np.float32)
# create the faces and colors arrays
faces = []
colors = []
for m in range(self.nfaces - 1):
yoff = m * self.nfaces
for n in range(self.nfaces - 1):
faces.append([n + yoff, yoff + n + self.nfaces, yoff + n + self.nfaces + 1])
faces.append([n + yoff, yoff + n + 1, yoff + n + self.nfaces + 1])
colors.append([0, 0, 0, 0])
colors.append([0, 0, 0, 0])

faces = np.array(faces)
colors = np.array(colors)

self.m1 = gl.GLMeshItem(
vertexes=verts,
faces=faces, faceColors=colors,
smooth=False, drawEdges=True
)

self.m1.setGLOptions('additive')
self.plot.addItem(self.m1)


def update(self):
verts = np.array([
[
x, y, np.random.normal(1)
] for n, x in enumerate(self.xpoint) for m, y in enumerate(self.ypoint)
], dtype=np.float32)

faces = []
colors = []
for m in range(self.nfaces - 1):
yoff = m * self.nfaces
for n in range(self.nfaces - 1):
faces.append([n + yoff, yoff + n + self.nfaces, yoff + n + self.nfaces + 1])
faces.append([n + yoff, yoff + n + 1, yoff + n + self.nfaces + 1])
colors.append([n / self.nfaces, 1 - n / self.nfaces, m / self.nfaces, 0.7])
colors.append([n / self.nfaces, 1 - n / self.nfaces, m / self.nfaces, 0.8])

faces = np.array(faces)
colors = np.array(colors)

self.m1.setMeshData(
vertexes = verts, faces = faces, faceColors = colors
)

def start(self):
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtWidgets.QApplication.instance().exec_()


def aimation(self):
timer = QtCore.QTimer()
timer.timeout.connect(self.update)
timer.start(10)
self.start()
self.update()


if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
t = GLWidget()
t.aimation()
```
I got following following error:
"    raise GLError(
OpenGL.error.GLError: GLError(
        err = 1282,
        description = b'invalid operation',
        baseOperation = glViewport,
        cArguments = (0, 0, 640, 480)
)"

My ultimate goal is to create a push button, "Run" when I click it the simulation starts running. I don't what's the problem. Any idea?

Martin Chase

unread,
Jan 19, 2022, 4:32:09 PM1/19/22
to pyqt...@googlegroups.com
In my experience, the GL widgets don't easily allow non-GL widgets to be embedded. I'm not sure if this is something that can be worked around, but I know e.g. https://github.com/pyqtgraph/pyqtgraph/blob/master/pyqtgraph/examples/VideoSpeedTest.py puts the GL underneath the non-GL without trouble, so that may be your best bet.

Good luck!
 - Martin

Hassan Bahrami

unread,
Jan 19, 2022, 6:52:12 PM1/19/22
to pyqtgraph
Hi Martin,
Thank you for your reply,

You're right, GLWidget is not completely compatible with other widgets in Qt. But I could reslove the problem by replacing GraphicsLayoutWidget instead of using Qwidget. Also, for using OpenGL functionality in pyqtgraph, I downgraded my pyqtgraph version to 0.11rc0 which is bug-fixed and has performance improvements. Now I can use pyopengl in pyqtgraph as well. 
Anyway, thanks for the help!

Hassan  
Reply all
Reply to author
Forward
0 new messages