Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Embedded pyglet Widget
Forum Update on Monday, May 27th 2025

Embedded pyglet Widget

Scheduled Pinned Locked Moved Unsolved Qt for Python
qt for pythonpython
4 Posts 2 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    gadese
    wrote on last edited by
    #1

    Hi,

    I currently have a Pyglet window running a simple 3D scene (simple shapes moving in the scene). I would like to build a GUI around this window using PyQt. Ideally, I would have an embedded Widget showing the scene, and a bunch of buttons/sliders that would let me add or move objects in the scene. I've been searching for most of this week, but haven't really found anything to help me, apart from a few obscure forums threads for 2007 or 2009. Note that I am not an OpenGL expert.

    I have been trying to adapt this repo from 2013 and I've managed to make some progress, but I'm currently a bit stuck. I've been trying to display simple pyglet text through a custom PyQt widget, but the display isn't right. I know something is working because I can correctly change the scene's background color, but drawing text or shapes aren't working properly as you can see in the image below

    efae091d-a56f-45de-9863-a2004a803fab-image.png .

    I'm not sure what to look at next, any insight would be very appreciated. My code is below (it's pretty simple)

    """
    This module contains the definiton of a pyglet widget for a 
    PySide application: QPygletWidget
    It also provides a basic usage example.
    """
    import sys
    import pyglet
    pyglet.options['shadow_window'] = False
    pyglet.options['debug_gl'] = False
    from pyglet import gl
    from PyQt5 import QtCore, QtOpenGL, QtWidgets
    
    
    class ObjectSpace(object):
        """ Object space mocker """
        def __init__(self):
            # Textures and buffers scheduled for deletion the next time this
            # object space is active.
            self._doomed_textures = []
            self._doomed_buffers = []
    
    
    class Context(object):
        """
        pyglet.gl.Context mocker. This is used to make pyglet believe that a valid
        context has already been setup. (Qt takes care of creating the open gl
        context)
        _Most of the methods are empty, there is just the minimum required to make
        it look like a duck..._
        """
            # define the same class attribute as pyglet.gl.Context
        CONTEXT_SHARE_NONE = None
        CONTEXT_SHARE_EXISTING = 1
        _gl_begin = False
        _info = None
        _workaround_checks = [
            ('_workaround_unpack_row_length',
             lambda info: info.get_renderer() == 'GDI Generic'),
            ('_workaround_vbo',
             lambda info: info.get_renderer().startswith('ATI Radeon X')),
            ('_workaround_vbo_finish',
             lambda info: ('ATI' in info.get_renderer() and
                           info.have_version(1, 5) and
                           sys.platform == 'darwin'))]
    
        def __init__(self, context_share=None):
            """
            Setup workaround attr and object spaces (again to mock what is done in
            pyglet context)
            """
            self.object_space = ObjectSpace()
            for attr, check in self._workaround_checks:
                setattr(self, attr, None)
    
        def __repr__(self):
            return '%s()' % self.__class__.__name__
    
        def set_current(self):
            pass
    
        def destroy(self):
            pass
    
        def delete_texture(self, texture_id):
            pass
    
        def delete_buffer(self, buffer_id):
            pass
    
    
    class QPygletWidget(QtOpenGL.QGLWidget):
        """
        A simple pyglet widget.
        User can subclass this widget and implement the following methods:
            - on_init: called when open gl has been initialised
            - on_update: called every dt.
            - on_draw: called when paintGL is executed
            - on_resize: called when resizeGL is executed
        """
        def __init__(self, parent=None,
                     clear_color=(0.0, 0.0, 0.0, 1.0),
                     frame_time=32,
                     dt=16):
            """
            :param clear_color: The widget clear color
            :type clear_color: tuple(r, g, b, a)
            :param frame_time: The desired frame time [ms]
            :type: frame_time: int
            :param dt: The desired update rate [ms]
            :type: dt: int
            """
            QtOpenGL.QGLWidget.__init__(self, parent)
    
            # init members
            self._clear_color = clear_color
            self._dt = dt
            self.update_timer = QtCore.QTimer()
            self.draw_timer = QtCore.QTimer()
    
            # configure draw and update timers
            self.update_timer.setInterval(dt)
            self.update_timer.timeout.connect(self._update)
            self.draw_timer.setInterval(frame_time)
            self.draw_timer.timeout.connect(self.updateGL)
    
            # start timers
            self.update_timer.start()
            self.draw_timer.start()
    
        def _update(self):
            """
            Calls on_update with the choosen dt
            """
            self.on_update(self._dt)
    
        def on_init(self):
            """
            Lets the user initialise himself
            """
            pass
    
        def on_draw(self):
            """
            Lets the user draw his scene
            """
            pass
    
        def on_update(self, dt):
            """
            Lets the user draw his scene
            """
            pass
    
        def on_resize(self, w, h):
            """
            Lets the user handle the widget resize event. By default, this method
            resizes the view to the widget size.
            """
            gl.glViewport(0, 0, w, h)
            gl.glMatrixMode(gl.GL_PROJECTION)
            gl.glLoadIdentity()
            gl.glOrtho(0, w, 0, h, -1, 1)
            gl.glMatrixMode(gl.GL_MODELVIEW)
    
        def initializeGL(self):
            """
            Initialises open gl:
                - create a mock context to fool pyglet
                - setup various opengl rule (only the clear color atm)
            """
            # display = pyglet.canvas.get_display()
            # screen = display.get_default_screen()
    
            # template = pyglet.gl.Config()
            # config = screen.get_best_config(template)
            # context = config.create_context(None)
            # gl.current_context = context
            
            gl.current_context = Context()
            gl.glClearColor(0.5, 0.7, 1, 1)
            self.on_init()
    
        def resizeGL(self, w, h):
            """
            Resizes the gl camera to match the widget size.
            """
            self.on_resize(w, h)
    
        def paintGL(self):
            """
            Clears the back buffer than calls the on_draw method
            """
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.on_draw()
    
    
    class MyPygletWidget(QPygletWidget):
        def on_init(self):
            self.label = pyglet.text.Label('This is a pyglet label rendered in a Qt widget :)',
                              font_name='Times New Roman',
                              font_size=36,
                              x=180, y=200,
                              anchor_x='center', anchor_y='center')
    
            self.setMinimumSize(QtCore.QSize(640, 480))
    
        def on_draw(self):
            self.label.draw()
    
    class Window(QtWidgets.QMainWindow):
        def __init__(self):
            super().__init__()
            self.widget = MyPygletWidget()
            self.setCentralWidget(self.widget)
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.show()
        sys.exit(app.exec())
    
    
    if __name__ == "__main__":
        main()
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Did you already tried with using QOpenGLWidget ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • G Offline
        G Offline
        gadese
        wrote on last edited by gadese
        #3

        Yes I've tried QOpenGLWidget, and I get the same issue. The problem seems to be the pyglet integration and getting pyglet to use the OpenGL context created by QOpenGLWidget or QGLWidget rather than its own.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          I tested your sample code with a conda environment, latest PyQt5, pyglet from pip and while the text is not properly placed, it's rendered correctly.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved