I have been looking into how to mix gtk3 and opengl, in gtk2 you could use gtkglext but this is not packaged any where meaning any software developed would not end up in software repositories.
Managed to piece this together seems to work quite well tested on two laptops on ubuntu 13.04, posting here incase i ever need it in the future :)
#!/usr/bin/env python
# [SNIPPET_NAME: gtk3 opengl example]
# [SNIPPET_CATEGORIES: opengl]
# [SNIPPET_TAGS: opengl, gtk3]
# [SNIPPET_DESCRIPTION: using gtk3 library lets draw using opengl]
# [SNIPPET_AUTHOR: Oliver Marks ]
# [SNIPPET_LICENSE: GPL]
import sys
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL import GLX
from OpenGL.raw._GLX import struct__XDisplay
from OpenGL import GL
from ctypes import *
import Xlib
from Xlib.display import Display
from gi.repository import Gtk, GdkX11, Gdk
class gtkgl:
""" these method do not seem to exist in python x11 library lets exploit the c methods """
xlib = cdll.LoadLibrary('libX11.so')
xlib.XOpenDisplay.argtypes = [c_char_p]
xlib.XOpenDisplay.restype = POINTER(struct__XDisplay)
xdisplay = xlib.XOpenDisplay("")
display = Xlib.display.Display()
attrs = []
xwindow_id = None
width = height = 200
def __init__(self):
""" lets setup are opengl settings and create the context for our window """
self.add_attribute(GLX.GLX_RGBA, True)
self.add_attribute(GLX.GLX_RED_SIZE, 1)
self.add_attribute(GLX.GLX_GREEN_SIZE, 1)
self.add_attribute(GLX.GLX_BLUE_SIZE, 1)
self.add_attribute(GLX.GLX_DOUBLEBUFFER, 0)
xvinfo = GLX.glXChooseVisual(self.xdisplay, self.display.get_default_screen(), self.get_attributes())
configs = GLX.glXChooseFBConfig(self.xdisplay, 0, None, byref(c_int()))
self.context = GLX.glXCreateContext(self.xdisplay, xvinfo, None, True)
def add_attribute(self, setting, value):
"""just to nicely add opengl parameters"""
self.attrs.append(setting)
self.attrs.append(value)
def get_attributes(self):
""" return our parameters in the expected structure"""
attrs = self.attrs + [0, 0]
return (c_int * len(attrs))(*attrs)
def configure(self, wid):
""" """
self.xwindow_id = GdkX11.X11Window.get_xid(wid)
if(not GLX.glXMakeCurrent(self.xdisplay, self.xwindow_id, self.context)):
print 'failed'
glViewport(0, 0, self.width, self.height)
def draw_start(self):
"""make cairo context current for drawing"""
if(not GLX.glXMakeCurrent(self.xdisplay, self.xwindow_id, self.context)):
print "failed"
def draw_finish(self):
"""swap buffer when we have finished drawing"""
GLX.glXSwapBuffers(self.xdisplay, self.xwindow_id)
def test(self):
"""Test method to draw something so we can make sure opengl is working and we can see something"""
self.draw_start()
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_TRIANGLES)
glIndexi(0)
glColor3f(1.0, 0.0, 0.0)
glVertex2i(0, 1)
glIndexi(0)
glColor3f(0.0, 1.0, 0.0)
glVertex2i(-1, -1)
glIndexi(0)
glColor3f(0.0, 0.0, 1.0)
glVertex2i(1, -1)
glEnd()
self.draw_finish()
class gui():
glwrap = gtkgl()
def __init__(self):
self.window = Gtk.Window()
self.window.realize()
self.window.resize(self.glwrap.width, self.glwrap.height)
self.window.set_resizable(True)
self.window.set_reallocate_redraws(True)
self.window.set_title("GTK3 with opengl")
self.window.connect('delete_event', Gtk.main_quit)
self.window.connect('destroy', lambda quit: Gtk.main_quit())
self.drawing_area = Gtk.DrawingArea()
self.drawing_area.connect('configure_event', self.on_configure_event)
self.drawing_area.connect('draw', self.on_draw)
self.drawing_area.set_double_buffered(False)
self.drawing_area.set_size_request(self.glwrap.width, self.glwrap.height)
self.window.add(self.drawing_area)
self.window.show_all()
def on_configure_event(self, widget, event):
self.glwrap.configure(widget.get_window())
return True
def on_draw(self, widget, context):
self.glwrap.test()
def main():
g = gui()
Gtk.main()
if __name__ == '__main__':
main()
You can always pack gtkglext yourself. Also, you might want to use Clutter for OpenGl interaction inside a Gtk+ widgets hierarchy.
Related
I am trying to draw colliders of Box2D. Now I have only physics in this example without graphics for simplicity. The DrawSegment() method must be called to print hello. I inherited the DebugDrawer class from the b2Draw class:
debug_drawer.py
from Box2D import b2Draw
class DebugDrawer(b2Draw):
def DrawSegment(self, p1, p2, color):
print("hello")
def DrawSolidPolygon(self, vertices, color):
pass
def DrawPoint(self, p, size, color):
pass
def DrawPolygon(self, vertices, color):
pass
def DrawCircle(self, center, radius, color, drawwidth=1):
pass
def DrawSolidCircle(self, center, radius, axis, color):
pass
def DrawTransform(self, xf):
pass
I created one object with the box shape. I have the animationLoop() method that I call with timer. Inside of the animationLoop() method I the self.world.Step() method and I call the paintGL() method by calling the self.update() method. Inside of the paintGL() method I call the self.world.DrawDebugData() method. I expect that the DrawSegment() will be called but it does not happen.
widget.py
from Box2D import (b2_staticBody, b2Body, b2BodyDef, b2FixtureDef,
b2PolygonShape, b2Vec2, b2World)
from OpenGL import GL as gl
from PyQt6.QtCore import QElapsedTimer, QSize, QTimer
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from debug_drawer import DebugDrawer
class Widget(QOpenGLWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Box2D, OpenGL3, PyQt6")
self.setFixedSize(QSize(500, 500))
self.deltaTime = 0
self.WORLD_SCALE = 30.0
self.world = b2World(gravity=b2Vec2(0.0, 9.8))
def initializeGL(self):
gl.glClearColor(0.2, 0.2, 0.2, 1.0)
gl.glEnable(gl.GL_DEPTH_TEST)
self.debugDrawer = DebugDrawer()
self.world.renderer = self.debugDrawer
self.debugDrawer.flags = { 'drawShapes': True,
'drawJoints': True, 'drawAABBs': True, 'drawPairs': True }
# print(self.debugDrawer.flags)
shape = b2PolygonShape()
shape.SetAsBox(50.0 / self.WORLD_SCALE, 50.0 / self.WORLD_SCALE)
bodyDef = b2BodyDef()
bodyDef.type = b2_staticBody
self.body: b2Body = self.world.CreateBody(bodyDef)
fixtureDef = b2FixtureDef()
fixtureDef.shape = shape
fixtureDef.density = 2
self.body.CreateFixture(fixtureDef)
self.timer = QTimer()
self.timer.timeout.connect(self.animationLoop)
self.elapsedTimer = QElapsedTimer()
self.elapsedTimer.start()
self.timer.start(1000//60)
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
self.world.DrawDebugData()
def resizeGL(self, w: int, h: int):
gl.glViewport(0, 0, w, h)
def animationLoop(self):
self.deltaTime = self.elapsedTimer.elapsed() / 1000.0
self.elapsedTimer.restart()
self.world.Step(self.deltaTime, 8, 3)
self.update()
main.py
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QSurfaceFormat
from PyQt6.QtWidgets import QApplication
from widget import Widget
def main():
QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
app = QApplication(sys.argv)
format = QSurfaceFormat()
format.setSamples(8)
w = Widget()
w.setFormat(format)
w.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
I should use DrawPolygon to draw segments of colliders when I use boxes to draw borders around game objects. DrawSegment() will be called when an instance of b2EdgeShape is created:
edgeShape = b2EdgeShape()
edgeShape.vertices = [(0.0, 0.0), (1.0, 0.0)]
self.edgeBody: b2Body = self.world.CreateBody(bodyDef)
edgeFixtureDef = b2FixtureDef()
edgeFixtureDef.shape = edgeShape
edgeFixtureDef.density = 2
self.edgeBody.CreateFixture(edgeFixtureDef)
I am writing an application that shows the user's webcam video feed in a PyQT5 window. Using a QLabel and updating the label's pixmap for every frame is to slow due to the target device's performance.
I therefore tried to gain some speed by using OpenGL to display the video frames as 2D texture on a rectangle. I found this earlier question by user Arijit that contains a working example using GLUT. However, I fail to port the code from using GLUT to a QOpenGLWidget.
For the init and reshape functions in GLUT it is clear that they correspond to the initializeGL and resizeGL functions in QT. But where in the QOpenGLWidget lifecycle do the display and idle functions belong? Executing them inside paintGL shows no effect. The current code does not crash, but the widget stays black.
What is the right way to do this?
#!/usr/bin/env python
import sys, time
import cv2
import numpy as np
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class GLWidget(QOpenGLWidget):
def __init__(self, parent=None, width=1280, height=720):
self.parent = parent
self.width = width
self.height = height
QOpenGLWidget.__init__(self, parent)
def sizeHint(self):
return QSize(self.width,self.height)
def setImage(self,image):
self.image = np.flipud(image).tobytes()
self._idle()
def initializeGL(self):
version_profile = QOpenGLVersionProfile()
version_profile.setVersion(2,0)
self.gl = self.context().versionFunctions(version_profile)
self.gl.glClearColor(0.0, 0.0, 0.0, 1.0)
self.setImage(np.zeros((self.width, self.height,3)))
def _idle(self):
self.gl.glTexImage2D(self.gl.GL_TEXTURE_2D,
0,
self.gl.GL_RGB,
self.width,self.height,
0,
self.gl.GL_RGB,
self.gl.GL_UNSIGNED_BYTE,
self.image)
self.update()
def _display(self):
self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT)
self.gl.glEnable(self.gl.GL_TEXTURE_2D)
self.gl.glTexParameterf(self.gl.GL_TEXTURE_2D, self.gl.GL_TEXTURE_MIN_FILTER, self.gl.GL_NEAREST)
self.gl.glMatrixMode(self.gl.GL_PROJECTION)
self.gl.glLoadIdentity()
self.gl.glOrtho(0, self.width, 0, self.height,-1,1)
self.gl.glMatrixMode(self.gl.GL_MODELVIEW)
self.gl.glLoadIdentity()
self.gl.glBegin(self.gl.GL_QUADS)
self.gl.glTexCoord2f(0.0, 0.0)
self.gl.glVertex2f(0.0, 0.0)
self.gl.glTexCoord2f(1.0, 0.0)
self.gl.glVertex2f(self.width, 0.0)
self.gl.glTexCoord2f(1.0, 1.0)
self.gl.glVertex2f(self.width, self.height)
self.gl.glTexCoord2f(0.0, 1.0)
self.gl.glVertex2f(0.0, self.height)
self.gl.glEnd()
self.gl.glFlush()
def resizeGL(self, w, h):
if h == 0:
h = 1
self.gl.glViewport(0, 0, w, h)
self.gl.glMatrixMode(self.gl.GL_PROJECTION)
self.gl.glLoadIdentity()
if w <= h:
self.gl.glOrtho(-1, 1, -1*h/w, h/w, -1, 1)
else:
self.gl.glOrtho(-1*w/h, w/h, -1, 1, -1, 1)
self.gl.glMatrixMode(self.gl.GL_MODELVIEW)
self.gl.glLoadIdentity()
def paintGL(self):
self._display()
class VideoThread(QThread):
change_image_signal = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
self._run_flag = True
def run(self):
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_BUFFERSIZE,3)
while self._run_flag:
_, frame = capture.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.change_image_signal.emit(frame)
time.sleep(0.4)
capture.release()
def stop(self):
self._run_flag = False
self.wait()
class MainUI(QWidget):
def __init__(self):
QWidget.__init__(self)
self.video_size = QSize(394,292)
self.setup_ui()
self.setup_camera()
def setup_ui(self):
self.video_widget = GLWidget(self,self.video_size.width(),self.video_size.height())
self.main_layout = QGridLayout()
self.main_layout.addWidget(self.video_widget,0,0)
self.setLayout(self.main_layout)
def closeEvent(self, event):
self.thread.stop()
event.accept()
def setup_camera(self):
self.thread = VideoThread()
self.thread.change_image_signal.connect(self.display_video_stream)
self.thread.start()
#pyqtSlot(np.ndarray)
def display_video_stream(self,image):
self.video_widget.setImage(image)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MainUI()
win.show()
sys.exit(app.exec())
I found this nice tutorial of drawing and rotating a cube with PyQt and modern OpenGL. My objective was to adapt the script for point clouds, by doing the following (see also code below):
Load point cloud using Open3D and extract coordinates & colors as numpy arrays
Create Vertex Buffer Objects (VBOs) from the arrays
Change the drawing function to gl.glDrawElements(gl.GL_POINTS, ...)
Unfortunately then the point cloud is very distorted and thin (see screenshot). It should actually be a room with chairs and walls.
Do you see if I made a mistake with the VBOs or drawing? Or is there a better way of loading a point cloud?
I tested the example with the old fixed pipeline (glBegin(GL_POINTS) ... glEnd()) and there the point cloud is correctly drawn (but also the performance really bad!).
from PyQt5 import QtCore # core Qt functionality
from PyQt5 import QtGui # extends QtCore with GUI functionality
from PyQt5 import QtOpenGL # provides QGLWidget, a special OpenGL QWidget
from PyQt5 import QtWidgets
import OpenGL.GL as gl # python wrapping of OpenGL
from OpenGL import GLU # OpenGL Utility Library, extends OpenGL functionality
from OpenGL.arrays import vbo
import numpy as np
import open3d as o3d
import sys
# Loading the point cloud from file
def load_pointcloud():
pcd = o3d.io.read_point_cloud("../pointclouds/0004.ply")
print(pcd)
print("Pointcloud Center: " + str(pcd.get_center()))
points = np.asarray(pcd.points)
colors = np.asarray(pcd.colors)
return points, colors
#### here was only the GUI code (slider, ...) , which works fine! ####
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
def initializeGL(self):
self.qglClearColor(QtGui.QColor(250, 250, 250)) # initialize the screen to blue
gl.glEnable(gl.GL_DEPTH_TEST) # enable depth testing
self.initGeometryPC()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def setRotX(self, val):
self.rotX = val
def setRotY(self, val):
self.rotY = val
def setRotZ(self, val):
self.rotZ = val
def resizeGL(self, width, height):
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
aspect = width / float(height)
#GLU.gluPerspective(45.0, aspect, 1.0, 100.0) #GLU.gluPerspective(45.0, aspect, 1.0, 100.0)
gl.glOrtho(-2.0, 2.0, -2.0, 2.0, 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() # push the current matrix to the current stack
gl.glTranslate(0.0, 0.0, -5.0) # third, translate cube to specified depth
#gl.glScale(.5, .5, .5) # second, scale point cloud
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) # first, translate point cloud center to origin
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.glPointSize(2)
gl.glDrawElements(gl.GL_POINTS, len(self.pointsIdxArray), gl.GL_UNSIGNED_INT, self.pointsIdxArray)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
gl.glDisableClientState(gl.GL_COLOR_ARRAY)
gl.glPopMatrix() # restore the previous modelview matrix
# Push geometric data to GPU
def initGeometryPC(self):
points, colors = load_pointcloud()
self.pointsVtxArray = points
self.vertVBO = vbo.VBO(np.reshape(self.pointsVtxArray, (1, -1)).astype(np.float32))
self.vertVBO.bind()
self.pointsClrArray = colors
self.colorVBO = vbo.VBO(np.reshape(self.pointsClrArray, (1, -1)).astype(np.float32))
self.colorVBO.bind()
self.pointsIdxArray = np.arange(len(points))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
After a long search I came upon this stackoverflow-post. I adapted my code to that answer by storing point coordinates and colors together in one vbo-object (gl.glGenBuffers(1)). Then I define the vertex and color pointer with the specific stride and offset:
gl.glVertexPointer(3, gl.GL_FLOAT, 6*4, None)
Stride= 24 bytes: [x, y, z, r, g, b] * sizeof(float)
gl.glColorPointer(3, gl.GL_FLOAT, 6*4, ctypes.c_void_p(3*4))
Offset= 12 bytes: the rgb color starts after the 3 coordinates x, y, z
And finally I use gl.glDrawArrays(gl.GL_POINTS, 0, noOfVertices) for drawing the point cloud.
The full code can be seen below (marked with ### NEW ### comments):
from PyQt5 import QtCore # core Qt functionality
from PyQt5 import QtGui # extends QtCore with GUI functionality
from PyQt5 import QtOpenGL # provides QGLWidget, a special OpenGL QWidget
from PyQt5 import QtWidgets
import OpenGL.GL as gl # python wrapping of OpenGL
from OpenGL import GLU # OpenGL Utility Library, extends OpenGL functionality
from OpenGL.arrays import vbo
import numpy as np
import open3d as o3d
import ctypes
import sys # we'll need this later to run our Qt application
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self) # call the init for the parent class
self.resize(300, 300)
self.setWindowTitle('Hello OpenGL App')
self.glWidget = GLWidget(self)
self.initGUI()
timer = QtCore.QTimer(self)
timer.setInterval(20) # period, in milliseconds
timer.timeout.connect(self.glWidget.updateGL)
timer.start()
def initGUI(self):
central_widget = QtWidgets.QWidget()
gui_layout = QtWidgets.QVBoxLayout()
central_widget.setLayout(gui_layout)
self.setCentralWidget(central_widget)
gui_layout.addWidget(self.glWidget)
sliderX = QtWidgets.QSlider(QtCore.Qt.Horizontal)
sliderX.valueChanged.connect(lambda val: self.glWidget.setRotX(val))
sliderY = QtWidgets.QSlider(QtCore.Qt.Horizontal)
sliderY.valueChanged.connect(lambda val: self.glWidget.setRotY(val))
sliderZ = QtWidgets.QSlider(QtCore.Qt.Horizontal)
sliderZ.valueChanged.connect(lambda val: self.glWidget.setRotZ(val))
gui_layout.addWidget(sliderX)
gui_layout.addWidget(sliderY)
gui_layout.addWidget(sliderZ)
class GLWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
self.parent = parent
QtOpenGL.QGLWidget.__init__(self, parent)
def initializeGL(self):
self.qglClearColor(QtGui.QColor(100, 100, 100)) # initialize the screen to blue
gl.glEnable(gl.GL_DEPTH_TEST) # enable depth testing
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def setRotX(self, val):
self.rotX = val
def setRotY(self, val):
self.rotY = val
def setRotZ(self, val):
self.rotZ = val
def resizeGL(self, width, height):
gl.glViewport(0, 0, width, height)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
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() # push the current matrix to the current stack
gl.glTranslate(0.0, 0.0, -3.0) # third, translate cube to specified depth
#gl.glScale(20.0, 20.0, 20.0) # second, scale cube
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) # first, translate cube center to origin
# Point size
gl.glPointSize(3)
### NEW ###
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
stride = 6*4 # (24 bates) : [x, y, z, r, g, b] * sizeof(float)
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
gl.glVertexPointer(3, gl.GL_FLOAT, stride, None)
gl.glEnableClientState(gl.GL_COLOR_ARRAY)
offset = 3*4 # (12 bytes) : the rgb color starts after the 3 coordinates x, y, z
gl.glColorPointer(3, gl.GL_FLOAT, stride, ctypes.c_void_p(offset))
noOfVertices = self.noPoints
gl.glDrawArrays(gl.GL_POINTS, 0, noOfVertices)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
gl.glDisableClientState(gl.GL_COLOR_ARRAY)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
### NEW ###
gl.glPopMatrix() # restore the previous modelview matrix
def initGeometry(self):
vArray = self.LoadVertices()
self.noPoints = len(vArray) // 6
print("No. of Points: %s" % self.noPoints)
self.vbo = self.CreateBuffer(vArray)
### NEW ###
def LoadVertices(self):
pcd = o3d.io.read_point_cloud("../pointclouds/0004.ply")
print(pcd)
print("Pointcloud Center: " + str(pcd.get_center()))
points = np.asarray(pcd.points).astype('float32')
colors = np.asarray(pcd.colors).astype('float32')
attributes = np.concatenate((points, colors),axis=1)
print("Attributes shape: " + str(attributes.shape))
return attributes.flatten()
def CreateBuffer(self, attributes):
bufferdata = (ctypes.c_float*len(attributes))(*attributes) # float buffer
buffersize = len(attributes)*4 # buffer size in bytes
vbo = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
gl.glBufferData(gl.GL_ARRAY_BUFFER, buffersize, bufferdata, gl.GL_STATIC_DRAW)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
return vbo
### NEW ###
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
However, I still did not find the correct parameters for initial approach above with two separate VBOs for coordinate and color. So I am happy for further comments.
I want to get the characters printed only in blue.
How to do it?
Here is the sample program code, which is a fragment of most of the program.
I would be very grateful for your help.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
class TextViewWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="awesome gui")
self.set_resizable(True)
self.set_default_size(700, 550)
self.grid = Gtk.Grid()
self.add(self.grid)
self.create_textview()
self.buffer = []
def create_textview(self):
scrolledwindow = Gtk.ScrolledWindow()
scrolledwindow.set_hexpand(True)
scrolledwindow.set_vexpand(True)
self.grid.attach(scrolledwindow, 0, 2, 80, 1)
self.textview = Gtk.TextView()
scrolledwindow.add(self.textview)
self.textbuffer = self.textview.get_buffer()
self.textview.set_editable(False)
self.textview.set_cursor_visible(False)
self.textview.connect("key-press-event", self.on_key_down)
def on_key_down(self, widget, event, data=None):
znak_p = event.string
end_iter_m = self.textbuffer.get_iter_at_line_offset(1, 1)
qwerty_tag = self.textbuffer.create_tag(None, editable=True, foreground="blue")
self.textbuffer.insert_with_tags(end_iter_m, znak_p, qwerty_tag)
win = TextViewWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Your on_key_down handler is wrong:
you are creating an anonymous tag every time you're pressing a key
you are using an invalid string for the GtkTextTag:foreground property
you are not returning a value from the callback telling GTK whether you handled the event (and thus should stop the event propagation) or not.
The GtkTextTag:foreground property uses the same format as the gdk_rgba_parse() function; if you want a blue color, you should use rgba(0.0, 0.0, 1.0, 1.0) instead of "blue".
A correct handler is:
def on_key_down(self, widget, event, data=None):
znak_p = event.string
end_iter_m = self.textbuffer.get
self.textbuffer.insert_with_tags(end_iter_m, znak_p, self.qwerty_tag)
return True
I'm working on a transparent window which includes a DrawingArea widget, which gets on top with a solid background color, but I want to keep it transparent. I've tried everything, unfortunately the docs are a bit dated (with PyGTK on the top results). Other things I've done is connecting its draw event as I'm doing it with the window, but with no success.
Of course I need the square to be shown, so I just need the background color to transparent. I've also tried with modify_bg, but I only manage to set it to solid colors.
Here's what I have so far.
#!/usr/bin/env python
from gi.repository import Gtk, Gdk
import cairo
class GWin (Gtk.Window):
def __init__(self):
super(GWin, self).__init__()
self.set_position(Gtk.WindowPosition.CENTER)
self.screen = self.get_screen()
self.visual = self.screen.get_rgba_visual()
if self.visual != None and self.screen.is_composited():
self.set_visual(self.visual)
self.connect("draw", self.on_win_draw)
self.set_app_paintable(True)
self.show_all()
self.draw_area = Gtk.DrawingArea()
self.draw_area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.draw_area.connect('draw', self.begin_draw)
self.draw_area.show()
self.add(self.draw_area)
def begin_draw(self, draw_area, cairo_context):
cairo_context.rectangle(20, 20, 120, 120)
cairo_context.stroke()
def on_win_draw(self, widget, cr):
cr.set_source_rgba(1, 1, 1, 0.1)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
win = GWin()
win.connect('delete-event', Gtk.main_quit)
Gtk.main()
You need to set the cairo.Context source rgba before creating the rectangle. Here is the code, the edited line marked with ### ADDED THIS LINE:
#!/usr/bin/env python
from gi.repository import Gtk, Gdk
import cairo
class GWin (Gtk.Window):
def __init__(self):
super(GWin, self).__init__()
self.set_position(Gtk.WindowPosition.CENTER)
self.screen = self.get_screen()
self.visual = self.screen.get_rgba_visual()
if self.visual != None and self.screen.is_composited():
self.set_visual(self.visual)
self.connect("draw", self.on_win_draw)
self.set_app_paintable(True)
self.show_all()
self.draw_area = Gtk.DrawingArea()
self.draw_area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.draw_area.connect('draw', self.begin_draw)
self.draw_area.show()
self.add(self.draw_area)
def begin_draw(self, draw_area, cairo_context):
cairo_context.set_source_rgba(1, 1, 1, 1) ### ADDED THIS LINE
cairo_context.rectangle(20, 20, 120, 120)
cairo_context.stroke()
def on_win_draw(self, widget, cr):
cr.set_source_rgba(1, 1, 1, 0.1)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
win = GWin()
win.connect('delete-event', Gtk.main_quit)
Gtk.main()