unexpected behaviour of return_keyboard_events in PySimpleGUI

Viewed 6931
import PySimpleGUI as sg

layout = [[sg.Button("OK1", key='1', bind_return_key=True)],
      [sg.Button("OK2", key='2', bind_return_key=True)],
      [sg.Button("OK3", key='3', bind_return_key=True)]]
window = sg.Window("Keyboard Test", return_keyboard_events=True).Layout(layout)
while True:
    event, values = window.Read()
    print(event)
    if event == None:
        break

When I run the above code and perform mouse click operation, I get the output as following that is as expected,

clicking on OK1 Button print in the console as: 1

clicking on OK2 Button print in the console as: 2

clicking on OK3 Button print in the console as: 3

But, when I perform keyboard event means, I visit on the button through tab key of keyboard and press Enter on that Button via keyboard it return the same key on all these three button,

Visit on these button one by one via tab key and then press Enter on each I get the result as,

Press Enter on OK1 Button print in the console as: 1

Press Enter on OK2 Button print in the console as: 1

Press Enter on OK3 Button print in the console as: 1

That is not expected output. What I want it should also print their own key same as mouse click event.

What is my intention:

  1. When user press Enter button over OK1, It should print('Hello, OK1 pressed.')

  2. When user press Enter button over OK2, It should print('Hello, OK2 pressed.')

  3. When user press Enter button over OK3, It should print('Hello, OK3 pressed.')

  4. When user click on OK1, It should print('Hello, OK1 pressed.')

  5. When user click on OK2, It should print('Hello, OK2 pressed.')

  6. When user click on OK3, It should print('Hello, OK3 pressed.')

How to achieve this?

2 Answers

I finally understood the question and wrote this as a solution. It's been turned into a Demo Program for the project because people do expect the ENTER key to click a button and yet tkinter and Qt both seem to not work this way. They select buttons using the spacebar.

This source code works for both PySimpleGUI and PySimpleGUIQt. Just use the correct import statement at the top.

    import PySimpleGUI as sg
    # import PySimpleGUIQt as sg

    QT_ENTER_KEY1 =  'special 16777220'
    QT_ENTER_KEY2 =  'special 16777221'

    layout = [  [sg.T('Test of Enter Key use')],
                [sg.In(key='_IN_')],
                [sg.Button('Button 1', key='_1_')],
                [sg.Button('Button 2', key='_2_')],
                [sg.Button('Button 3', key='_3_')],  ]

    window = sg.Window('My new window', layout,
                       return_keyboard_events=True)
    while True:             # Event Loop
        event, values = window.Read()
        if event is None:
            break
        if event in ('\r', QT_ENTER_KEY1, QT_ENTER_KEY2):         # Check for ENTER key
            elem = window.FindElementWithFocus()                            # go find element with Focus
            if elem is not None and elem.Type == sg.ELEM_TYPE_BUTTON:       # if it's a button element, click it
                elem.Click()
            # check for buttons that have been clicked
        elif event == '_1_':
            print('Button 1 clicked')
        elif event == '_2_':
            print('Button 2 clicked')
        elif event == '_3_':
            print('Button 3 clicked')

Out of all of the code above, the part that implements this feature is contained in these 4 lines of code. Add these lines of code to your event loop and then your window will behave such that the ENTER key will click a button. The rest of the code does things with the clicks, is the layout, etc. It's really these statements that implement it.

if event in ('\r', QT_ENTER_KEY1, QT_ENTER_KEY2):         # Check for ENTER key
    elem = window.FindElementWithFocus()                            # go find element with Focus
    if elem is not None and elem.Type == sg.ELEM_TYPE_BUTTON:       # if it's a button element, click it
        elem.Click()

I don't fully understand what your goal is. What behavior do you want?

When a button has the focus, pressing the return key doesn't seem to trigger buttons by default. The space bar will though.

Here is some code that will click a button based on a user's keyboard input. I THINK that was what you described after I re-read your question a few times.

import PySimpleGUI as sg

layout = [[sg.Button("OK1", key='_1_', )],
          [sg.Button("OK2", key='_2_', )],
          [sg.Button("OK3", key='_3_', )]]

window = sg.Window("Keyboard Test", layout, return_keyboard_events=True)

while True:
    event, values = window.Read()
    # window.Maximize()
    print('event: ', event)
    if event == None:
        break
    if event == '1':
        window.Element('_1_').Click()
    elif event == '2':
        window.Element('_2_').Click()
    elif event == '3':
        window.Element('_3_').Click()

window.Close()

If you want to control the buttons using the keyboard, then what you'll have to do is collect the keyboard key presses and then convert those into whatever behavior you want.

Pressing ENTER when a button has focus (is highlighted) does NOT generate a button click, a SPACE BAR does. You can see this demonstrated in this tkinter program:

import tkinter as tk


def write_slogan():
    print("Tkinter is easy to use!")


root = tk.Tk()
frame = tk.Frame(root)
frame.pack()

button = tk.Button(frame,
                   text="QUIT",
                   fg="red",
                   command=quit)
button.pack(side=tk.LEFT)
slogan = tk.Button(frame,
                   text="Hello",
                   command=write_slogan)
slogan.pack(side=tk.LEFT)

root.mainloop()

[EDIT - sorry about the edits but I'm experimenting... ]

Related