Search code examples
pythonpython-3.xwindowspyglet

How to remove objects (labels, graphics) from the screen when using batched rendering?


I am building a demo program in Pyglet that uses serial output to read and update objects on the screen.

import pyglet
import output_parser as parse

port = input("Serial port ? (examples:COM3, /dev/ttyUSB0) ")
ser = parse.serial.Serial(port=port, baudrate=115200)

ser.write('exit\r'.encode('utf-8'))

# Test is ser working
ser.isOpen()

##########################################################
def update(self):
    #Some code here to obtain output and treat data
    #
    #
    if posTiles and negTiles:
        global finalcoords
        finalcoords = findCoords(poscoords, negcoords, wide)
        global canvas
        canvas[0].vertices = finalcoords
        if uid:
            global uid_label
            uid_label = pyglet.text.Label(text=str(uid),
                                          font_name='Times New Roman',
                                          font_size=24,
                                          x=finalcoords[0]+wide,
                                          y=finalcoords[5],
                                          color=(0,0,250,255),
                                          batch=batch, group=text)
    else:
        if canvas:
            try:
                canvas[0].vertices = zero
                uid_label.delete()
            except:
                pass
######################################################
try:
    config = pyglet.gl.Config(double_buffer=True)
    window = pyglet.window.Window(1280, 720, resizable=True, config=config)

    window.set_minimum_size(640, 480)

    batch = pyglet.graphics.Batch()
    plate = pyglet.graphics.OrderedGroup(0)
    connect = pyglet.graphics.OrderedGroup(1)
    text = pyglet.graphics.OrderedGroup(2)

    cells = {}
    canvas = {}
    cells[0] = Cell(x[0],y[0],l, global_id[0:4])

    canvas[0] = batch.add(4, pyglet.gl.GL_QUADS, connect, ('v2f', zero))

    @window.event
    def on_draw():
        window.clear()
        batch.draw()

    @window.event
    def on_deactivate():
        ser.close()

    #window.push_handlers(pyglet.window.event.WindowEventLogger())

    pyglet.clock.schedule_interval(update, 1/240)

    pyglet.app.run()

finally:
    window.close()
    ser.close()

The update() function checks for changes in the serial output and draws appropriate shapes in the pyglet window. I also want the update() function to remove the uid_label from the screen when there is no real output from the serial port. This image shows how the program works - you can see the canvas object as the white rectangle, and "3004" as being the label.

However, when there is no output from the serial port (no values for posTiles and negTiles), the label object still remains: Image, even though I have called uid_label.delete() on it.

So, my question is - how do I make the label on the screen disappear? uid_label.delete() does not seem to work, since the label is still in memory and shows on the screen even after window.clear() and batch.draw(). Unless I understand this incorrectly, an object that is removed from a batch should not be redrawn on the window.

I had the same issue before when trying to make the canvas[0] object appear and disappear, but I found a workaround by setting the vertices to zero. However, I cannot do that with a label, and ideally I would like to also add and delete objects as the program goes, and not have to store their vertices and set them to zero when I need.


Solution

  • Actually, .delete() does work. Here's a minimal example (based on your code) that does the trick:

    import pyglet
    
    canvas = {}
    
    try:
        config = pyglet.gl.Config(double_buffer=True)
        window = pyglet.window.Window(1280, 720, resizable=True, config=config)
        window.set_minimum_size(640, 480)
    
        batch = pyglet.graphics.Batch()
    
        canvas[1] = pyglet.text.Label("Moo", x=10, y=10, batch=batch)
    
        @window.event
        def on_draw():
            window.clear()
            batch.draw()
    
        @window.event
        def on_key_press(symbol, modifiers):
            # As soon as a key is pressed, we delete the batch objects (all of them)
            for index in list(canvas):
                canvas[index].delete()
                del(canvas[index])
    
        pyglet.app.run()
    
    finally:
        window.close()
    

    Press any key and it should make the label disappear.
    One issue you've might have had when you tried this, is that there's nothing in your code that actually refreshes the graphical area.

    Which would give the illusion that nothing has happened. Anytime you use batch.add(...) it will return a vertices object in which you have do delete() on. Same goes for sprites.