QtWidget is not showing - python-3.x

I am trying to use PyQt5 to show two widgets, the first one is a plot of sin, cos and tan function. I am using the pyqtgraph and used the code that was found in the answer of this question. I am also using another widget that draws a cube using PyOpenGL, by taking the example found in this link. I am trying to show this two widgets in one main widget, which is the main window. My approach is the following
Take a main widget.
In the main widget, use a QVBoxLayout()
In the QVBoxLayout, at two widgets mentioned above
But when I am running the code, only the plot that is using the pyqtgraph is shown but not the cube that is drawn using PyOpenGL. After a little bit debugging, I was able to find out that the height of the cube widget is setting to 0 by default. I am not sure why this is hapenning. I tried calling glWidget.resize(640,480). But it didn't work. I am new on working with PyQt and PyOpenGL. I think I am missing some details that will allow the height of the glWidget to be greater than 0, if my assumption is correct. Also I am not sure if this is actually possible to do. My current code is given below, it is a little bit messy.
import sys
from OpenGL.GL.images import asWrapper
from PyQt5.QtWidgets import QApplication, QGridLayout
from PyQt5 import QtWidgets
import pyqtgraph as pg
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt5 import QtGui
from PyQt5.QtOpenGL import *
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np
from PyQt5 import QtOpenGL
import OpenGL.GL as gl
from OpenGL import GLU
from OpenGL.arrays import vbo
class TimeLine(QtCore.QObject):
frameChanged = QtCore.pyqtSignal(int)
def __init__(self, interval=60, loopCount=1, parent=None):
super(TimeLine, self).__init__(parent)
self._startFrame = 0
self._endFrame = 0
self._loopCount = loopCount
self._timer = QtCore.QTimer(self, timeout=self.on_timeout)
self._counter = 0
self._loop_counter = 0
self.setInterval(interval)
def on_timeout(self):
if self._startFrame <= self._counter < self._endFrame:
self.frameChanged.emit(self._counter)
self._counter += 1
else:
self._counter = 0
self._loop_counter += 1
if self._loopCount > 0:
if self._loop_counter >= self.loopCount():
self._timer.stop()
def setLoopCount(self, loopCount):
self._loopCount = loopCount
def loopCount(self):
return self._loopCounts
interval = QtCore.pyqtProperty(int, fget=loopCount, fset=setLoopCount)
def setInterval(self, interval):
self._timer.setInterval(interval)
def interval(self):
return self._timer.interval()
interval = QtCore.pyqtProperty(int, fget=interval, fset=setInterval)
def setFrameRange(self, startFrame, endFrame):
self._startFrame = startFrame
self._endFrame = endFrame
#QtCore.pyqtSlot()
def start(self):
self._counter = 0
self._loop_counter = 0
self._timer.start()
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent = None):
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
self.resizeGL(640,800)
def initializeGL(self):
self.qglClearColor(QtGui.QColor(0,0,255))
gl.glEnable(gl.GL_DEPTH_TEST)
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def resizeGL(self, width, height):
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
print(width, height)
aspect = width / float(height)
GLU.gluPerspective(45.0, aspect, 1.0, 100.0)
gl.glMatrixMode(gl.GL_MODELVIEW)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glPushMatrix()
gl.glTranslate(0.0, 0.0, -50.0)
gl.glScale(20.0, 20.0, 20.0)
gl.glRotate(self.rotX, 1.0, 0.0, 0.0)
gl.glRotate(self.rotY, 0.0, 1.0, 0.0)
gl.glRotate(self.rotZ, 0.0, 0.0, 1.0)
gl.glTranslate(-0.5, -0.5, -0.5)
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
gl.glEnableClientState(gl.GL_COLOR_ARRAY)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, self.vertVBO)
gl.glColorPointer(3, gl.GL_FLOAT, 0, self.colorVBO)
gl.glDrawElements(gl.GL_QUADS, len(self.cubeIdxArray), gl.GL_UNSIGNED_INT, self.cubeIdxArray)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
gl.glDisableClientState(gl.GL_COLOR_ARRAY)
gl.glPopMatrix()
def initGeometry(self):
self.cubeVtxArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0]])
self.vertVBO = vbo.VBO(np.reshape(self.cubeVtxArray,
(1, -1)).astype(np.float32))
self.vertVBO.bind()
self.cubeClrArray = np.array(
[[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[1.0, 0.0, 1.0],
[1.0, 1.0, 1.0],
[0.0, 1.0, 1.0 ]])
self.colorVBO = vbo.VBO(np.reshape(self.cubeClrArray,
(1, -1)).astype(np.float32))
self.colorVBO.bind()
self.cubeIdxArray = np.array(
[0, 1, 2, 3,
3, 2, 6, 7,
1, 0, 4, 5,
2, 1, 5, 6,
0, 3, 7, 4,
7, 6, 5, 4 ])
def setRotX(self, val):
self.rotX = np.pi * val
def setRotY(self, val):
self.rotY = np.pi * val
def setRotZ(self, val):
self.rotZ = np.pi * val
class MainGui(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.resize(600,600)
self.cube = GLWidget(self)
self.setupUI()
def setupUI(self):
central_widget = QtWidgets.QWidget()
central_layout = QtWidgets.QVBoxLayout()
central_widget.setLayout(central_layout)
self.setCentralWidget(central_widget)
pg.setConfigOption('background',0.95)
pg.setConfigOptions(antialias=True)
self.plot = pg.PlotWidget()
self.plot.setAspectLocked(lock = True, ratio = 0.01)
#self.cube = GLWidget(self)
#self.cube.resize(200,200)
central_layout.addWidget(self.cube)
central_layout.addWidget(self.plot)
self._plots = [self.plot.plot([], [], pen=pg.mkPen(color=color, width=2)) for color in ('g', 'r', 'y')]
self._timeline = TimeLine(loopCount = 0, interval = 10)
self._timeline.setFrameRange(0,720)
self._timeline.frameChanged.connect(self.generate_data)
self._timeline.start()
def plot_data(self, data):
for plt, val in zip(self._plots, data):
plt.setData(range(len(val)),val)
#QtCore.pyqtSlot(int)
def generate_data(self, i):
ang = np.arange(i, i + 720)
cos_func = np.cos(np.radians(ang))
sin_func = np.sin(np.radians(ang))
tan_func = sin_func/cos_func
tan_func[(tan_func < -3) | (tan_func > 3)] = np.NaN
self.plot_data([sin_func, cos_func, tan_func])
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
gui = MainGui()
gui.show()
sys.exit(app.exec_())

It seems that QGLWidget (which, by the way, is deprecated, and QOpenGLWidget should be used instead) doesn't implement sizeHint(), so it returns an invalid size (QSize(-1, -1)), which means that the widget can be possibly resized to a 0 width and/or height.
Since the plot widget has an expanding size policy (and dynamically reimplements sizeHint()) the result is that the gl widget is completely hidden, having 0 height.
A possible solution is to add the widgets with a proper stretch argument to the layout.
If you want both widgets to have the same height, you can do the following:
central_layout.addWidget(self.cube, stretch=1)
central_layout.addWidget(self.plot, stretch=1)
Note that the stretch is ratio-based (only integers are considered), so, if you want the cube have half the height of the plot:
central_layout.addWidget(self.cube, stretch=1)
central_layout.addWidget(self.plot, stretch=2)
Alternatively, you can use setMinimumHeight() for the gl widget, but since the plot has an expanding policy (which normally takes precedence), that gl widget will always have that height. A better solution would be to set an expanding policy for the gl widget and implement QSizeHint, but remember that the plot widget has a dynamic size hint, so it will always take some amount of "size priority".
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent = None):
QtOpenGL.QGLWidget.__init__(self, parent)
self.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
def sizeHint(self):
return QtCore.QSize(300, 150)
# ...
There should be no need to manually call resizeGL() in the __init__, and you should also always use the dynamic access parent() function to get the parent.

Related

Is there any way to call a function in a module B, and B module is inside A module just importing module A?

Suppose we Have in python 3+
import OpenGL as gl
and I want to do something as
gl.GL.glClearColor(0.1, 0.2, 0.2, 1)
this doesn't work, but I'm curious to know if there is any way to do that, just import the main module and call other from the main.
import pygame as pg
from OpenGL import GL as gl
from OpenGL.GL import shaders as gls
import numpy as np
import ctypes
class App:
def __init__(self):
#initialise pygame
pg.init()
pg.display.set_mode((640,480), pg.OPENGL|pg.DOUBLEBUF)
self.clock = pg.time.Clock()
#initialise opengl
gl.glClearColor(0.1, 0.2, 0.2, 1)
self.shader = self.createShader("shaders/vertex.txt", "shaders/fragment.txt")
self.triangle = Triangle(self.shader)
self.mainLoop()
def createShader(self, vertexFilepath, fragmentFilepath):
with open(vertexFilepath,'r') as f:
vertex_src = f.readlines()
with open(fragmentFilepath,'r') as f:
fragment_src = f.readlines()
shader = gls.compileProgram(gls.compileShader(vertex_src, gl.GL_VERTEX_SHADER),
gls.compileShader(fragment_src, gl.GL_FRAGMENT_SHADER))
return shader
def mainLoop(self):
running = True
while (running):
#check events
for event in pg.event.get():
if (event.type == pg.QUIT):
running = False
#refresh screen
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
self.triangle.draw(self.shader)
pg.display.flip()
#timing
self.clock.tick()
framerate = int(self.clock.get_fps())
pg.display.set_caption(f"Running at {framerate} fps.")
self.quit()
def quit(self):
self.triangle.destroy()
gl.glDeleteProgram(self.shader)
pg.quit()
class Triangle:
def __init__(self, shader):
gl.glUseProgram(shader)
# x, y, z, r, g, b
self.vertices = (
-0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0, 0.0,
0.0, 0.5, 0.0, 0.0, 0.0, 1.0
)
self.vertices = np.array(self.vertices, dtype=np.float32)
self.vertex_count = 3
self.vao = gl.glGenVertexArrays(1)
gl.glBindVertexArray(self.vao)
self.vbo = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
gl.glBufferData(gl.GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, gl.GL_STATIC_DRAW)
gl.glEnableVertexAttribArray(0)
gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 24, ctypes.c_void_p(0))
gl.glEnableVertexAttribArray(1)
gl.glVertexAttribPointer(1, 3, gl.GL_FLOAT, gl.GL_FALSE, 24, ctypes.c_void_p(12))
def draw(self, shader):
gl.glUseProgram(shader)
gl.glBindVertexArray(self.vao)
gl.glDrawArrays(gl.GL_TRIANGLES, 0, self.vertex_count)
def destroy(self):
gl.glDeleteVertexArrays(1,(self.vao,))
gl.glDeleteBuffers(1,(self.vbo,))
if __name__ == "__main__":
app = App()
But I want to replace "from OpenGL import GL as gl" and "from OpenGL.GL import shaders as gls" to just one import something as import OpenGL as gl, and from gl I want to access the sub-modules and functions inside it using a complete path, something as gl.GL.shaders.compileShader(). Is there any way to do it in python?
If i try do this using complete path I got this error
AttributeError: module 'OpenGL.GL' has no attribute 'GL'

Running PyQt5 on Raspberry Pi - "PyQt5._QOpenGLFunctions_ES2" error

I am facing a problem running PyQt5 on Raspberry Pi 4.
I use raspberry pi 4, version 10 (buster) kernel version 4.19.75-v71.
The default python is 3.7.3.
I followed the exact same steps of installing sip and PyQt5 as mentioned on this thread here. I also installed python 3.6.0 following the steps introduced on the aforementioned thread.
After finishing the installation without any error, and when I run my code, I face the following error message:
qt5ct: using qt5ct plugin
QEGLPlatformContext: Failed to create context: 3009
QOpenGLWindow::beginPaint: Failed to create context
QOpenGLWindow::beginPaint: Failed to make context current
Traceback (most recent call last):
File "my_code.py", line 68, in initializeGL
self.gl = self.context().versionFunctions()
AttributeError: module 'PyQt5._QOpenGLFunctions_ES2' has no attribute 'QOpenGLFunctions_ES2'
Aborted
Any guidance how to overcome this problem? Much appreciated. Thanks in advance.
PS the code is running smoothly on Win10. Thus, the code itself must have no problem. (the environment on Win10 is: numpy=1.14.3; numpy-stl=2.5.0; pyqt5=5.10.1; sip=4.19.8; six=1.11.0; python=3.6.0; python-utils=2.3.0)
maybe you can try to reinstall pyqt5 to fix this problem. look if there are a thread is occupy pip/pyqt5/qmake.exe.
Or look you GPU, does it is OpenGL2.0 or higher version?
you said that the problems was made by
"self.gl=self.context().versionFunctions()"
And I was writhing an example, you can try it:
import sys
import math
from PyQt5.QtCore import pyqtSignal, QPoint, QSize, Qt
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QOpenGLWidget, QSlider,
QWidget)
import OpenGL.GL as gl
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.glWidget = GLWidget()
self.xSlider = self.createSlider()
self.ySlider = self.createSlider()
self.zSlider = self.createSlider()
self.xSlider.valueChanged.connect(self.glWidget.setXRotation)
self.glWidget.xRotationChanged.connect(self.xSlider.setValue)
self.ySlider.valueChanged.connect(self.glWidget.setYRotation)
self.glWidget.yRotationChanged.connect(self.ySlider.setValue)
self.zSlider.valueChanged.connect(self.glWidget.setZRotation)
self.glWidget.zRotationChanged.connect(self.zSlider.setValue)
mainLayout = QHBoxLayout()
mainLayout.addWidget(self.glWidget)
mainLayout.addWidget(self.xSlider)
mainLayout.addWidget(self.ySlider)
mainLayout.addWidget(self.zSlider)
self.setLayout(mainLayout)
self.xSlider.setValue(15 * 16)
self.ySlider.setValue(345 * 16)
self.zSlider.setValue(0 * 16)
self.setWindowTitle("Hello GL")
def createSlider(self):
slider = QSlider(Qt.Vertical)
slider.setRange(0, 360 * 16)
slider.setSingleStep(16)
slider.setPageStep(15 * 16)
slider.setTickInterval(15 * 16)
slider.setTickPosition(QSlider.TicksRight)
return slider
class GLWidget(QOpenGLWidget):
xRotationChanged = pyqtSignal(int)
yRotationChanged = pyqtSignal(int)
zRotationChanged = pyqtSignal(int)
def __init__(self, parent=None):
super(GLWidget, self).__init__(parent)
self.object = 0
self.xRot = 0
self.yRot = 0
self.zRot = 0
self.lastPos = QPoint()
self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0)
self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0)
def getOpenglInfo(self):
info = """
Vendor: {0}
Renderer: {1}
OpenGL Version: {2}
Shader Version: {3}
""".format(
gl.glGetString(gl.GL_VENDOR),
gl.glGetString(gl.GL_RENDERER),
gl.glGetString(gl.GL_VERSION),
gl.glGetString(gl.GL_SHADING_LANGUAGE_VERSION)
)
return info
def minimumSizeHint(self):
return QSize(50, 50)
def sizeHint(self):
return QSize(400, 400)
def setXRotation(self, angle):
angle = self.normalizeAngle(angle)
if angle != self.xRot:
self.xRot = angle
self.xRotationChanged.emit(angle)
self.update()
def setYRotation(self, angle):
angle = self.normalizeAngle(angle)
if angle != self.yRot:
self.yRot = angle
self.yRotationChanged.emit(angle)
self.update()
def setZRotation(self, angle):
angle = self.normalizeAngle(angle)
if angle != self.zRot:
self.zRot = angle
self.zRotationChanged.emit(angle)
self.update()
def initializeGL(self):
print(self.getOpenglInfo())
self.setClearColor(self.trolltechPurple.darker())
self.object = self.makeObject()
gl.glShadeModel(gl.GL_FLAT)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glEnable(gl.GL_CULL_FACE)
def paintGL(self):
gl.glClear(
gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glLoadIdentity()
gl.glTranslated(0.0, 0.0, -10.0)
gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
gl.glCallList(self.object)
def resizeGL(self, width, height):
side = min(width, height)
if side 360 * 16:
angle -= 360 * 16
return angle
def setClearColor(self, c):
gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF())
def setColor(self, c):
gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
before try this example, please run this command(install pyOpenGL):
pip install pyOpenGL

kivy Cannot convert float to kivy.properties.Property

I'm trying to have a button which can be clicked to add two buttons below the most recently added buttons. I'm doing this with a float height which starts at .9 and decrements from there. I'm getting the error TypeError: Cannot convert float to kivy.properties.Property.
class TasksWindow(FloatLayout):
height = .9
def __init__(self, **kwargs):
super(TasksWindow, self).__init__(**kwargs)
addBtn = Button(
text="+", pos_hint={'x': .9, 'top': 1}, size_hint=(.1, .1))
self.add_widget(addBtn)
addBtn.bind(on_press=self.clkAdd)
def clkAdd(self, obj):
height = obj.height
editBtn = Button(text="Tap to Edit", pos_hint={
'x': 0.0, 'top': height}, size_hint=(.9, .1))
delBtn = Button(text="X", pos_hint={
'x': .9, 'top': height}, size_hint=(.1, .1))
height -= .1
self.add_widget(editBtn)
self.add_widget(delBtn)
class TasksApp(App):
def build(self):
window = TasksWindow()
return window
if __name__ == '__main__':
TasksApp().run()
Use kivy.properties.NumericProperty. Ensure not to override a property name. FloatLayout has a height property.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty
class TasksWindow(FloatLayout):
btn_height = NumericProperty(0.9)
def __init__(self, **kwargs):
super(TasksWindow, self).__init__(**kwargs)
add_btn = Button(text="+", pos_hint={'x': .9, 'top': 1}, size_hint=(.1, .1))
self.add_widget(add_btn)
add_btn.bind(on_press=self.click_add)
def click_add(self, obj):
height = self.btn_height
edit_btn = Button(text="Tap to Edit", pos_hint={
'x': 0.0, 'top': height}, size_hint=(.9, .1))
del_btn = Button(text="X", pos_hint={
'x': .9, 'top': height}, size_hint=(.1, .1))
self.btn_height -= .1
self.add_widget(edit_btn)
self.add_widget(del_btn)
class TasksApp(App):
def build(self):
return TasksWindow()
if __name__ == '__main__':
TasksApp().run()
You are encountering the following error because you are using Kivy keyword, height
TypeError: Cannot convert float to kivy.properties.Property
Replace:
height = .9
with:
parent_height = NumericProperty(.9) # 90% height of its parent layout
Example
main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.properties import NumericProperty
class TasksWindow(FloatLayout):
parent_height = NumericProperty(.9) # 90% height of its parent layout
def __init__(self, **kwargs):
super(TasksWindow, self).__init__(**kwargs)
addBtn = Button(
text="+", pos_hint={'x': .9, 'top': 1}, size_hint=(.1, .1))
self.add_widget(addBtn)
addBtn.bind(on_press=self.clkAdd)
def clkAdd(self, obj):
editBtn = Button(text="Tap to Edit", pos_hint={
'x': 0.0, 'top': self.parent_height}, size_hint=(.9, .1))
delBtn = Button(text="X", pos_hint={
'x': .9, 'top': self.parent_height}, size_hint=(.1, .1))
self.parent_height -= .1
self.add_widget(editBtn)
self.add_widget(delBtn)
class TasksApp(App):
def build(self):
window = TasksWindow()
return window
if __name__ == '__main__':
TasksApp().run()
Output

Checking which item was select in CheckButtons [duplicate]

I have two CheckButtons widgets with 3 elements each. I'd like to read the status of both widgets when either one of the CheckButtons is selected then update the chart accordingly.
The slider widget has a .val for returning the status of a slider, but the CheckButtons widget seems a bit more awkward (or am I missing something obvious)?
short example:
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
class Example:
def updateChart(self, event):
colour = self.colours.labels # gets labes as text object, is there an easy way of getting the status?
print colour
# measurement = measurements.something
def __init__(self):
colourax = plt.axes([0.5, 0.4, 0.09, 0.2])
measurementax = plt.axes([0.5, 0.6, 0.09, 0.2])
self.colours = CheckButtons(colourax, ('Red', 'Green', 'Blue'), (False, False, False))
self.measurements = CheckButtons(measurementax, ('1', '2', '3'), (False, False, False))
self.colours.on_clicked(self.updateChart)
self.measurements.on_clicked(self.updateChart)
def run(self):
plt.show()
ex = Example()
ex.run()
I know it's a bit awkward, but you can check for visibility of on of the cross lines in check boxes.
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
colourax = plt.axes([0.5, 0.4, 0.09, 0.2])
colours = CheckButtons(colourax, ('Red', 'Green', 'Blue'), (False, False, False))
isRedChecked = colours.lines[0][0].get_visible()
isGreenChecked = colours.lines[1][0].get_visible()
isBlueChecked = colours.lines[2][0].get_visible()
The current development version (as of July 2017) has a
CheckButtons.get_status()
method incorporated. This can be used to query the current status of the checkboxes. It should be released in the stable version pretty soon. (Source here)
Until then, you may emulate this behaviour by using your own get_status method as in the following. It uses the same mechanism as the get_status() method from the development version, which is also very close to what the answer of #Gruby is proposing (looking at the visibility of the lines).
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
class Example:
def updateChart(self, event):
colour = self.get_status(self.colours)
measurement = self.get_status(self.measurements)
print measurement, colour
def get_status(self, cb):
return [l1.get_visible() for (l1, l2) in cb.lines]
def __init__(self):
colourax = plt.axes([0.5, 0.4, 0.09, 0.2])
measurementax = plt.axes([0.5, 0.6, 0.09, 0.2])
self.colours = CheckButtons(colourax, ('Red', 'Green', 'Blue'), (False, False, False))
self.measurements = CheckButtons(measurementax, ('1', '2', '3'), (False, False, False))
self.colours.on_clicked(self.updateChart)
self.measurements.on_clicked(self.updateChart)
def run(self):
plt.show()
ex = Example()
ex.run()
There might perhaps be a more elegant way but you can always keep track of the states of each of the checkboxes yourself, e.g. in a dict. The function that you specify using on_clicked() will receive the label string of the active checkbox as its second argument, which you can then use to update the status appropriately:
import matplotlib.pyplot as plt
from matplotlib.widgets import CheckButtons
class Example:
def onColor(self,label):
self.cstates[label] = not self.cstates[label]
print 'un'*(not self.cstates[label]) + 'checked %s' %label
self.updateChart()
def onMeasurement(self,label):
self.mstates[label] = not self.mstates[label]
print 'un'*(not self.mstates[label]) + 'checked %s' %label
self.updateChart()
def updateChart(self, event=None):
"""do something here using self.cstates and self.mstates?"""
pass
def __init__(self):
colourax = plt.axes([0.5, 0.4, 0.09, 0.2])
measurementax = plt.axes([0.5, 0.6, 0.09, 0.2])
clabels, cvals = ('Red', 'Green', 'Blue'), (False,)*3
mlabels, mvals = ('1', '2', '3'), (False,)*3
self.cstates = dict(zip(clabels,cvals))
self.mstates = dict(zip(mlabels,mvals))
self.colours = CheckButtons(colourax, clabels, cvals)
self.colours.on_clicked(self.onColor)
self.measurements = CheckButtons(measurementax, mlabels, mvals)
self.measurements.on_clicked(self.onMeasurement)
def run(self):
plt.show()
ex = Example()
ex.run()
Not the prettiest, but it works!

