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.
Related
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.
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'
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
I have trouble rendering a custom GTK3 drawing area with custom cairo code.
It seems that the cairo context doesn't want to trouble with the shape I specify. It writes the whole source onto the whole destination, regardless of the shape.
So for example, if I set a fully white source area to paint a small white rectangle, and I ask cairo to fill() that rectangle, it paints the whole DrawingArea widget instead of that rectangle. What am I missing here ?
#!/usr/bin/env python3
from gi.repository import Gtk as gtk
from gi.repository import Gdk as gdk
import cairo
class Canvas(gtk.DrawingArea):
def __init__(self):
gtk.DrawingArea.__init__(self)
self.set_size_request(600,400)
self.connect('draw',Canvas.on_draw)
def on_draw(self,context):
context.set_source_rgb( 0.1, 0.0, 0.1 )
context.fill()
context.set_source_rgb( 1.0, 1.0, 1.0 )
context.rectangle(50,50,100,100)
context.fill()
context.paint()
return False
#look at this code
class MainWindow(gtk.Window):
def __init__(self):
gtk.Window.__init__(self, title="Game Centurion")
self.dummy0 = gtk.Label(label="dummyâ‚€")
self.canvas = Canvas()
self.box = gtk.Box()
self.box.pack_start(self.canvas, True, True, 0)
self.box.pack_start(self.dummy0, True, True, 0)
self.add(self.box)
self.connect('delete-event', gtk.main_quit)
if __name__ == '__main__':
w = MainWindow()
w.show_all()
gtk.main()
Here is the result window, you can see it is fully white instead of having a small white square over a dark purple background as I specified in the code above.
Thank you for any help.
Okay, I got it.
I misunderstood the role of the method paint of object context.
I though it was some kind of "commit" to actually perform all operation specified before.
Actually those operations are painted "on spot" (or after the return call, I dunno), and paint is an operation that copy the whole source into the destination.
No wonder it didn't work. out so well.
Here is the correct drawing callback :
def on_draw(self,emitter,context):
context.set_source_rgb( 0.1, 0.0, 0.1 )
context.paint()
context.rectangle(50,50,100,100)
context.set_source_rgb( 1.0, 1.0, 1.0 )
context.fill()
return False
I am using a GTK drawing area to display circles. I am creating the circles by drawing 2 pi arcs and filling them with a color. I want to give the color of the circles an alpha. This way when a circle is drawn on top of another circle I will be able to see the circle underneath.
Does anyone have an ideas to achieve what I want?
Maybe I missed something that would be useful in the gtk.gdk.GC.
Thanks, Ian
Try Cairo, please. Here is a deom:
#!/usr/bin/env python3
import cairo
from gi.repository import Gtk
import math
class Demo(Gtk.Window):
def __init__(self):
super(Demo, self).__init__()
self.init_ui()
def init_ui(self):
darea = Gtk.DrawingArea()
darea.connect('draw', self.on_draw)
self.add(darea)
self.set_title('Fill & stroke')
self.resize(300, 150)
self.set_position(Gtk.WindowPosition.CENTER)
self.connect('delete-event', Gtk.main_quit)
self.show_all()
def on_draw(self, window, cr):
cr.set_source_rgba(0.3, 0.4, 0.5, 0.5)
cr.arc(60, 60, 40, 0, 2*math.pi)
cr.fill()
cr.set_source_rgba(0.5, 0.2, 0.7, 0.5)
cr.arc(70, 60, 30, 0, 2*math.pi)
cr.fill()
def main():
app = Demo()
Gtk.main()
if __name__ == '__main__':
main()
And here is the screenshot:
Visit here to learn more about Cairo.