Home > Software engineering >  pysimplegui read blocks main thread
pysimplegui read blocks main thread

Time:01-05

I'm trying to create a simple GUI program as a status indicator for an automation script. The GUI will be running in the background (but be visible) and be updated as the some data gets processed. I started with pysimplegui because it was much easier to understand. However, I noticed that running read blocks the main thread. This causes issues because the program is supposed to process keyboard inputs (using pynput) if required. The keylogger which is on a separate thread works fine, but the main thread is halted so no changes are worked on. How do I fix this, so that the main runs as usual and only occasionally updates the GUI window?

Here's the code I've written as of yet:

main.py

from src.components import gui, logger
from pynput import keyboard


def on_press(key):
    try:
        global start
        start = True
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))


if __name__ == "__main__":
    start = False

    listener = keyboard.Listener(on_press=on_press)
    listener.start()

    image_window = gui.create_image_window()
    gui.welcome_window(image_window)

    image_window.read()

    # This does not run. The read() blocks the program here 
    while not start:  
        print("Something")

gui.py

import PySimpleGUI as sg
import base64

icon = base64.b64encode(open('./src/resources/paper-clip.png', 'rb').read())


def create_text_window():
    sg.theme('DarkBlack1')
    layout = [[sg.Text("Example", key="-TEXT-")]]
    return sg.Window(title="Example", layout=layout, resizable=False, size=(500, 300), keep_on_top=True,
                     icon=icon, titlebar_icon=icon, margins=(0,0), element_padding=(0,0), finalize=True)


def create_image_window():
    image = sg.Image(size=(500, 300), key="-IMAGE-")
    layout = [[image]]
    return sg.Window(title="Example", layout=layout, resizable=False, size=(500, 300), keep_on_top=True,
                     icon=icon, titlebar_icon=icon,margins=(0,0), element_padding=(0,0), finalize=True)


def welcome_window(window):
    image = sg.Image("./src/resources/paper-clip.png",size=(500, 300))
    window['-IMAGE-'].update(filename="./src/resources/example.png")
    window.Refresh()

CodePudding user response:

Example code to demo how thread working with GUI in main thread, using method write_event_value of Window to generate event to main thread.

from pynput import keyboard
import PySimpleGUI as sg


def on_press(key, window):
    try:
        global start
        start = True
        print('alphanumeric key {0} pressed'.format(key.char))
    except AttributeError:
        print('special key {0} pressed'.format(key))
    window.write_event_value('KEY', key)

def create_window():
    layout = [[sg.Image(key="-IMAGE-"), sg.Text("Wait the key pressed !", size=25, key='Status')]]
    return sg.Window("Title", layout=layout, finalize=True)

def welcome_window(window):
    window['-IMAGE-'].update(data=sg.EMOJI_BASE64_HAPPY_LAUGH)
    window.Refresh()

start = False

window = create_window()
welcome_window(window)

listener = keyboard.Listener(on_press=lambda key, win=window:on_press(key, win))
listener.start()

while True:

    event, values = window.read()

    if event == sg.WIN_CLOSED:
        break
    elif event == 'KEY':
        key = values[event]
        window['Status'].update(f"'{key}' key pressed !")

listener.stop()
window.close()
  • Related