0

I have a GUI based on PySimpleGUI (PySimpleGUI 3.4.2., Python 3.7.2, macOS Mojave 10.14.6) that works fine except buttons seem to be firing although disabled.

Users listen to 3 consecutive sounds and give a rating in my GUI by clicking a button. While the user listens to the sounds, the buttons are disabled so that a response cannot be given until all sounds are over. The buttons are greyed out successfully in the GUI (window.FindElement(button_label).Update(disabled=False)). However, if one presses a disabled button, the GUI then takes this response in as soon as the buttons are enabled (as if the response event was queued), even though no button was pressed after enabling the buttons, which messes up the GUI (e.g. an accidental double click is considered as the responses to two sets of 3 sounds.)

I've tried to find answers, but I haven't found any for PySimpleGUI. I have tried different ways to pause the code during sound presentation (sd.wait and time.sleep) just in case the buttons were enabled in the background somehow while the sound was played. I've tried to mess around with the events that are read in to work around the issue, but to no avail. I have had trouble with enabling these buttons with the .Update() approach before and only got the buttons to grey out once I added the window.Refresh() line. I somehow have to ensure that the buttons are not taking any inputs while disabled.

This is example code that is severely condensed from the real version. It is a working version in which the response buttons are disabled for 3 seconds after providing a response and all collected responses are printed. This visualises that buttons collect responses while being disabled.

import PySimpleGUI as sg
import time

response_buttons = ['b1', 'b2', 'b3', 'b4', 'b5']
current_event=[]
layout = [[sg.Button('start', key='start')],
            [sg.Button('text5', key='b5')],
            [sg.Button('text4', key='b4')],
            [sg.Button('text3', key='b3')],
            [sg.Button('text2', key='b2')],
            [sg.Button('text1', key='b1')]]
window = sg.Window('GUI test').Layout(layout).Finalize()
for button_label in response_buttons:
    window.FindElement(button_label).Update(disabled=True)
window.Refresh()

while True:
    # Read the Window
    event, values = window.Read()
    print(event)
    if event is None:
        break
    # Take appropriate action based on button
    if event == 'start':
        window.FindElement('start').Update(disabled=True)
        for button_label in response_buttons:
            window.FindElement(button_label).Update(disabled=False)
        window.Refresh()
    if event in response_buttons:
        # collect and store response
        current_event = current_event + [event]
        # disable the buttons during sound presentation
        for button_label in response_buttons:
            window.FindElement(button_label).Update(disabled=True)
        window.Refresh()
        time.sleep(3)
        for button_label in response_buttons:
            window.FindElement(button_label).Update(disabled=False)

The goal is that a user can press a button once after listening to the sounds, then all buttons are disabled until the next set of sounds is over. Double-clicking a button and clicking a button while disabled will not result in a registered response.

Sas
  • 1
  • 1
  • 2

1 Answers1

1

Your logic is not good. You're not setting the state of the buttons correctly after a text button is pressed. I stripped out all the sound stuff and just left the GUI so we're only looking at that and only that.

The problem came in when you clicked a Text button. Look at your code... the last thing you do in that if block was to ENABLE all the Text buttons. They should have been left disabled and the Start button should be enabled.

Here's a working demo that I believe sets the button states the way you want. First only Start is enabled. If clicked, it is disables and the Text buttons enabled. All that was working fine.

import PySimpleGUI as sg

response_buttons = ['b1', 'b2', 'b3', 'b4', 'b5']
current_event=[]
layout = [[sg.Button('start', key='start')],
            [sg.Button('text5', key='b5')],
            [sg.Button('text4', key='b4')],
            [sg.Button('text3', key='b3')],
            [sg.Button('text2', key='b2')],
            [sg.Button('text1', key='b1')]]
window = sg.Window('GUI test').Layout(layout).Finalize()
for button_label in response_buttons:
    window.FindElement(button_label).Update(disabled=True)
window.Refresh()

while True:
    # Read the Window
    event, values = window.Read()
    if event is None:
        break
    # Take appropriate action based on button
    if event == 'start':
        window.FindElement('start').Update(disabled=True)
        for button_label in response_buttons:
            window.FindElement(button_label).Update(disabled=False)
        window.Refresh()
    if event in response_buttons:
        # collect and store response
        current_event = current_event + [event]
        # disable the buttons during sound presentation
        for button_label in response_buttons:
            window.FindElement(button_label).Update(disabled=True)
        window.Refresh()
        window.FindElement('start').Update(disabled=False)
window.Close()

Mike from PSG
  • 5,312
  • 21
  • 39
  • Hi, thanks for your response. I think I didn't explain the GUI well enough. Basically you only press start at the very beginning to start the experiment. Then sounds are presented and you give a rating with one of the text buttons, which automatically starts the presentation of the next sound in the callback. That's why the start button is not enabled again. In general it LOOKS like the buttons are doing exactly what I want, except that disabled buttons still register responses in my code. – Sas Sep 03 '19 at 07:16
  • When you run my code, do the buttons do the right thing? Also, when I disable them, are they disabled on your computer? When you click one of the "disabled buttons" in my code, does it do anything? In other words, does my program work as you would expect it to work (where your program does not work the way you expect)? If so, you've got a bug plain and simple. – Mike from PSG Sep 03 '19 at 21:41
  • Oh, and I already told you what your bug is. You are re-enabling your buttons at the end of your if block. After the timer window.FindElement(button_label).Update(disabled=False). That re-enabled all your buttons that you wanted disabled. – Mike from PSG Sep 03 '19 at 21:42
  • No, that's exactly what I want the code to do. I don't want the user to have to press Start for every new repetition (sound presentation). A response to one of the text buttons automatically starts the next repetition (sound presentation) during which the buttons are disabled and once the sound is finished playing the buttons automatically enable. This is desired. Your code successfully disables the buttons, however, pressing start every time is not an option and shouldn't be required. – Sas Sep 04 '19 at 15:28
  • Then you need to call Read again. I don't believe comments are the best place to troubleshoot this problem. The GitHub Issues are the right place to move it. – Mike from PSG Sep 04 '19 at 20:56