I'm writing an application with pyglet where all rendered objects are children of the window class. I'm trying to draw a simple rectangle, but using on_resize seems to break everything. There's no error message, it just doesn't draw the rectangle.
This is my file structure:
main.py
lib
|-- window.py
|-- quad.py
This code doesn't work, but if I remove the on_resize methods it does:
-------------
FILE: main.py
-------------
import pyglet
import lib
window = lib.window.Window(1280, 720)
window.add_object(lib.quad.Quad())
pyglet.app.run()
-------------------
FILE: lib/window.py
-------------------
import pyglet
from . import quad
class Window(pyglet.window.Window):
def __init__(self, w, h):
super().__init__(width=w, height=h)
self.objects = []
def on_draw(self):
for obj in self.objects:
obj.on_draw()
def on_resize(self, width, height):
for obj in self.objects:
obj.on_resize(width, height)
def add_object(self, obj):
self.objects.extend([obj])
-------------
FILE: lib/quad.py
-------------
import pyglet
import pyglet.gl
class Quad():
def __init__(self):
self.quad = pyglet.graphics.vertex_list(4, ('v2i', (10, 10, 100, 10, 100, 100, 10, 100)), ('c3B', (0, 0, 255, 0, 0, 255, 0, 255, 0, 0, 255, 0)))
def on_draw(self):
self.quad.draw(pyglet.gl.GL_QUADS)
def on_resize(self, width, height):
pass
I would like to be able to keep rendered objects as children of the window class, since that makes running event handlers much easier. Is there any way that I can make this work with the on_resize handler? Any help is appreciated.
EDIT: I tried removing on_resize from the Quad class, and making on_resize do nothing in the Window class. It seems like the existence of the on_resize function is the issue--if on_resize exists, pyglet wont draw the rectangle.
The problem is by subclassing Window, (MyWindow in this case), when you define an on_resize() event handler, you are replacing the inherited handler with your own. What you want to do instead is to push your on_resize() handler onto the event handling stack so that both handlers get called. You want to do the same some for of the others like on_close(). Example:
class MyWindow(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_minimum_size(400, 300)
#
# Push your handler onto the on_resize handler stack
#
self.push_handlers(on_resize=self.local_on_resize)
def local_on_resize(self, x, y):
# Do stuff
def on_draw(self):
self.clear()
self.triangle.draw()
Note that you can reproduce the failure by having your local_on_resize() handler return a value of pyglet.event.EVENT_HANDLED, (which will stop processing of the remaining handlers), and the graphics won't render.
In the on_resize method add the glViewport function call. And also don't forget to set up an orthogonal projection. Take a look at my code, it draws a triangle at the center of the screen.
from pyglet.gl import *
class Triangle:
def __init__(self):
self.vertices = pyglet.graphics.vertex_list(3, ('v3f', [0,0,0, 300,0,0, 150,300,0]),
('c3B', [255,0,0, 0,255,0, 0,0,255]))
def draw(self):
self.vertices.draw(GL_TRIANGLES)
class MyWindow(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_minimum_size(400, 300)
glClearColor(0.2, 0.25, 0.2, 1.0)
glOrtho(0, 1280, 0, 720, -10, 10) # setup orthogonal projection
self.triangle = Triangle()
def on_draw(self):
self.clear()
glPushMatrix()
glTranslatef(640-150 ,360-150, 0) # translate the Triangle to the center
self.triangle.draw()
glPopMatrix()
def on_resize(self, width, height):
glViewport(0, 0, width, height) # resize the viewport
if __name__ == "__main__":
MyWindow(1280, 720, 'My window', resizable=True)
pyglet.app.run()
Related
How do i update ellipse color in kivy? i tried this
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color
from kivy.clock import Clock
class Touch(Widget):
def __init__(self, **kwargs):
super(Touch, self).__init__(**kwargs)
self.x=0
with self.canvas:
self.rect= Rectangle(pos= (self.x, 200), size= (3, 30), color=Color(0.9,0.9,0.1,1))
Clock.schedule_interval(self.update, 1/30.)
def update(self, *args):
self.x+=3
self.rect.pos= (self.x, 200)
self.rect.size= (self.x/2, 200)
# self.rect.color= Color(int(self.x/100), 0.9, 0.1, 1)
class My_app(App):
def build(self):
return Touch()
My_app().run()
it work when i try to change pos or size, but if i try to change the color by not commenting this line
# self.rect.color= Color(int(self.x/100), 0.9, 0.1, 1)
it will raise this error
AttributeError: 'kivy.graphics.vertex_instructions.Rectangle' object has no attribute 'color'
if we can't update the color of some rectangle, is there a proper way to update it?
[edit]
i got answer from reddit, turn out, when you type Color(r,g,b,a), it is making a new object, so if you assign it for example:
color= Color(r,g,b,a)
and you look inside of that object
dir(color)
it have "rgba" attribute, and when we change that attribute, you change the color to whatever shape object that is created when that color object is still active.
Yes, your info from reddit is correct. Here is how to apply it:
class Touch(Widget):
def __init__(self, **kwargs):
super(Touch, self).__init__(**kwargs)
self.x=0
with self.canvas:
self.color = Color(0.9,0.9,0.1,1)
self.rect= Rectangle(pos= (self.x, 200), size= (3, 30))
Clock.schedule_interval(self.update, 1/30.)
def update(self, *args):
self.x+=3
self.rect.pos= (self.x, 200)
self.rect.size= (self.x/2, 200)
self.color.rgb = [self.x/1000., 0, 0, 1]
I have changed the updated rgba to [self.x/1000., 0, 0, 1] just to make it more obvious when it is run.
I'm working on a GUI in Python with PySide2. I have a GraphicsView, where I'll put an image, and I'd like to draw and move a polygon around on that image. I've found many examples of simply drawing polygons, circles, etc. in PySide, PySide2, or PyQt 4/5 in Python. However, I haven't been able to figure out why my graphics items do not move on an event without deleting and redrawing.
I'm using the keyboard to change the X value on a PySide2 QRectF. The X value is clearly changing, but the rectangle does not actually move.
Here is a minimal example:
from PySide2 import QtCore, QtGui, QtWidgets
from functools import partial
class DebuggingDrawing(QtWidgets.QGraphicsView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# initialize the scene and set the size
self._scene = QtWidgets.QGraphicsScene(self)
self._scene.setSceneRect(0,0,500,500)
self.setScene(self._scene)
# make a green pen and draw a 10 wide, 20 high rectangle at x=20, y=30
self.pen = QtGui.QPen(QtCore.Qt.green, 0)
self.draw_rect = QtCore.QRectF(20, 30, 10, 20)
# add the rectangle to our scene
self._scene.addRect(self.draw_rect, self.pen)
def move_rect(self, dx: int):
# method for moving the existing rectangle
# get the x value
x = self.draw_rect.x()
print('x: {} dx: {}'.format(x, dx))
# use the moveLeft method of QRectF to change the rectangle's left side x value
self.draw_rect.moveLeft(x + dx)
self.update()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.labelImg = DebuggingDrawing()
# Get a keyboard shortcut and hook it up to the move_rect method
next_shortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Right'), self)
next_shortcut.activated.connect(partial(self.labelImg.move_rect, 1))
# get the left key shortcut, move_rect one pixel left
back_shortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Left'), self)
back_shortcut.activated.connect(partial(self.labelImg.move_rect, -1))
self.setCentralWidget(self.labelImg)
self.setMaximumHeight(480)
self.update()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
testing = MainWindow()
testing.show()
app.exec_()
Here's what the output looks like:
You clearly can't see in the image, but even though the rectangle's x value is changing according to our print calls, nothing moves around in the image. I've confirmed it's not just my eyes, because if I draw new rectangles in move_rect, they clearly show up.
draw_rect is a QRectF is an input to create an item(QGraphicsRectItem) that is returned by the addRect() method similar to pen, that is, it takes the information but then no longer uses it. The idea is to move the item using setPos():
class DebuggingDrawing(QtWidgets.QGraphicsView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# initialize the scene and set the size
self._scene = QtWidgets.QGraphicsScene(self)
self._scene.setSceneRect(0, 0, 500, 500)
self.setScene(self._scene)
# make a green pen and draw a 10 wide, 20 high rectangle at x=20, y=30
pen = QtGui.QPen(QtCore.Qt.green, 0)
draw_rect = QtCore.QRectF(20, 30, 10, 20)
# add the rectangle to our scene
self.item_rect = self._scene.addRect(draw_rect, pen)
def move_rect(self, dx: int):
p = self.item_rect.pos()
p += QtCore.QPointF(dx, 0)
self.item_rect.setPos(p)
If you still want to use draw_rect then you have to set it again in the item:
self.pen = QtGui.QPen(QtCore.Qt.green, 0)
self.draw_rect = QtCore.QRectF(20, 30, 10, 20)
# add the rectangle to our scene
self.item_rect = self._scene.addRect(self.draw_rect, self.pen)
def move_rect(self, dx: int):
# method for moving the existing rectangle
# get the x value
x = self.draw_rect.x()
print('x: {} dx: {}'.format(x, dx))
# use the moveLeft method of QRectF to change the rectangle's left side x value
self.draw_rect.moveLeft(x + dx)
self.item_rect.setRect(self.draw_rect)
It is recommended that "Graphics View Framework" be read so that the QGraphicsItems, QGraphicsView and QGraphicsScene work.
I have user-adjustable annotations in a graphics scene. The size/rotation of annotations is handled by dragging corners of a rectangle about the annotation. I'm using a custom rect (instead of the boundingRect) so it follows the rotation of the parent annotation. The control corners are marked by two ellipses whose parent is the rect so transformations of rect/ellipse/annotation are seamless.
I want to detect when the cursor is over one of the corners, which corner it is, and the exact coordinates. For this task it seems that I should filter the hoverevents with the parent rect using a sceneEventFilter.
I've tried umpty zilch ways of implementing the sceneEventFilter to no avail. All events go directly to the hoverEnterEvent function. I've only found a few bits of example code that do something like this but I'm just plain stuck. btw, I'm totally self taught on Python and QT over the past 3 months, so please bear with me. I'm sure I'm missing something very basic. The code is a simplified gui with two ellipses. We're looking to capture events in the sceneEventFilter but always goes to hoverEnterEvent.
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem
import sys
class myHandle(QtGui.QGraphicsEllipseItem):
def __init__(self, parent = None):
super(myHandle, self).__init__(parent)
def addTheHandle(self, h_parent = 'null', kind = 'null'):
handle_w = 40
if kind == 'scaling handle':
handle_x = h_parent.boundingRect().topRight().x() - handle_w/2
handle_y = h_parent.boundingRect().topRight().y() - handle_w/2
if kind == 'rotation handle':
handle_x = h_parent.boundingRect().topLeft().x() - handle_w/2
handle_y = h_parent.boundingRect().topLeft().y() - handle_w/2
the_handle = QtGui.QGraphicsEllipseItem(QtCore.QRectF(handle_x, handle_y, handle_w, handle_w))
the_handle.setPen(QtGui.QPen(QtGui.QColor(255, 100, 0), 3))
the_handle.setParentItem(h_parent)
the_handle.setAcceptHoverEvents(True)
the_handle.kind = kind
return the_handle
class myRect(QtGui.QGraphicsRectItem):
def __init__(self, parent = None):
super(myRect, self).__init__(parent)
def rectThing(self, boundingrectangle):
self.setAcceptHoverEvents(True)
self.setRect(boundingrectangle)
mh = myHandle()
rotation_handle = mh.addTheHandle(h_parent = self, kind = 'rotation handle')
scaling_handle = mh.addTheHandle(h_parent = self, kind = 'scaling handle')
self.installSceneEventFilter(rotation_handle)
self.installSceneEventFilter(scaling_handle)
return self, rotation_handle, scaling_handle
def sceneEventFilter(self, event):
print('scene ev filter')
return False
def hoverEnterEvent(self, event):
print('hover enter event')
class Basic(QtGui.QMainWindow):
def __init__(self):
super(Basic, self).__init__()
self.initUI()
def eventFilter(self, source, event):
return QtGui.QMainWindow.eventFilter(self, source, event)
def exit_the_program(self):
pg.exit()
def initUI(self):
self.resize(300, 300)
self.centralwidget = QtGui.QWidget()
self.setCentralWidget(self.centralwidget)
self.h_layout = QtGui.QHBoxLayout(self.centralwidget)
self.exit_program = QtGui.QPushButton('Exit')
self.exit_program.clicked.connect(self.exit_the_program)
self.h_layout.addWidget(self.exit_program)
self.this_scene = QGraphicsScene()
self.this_view = QGraphicsView(self.this_scene)
self.this_view.setMouseTracking(True)
self.this_view.viewport().installEventFilter(self)
self.h_layout.addWidget(self.this_view)
self.circle = self.this_scene.addEllipse(QtCore.QRectF(40, 40, 65, 65), QtGui.QPen(QtCore.Qt.black))
mr = myRect()
the_rect, rotation_handle, scaling_handle = mr.rectThing(self.circle.boundingRect())
the_rect.setPen(QtGui.QPen(QtCore.Qt.black))
the_rect.setParentItem(self.circle)
self.this_scene.addItem(the_rect)
self.this_scene.addItem(rotation_handle)
self.this_scene.addItem(scaling_handle)
def main():
app = QtGui.QApplication([])
main = Basic()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The main problem is that you are installing the event filter of the target items on the rectangle: the event filter of the rectangle will never receive anything. Moreover, sceneEventFilter accepts two arguments (the watched item and the event), but you only used one.
What you should do is to install the event filter of the rectangle on the target items:
rotation_handle.installSceneEventFilter(self)
scaling_handle.installSceneEventFilter(self)
That said, if you want to use those ellipse items for scaling or rotation of the source circle, your approach is a bit wrong to begin with.
from math import sqrt
# ...
class myRect(QtGui.QGraphicsRectItem):
def __init__(self, parent):
super(myRect, self).__init__(parent)
self.setRect(parent.boundingRect())
# rotation is usually based on the center of an object
self.parentItem().setTransformOriginPoint(self.parentItem().rect().center())
# a rectangle that has a center at (0, 0)
handleRect = QtCore.QRectF(-20, -20, 40, 40)
self.rotation_handle = QtGui.QGraphicsEllipseItem(handleRect, self)
self.scaling_handle = QtGui.QGraphicsEllipseItem(handleRect, self)
# position the handles by centering them at the right corners
self.rotation_handle.setPos(self.rect().topLeft())
self.scaling_handle.setPos(self.rect().topRight())
for source in (self.rotation_handle, self.scaling_handle):
# install the *self* event filter on the handles
source.installSceneEventFilter(self)
source.setPen(QtGui.QPen(QtGui.QColor(255, 100, 0), 3))
def sceneEventFilter(self, source, event):
if event.type() == QtCore.QEvent.GraphicsSceneMouseMove:
# map the handle event position to the ellipse parent item; we could
# also map to "self", but using the parent is more consistent
localPos = self.parentItem().mapFromItem(source, event.pos())
if source == self.rotation_handle:
# create a temporary line to get the rotation angle
line = QtCore.QLineF(self.boundingRect().center(), localPos)
# add the current rotation to the angle between the center and the
# top left corner, then subtract the new line angle
self.parentItem().setRotation(135 + self.parentItem().rotation() - line.angle())
# note that I'm assuming that the ellipse is a circle, so the top
# left angle will always be at 135°; if it's not a circle, the
# rect width and height won't match and the angle will be
# different, so you'll need to compute that
# parentRect = self.parentItem().rect()
# oldLine = QtCore.QLineF(parentRect.center(), parentRect.topLeft())
# self.parentItem().setRotation(
# oldLine.angle() + self.parentItem().rotation() - line.angle())
elif source == self.scaling_handle:
# still assuming a perfect circle, so the rectangle is a square;
# the line from the center to the top right corner is used to
# compute the square side size, which is the double of a
# right-triangle cathetus where the hypotenuse is the line
# between the center and any of its corners;
# if the ellipse is not a perfect circle, you'll have to
# compute both of the catheti
hyp = QtCore.QLineF(self.boundingRect().center(), localPos)
size = sqrt(2) * hyp.length()
rect = QtCore.QRectF(0, 0, size, size)
rect.moveCenter(self.rect().center())
self.parentItem().setRect(rect)
self.setRect(rect)
# update the positions of both handles
self.rotation_handle.setPos(self.rect().topLeft())
self.scaling_handle.setPos(self.rect().topRight())
return True
elif event.type() == QtCore.QEvent.GraphicsSceneMousePress:
# return True to the press event (which is almost as setting it as
# accepted, so that it won't be processed further more by the scene,
# allowing the sceneEventFilter to capture the following mouseMove
# events that the watched graphics items will receive
return True
return super(myRect, self).sceneEventFilter(source, event)
class Basic(QtGui.QMainWindow):
# ...
def initUI(self):
# ...
self.circle = self.this_scene.addEllipse(QtCore.QRectF(40, 40, 65, 65), QtGui.QPen(QtCore.Qt.black))
mr = myRect(self.circle)
self.this_scene.addItem(mr)
So I'm trying to learn animations in PyQt and throughout all the examples I can find online, they all seem to use the self.update() or self.repaint() methods to increment the animations. This means basically the code has to erase then redraw the entire widget for every frame, even though much of what I intend to animate is static.
For example the code below, this generates a circular progress pie. The important bit is the paint() method under ProgressMeter (first class): for every frame in the animation this example paints the background, the actual progress pie, and the percentage indicator.
If I change the code to something like:
if self.angle > 120:
# do not draw background
then after 120 frames, the background does not get drawn anymore.
This seems terribly inefficient because (logically) the background should only be drawn once, no?
What would you recommend for animations like these?
Addendum: I have lurked a lot on this site to steal examples and code, but haven't posted for a long time. Please let me know about proper etiquette etc if I am not following it properly.
import sys
from PyQt4 import QtGui, QtCore
class ProgressMeter(QtGui.QGraphicsItem):
def __init__(self, parent):
super(ProgressMeter, self).__init__()
self.parent = parent
self.angle = 0
self.per = 0
def boundingRect(self):
return QtCore.QRectF(0, 0, self.parent.width(),
self.parent.height())
def increment(self):
self.angle += 1
self.per = int(self.angle / 3.6)
if self.angle > 360:
return False
else:
return True
def paint(self, painter, option, widget):
self.drawBackground(painter, widget)
self.drawMeter(painter, widget)
self.drawText(painter)
def drawBackground(self, painter, widget):
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setPen(QtCore.Qt.NoPen)
p1 = QtCore.QPointF(80, 80)
g = QtGui.QRadialGradient(p1 * 0.2, 80 * 1.1)
g.setColorAt(0.0, widget.palette().light().color())
g.setColorAt(1.0, widget.palette().dark().color())
painter.setBrush(g)
painter.drawEllipse(0, 0, 80, 80)
p2 = QtCore.QPointF(40, 40)
g = QtGui.QRadialGradient(p2, 70 * 1.3)
g.setColorAt(0.0, widget.palette().midlight().color())
g.setColorAt(1.0, widget.palette().dark().color())
painter.setBrush(g)
painter.drawEllipse(7.5, 7.5, 65, 65)
def drawMeter(self, painter, widget):
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(widget.palette().highlight().color())
painter.drawPie(7.5, 7.5, 65, 65, 0, -self.angle * 16)
def drawText(self, painter):
text = "%d%%" % self.per
font = painter.font()
font.setPixelSize(11)
painter.setFont(font)
brush = QtGui.QBrush(QtGui.QColor("#000000"))
pen = QtGui.QPen(brush, 1)
painter.setPen(pen)
# size = painter.fontMetrics().size(QtCore.Qt.TextSingleLine, text)
painter.drawText(0, 0, 80, 80,
QtCore.Qt.AlignCenter, text)
class MyView(QtGui.QGraphicsView):
def __init__(self):
super(MyView, self).__init__()
self.initView()
self.setupScene()
self.setupAnimation()
self.setGeometry(300, 150, 250, 250)
def initView(self):
self.setWindowTitle("Progress meter")
self.setRenderHint(QtGui.QPainter.Antialiasing)
policy = QtCore.Qt.ScrollBarAlwaysOff
self.setVerticalScrollBarPolicy(policy)
self.setHorizontalScrollBarPolicy(policy)
self.setBackgroundBrush(self.palette().window())
self.pm = ProgressMeter(self)
self.pm.setPos(55, 55)
def setupScene(self):
self.scene = QtGui.QGraphicsScene(self)
self.scene.setSceneRect(0, 0, 250, 250)
self.scene.addItem(self.pm)
self.setScene(self.scene)
def setupAnimation(self):
self.timer = QtCore.QTimeLine()
self.timer.setLoopCount(0)
self.timer.setFrameRange(0, 100)
self.animation = QtGui.QGraphicsItemAnimation()
self.animation.setItem(self.pm)
self.animation.setTimeLine(self.timer)
self.timer.frameChanged[int].connect(self.doStep)
self.timer.start()
def doStep(self, i):
if not self.pm.increment():
self.timer.stop()
self.pm.update()
app = QtGui.QApplication([])
view = MyView()
view.show()
sys.exit(app.exec_())
The Qt's documentation about QWidget repaint slot says:
Repaints the widget directly by calling paintEvent() immediately, unless updates are disabled or the widget is hidden.
We suggest only using repaint() if you need an immediate repaint, for example during animation. In almost all circumstances update() is better, as it permits Qt to optimize for speed and minimize flicker.
Warning: If you call repaint() in a function which may itself be called from paintEvent(), you may get infinite recursion. The update() function never causes recursion.
That should give you an answer about when to use or not repaint or update slots.
About making animations I'd suggest you also to take a look to the Qt4's animation framework or Qt5's animation framework, which is a really powerful way to animate widgets on Qt.
I have the example code below, simplified from a larger project. I have been trying to make alpha channels work i have enabled blending and written a similar example using pygame which works. How ever setting up opengl to work with a glx context seems to stop blending from working, i have a feeling i need to enabel some parameter to the gl context setup but have not been able to find out what that parameter is.
Any suggestions on why this is not working, i have tried on two different machines one with high end radeon and another with an intel graphics card both do the same however.
#blending is not working any ideas why ?
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_ALPHA_SIZE, 1)
self.add_attribute(GLX.GLX_DOUBLEBUFFER, 0)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glShadeModel(GL_SMOOTH)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glLight(GL_LIGHT0, GL_POSITION, (0, 1, 1, 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)
glColor4f(1.0, 0.0, 0.0, 0.2)
glVertex2i(0, 1)
glIndexi(0)
glColor4f(0.0, 1.0, 0.0, 0.2)
glVertex2i(-1, -1)
glIndexi(0)
glColor4f(0.0, 0.0, 1.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()
It's not the OpenGL context missing something (at the point of creation I mean). You're simply not enabling blending. You need to add a glEnable(GL_BLEND); before drawing primitives that require blending.
BTW: Using 1 bit as minimum requirement for RGB channels can yield to undesired results. Use at least 5 bits (for 16 bit displays) or better yet 8 bits. Also you don't need an alpha channel on the main framebuffer for blending to work. So unless you want to create transparent windows on a compositor, then you should use 0 alpha bits on the window's framebuffer.