pyqt : transparent background QGLWidget

I hope to make a QGLWidget that has a transparent background, like a figure above.
It's a cpp code and I don't understand the some parts of it. As far as I know, it uses window handle, drawing context, and so on. But I'm poor at C and C++. I've used Python and PyQt, so it seems like a Atlantis for me. Is there any idea for QGLWidget that has a transparent background?
ADD
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QApplication, QColor
from PyQt4.QtOpenGL import QGLWidget
from OpenGL import GL
import sys
class TransGLWidget(QGLWidget):
def __init__(self, parent=None):
QGLWidget.__init__(self, parent)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.setGeometry(200, 100, 640, 480)
def initializeGL(self):
self.qglClearColor(QColor(0, 0, 0, 0))
def resizeGL(self, w, h):
GL.glViewport(0, 0, w, h)
GL.glMatrixMode(GL.GL_PROJECTION)
GL.glLoadIdentity()
x = float(w) / h
GL.glFrustum(-x, x, -1.0, 1.0, 1.0, 10.0)
GL.glMatrixMode(GL.GL_MODELVIEW)
GL.glLoadIdentity()
def paintGL(self):
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
GL.glBegin(GL.GL_TRIANGLES)
GL.glColor3f(1.0, 0.0, 0.0)
GL.glVertex3f(-1.0, 1.0, -3.0)
GL.glColor3f(0.0, 1.0, 0.0)
GL.glVertex3f(1.0, 1.0, -3.0)
GL.glColor3f(0.0, 0.0, 1.0)
GL.glVertex3f(0.0, -1.0, -3.0)
GL.glEnd()
app = QApplication(sys.argv)
widget = TransGLWidget()
widget.show()
app.exec_()
I try with above code, but it shows me nothing. (It seems a whole transparent widget.) If I get rid of "setAttribute", "setWindowFlags", is shows up a triangle. Is there any miss at the code?
Translated into Python from this C++ solution. The semicolon at the end has been removed, :: has been replaced with ., and True has been capitalized. The main source of difficulty is that setAttribute and setWindowFlags are actually methods of the QGLWidget, so self. has been added. Just add this in the __init__() constructor of your QGLWidget`.
self.setAttribute(Qt.WA_TranslucentBackground, True)
You can add
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
if you want the window to be on top of others and have no frame.

Resources