【问题标题】:unexpected behaviour of return_keyboard_events in PySimpleGUIPySimpleGUI 中 return_keyboard_events 的意外行为
【发布时间】:2019-06-20 10:00:03
【问题描述】:
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

当我运行上面的代码并执行鼠标点击操作时,我得到如下输出,正如预期的那样,

点击OK1按钮在控制台打印为:1

点击OK2按钮在控制台打印为:2

点击OK3按钮在控制台打印为:3

但是,当我执行键盘事件时,我通过键盘的 tab 键访问按钮,并通过键盘按该按钮上的 Enter ,它在所有这三个按钮上返回相同的键,

通过 tab 键一一访问这些按钮,然后在每个我得到结果时按 Enter,

OK1 按钮上按 Enter 键 在控制台中打印为:1

OK2 按钮上按 Enter 在控制台中打印为:1

OK3 按钮上按 Enter 键 在控制台中打印为:1

这不是预期的输出。我想要的它也应该像鼠标点击事件一样打印自己的键。

我的意图是什么:

  1. 当用户在 OK1 上按下 Enter 按钮时,它应该打印('Hello, OK1 pressed.')

  2. 当用户在 OK2 上按下 Enter 按钮时,它应该打印('Hello, OK2 pressed.')

  3. 当用户在 OK3 上按下 Enter 按钮时,它应该打印('Hello, OK3 pressed.')

  4. 当用户点击 OK1 时,应该打印('Hello, OK1 press.')

  5. 当用户点击 OK2 时,它应该打印('Hello, OK2 press.')

  6. 当用户点击 OK3 时,应该打印('Hello, OK3 press.')

如何做到这一点?

【问题讨论】:

  • 很高兴您提出这个问题。我仍在检查 Pyside2 (Qt) 是否在您按下 Enter 键时没有选择按钮。我看到了这种行为,但想验证它。无论作为答案提供的代码都适用于 Qt 和 tkinter。

标签: python-3.x pysimplegui


【解决方案1】:

我终于理解了这个问题并写了这个作为解决方案。它已变成该项目的Demo Program,因为人们确实希望 ENTER 键单击一个按钮,但 tkinter 和 Qt 似乎都不能以这种方式工作。他们使用空格键选择按钮。

此源代码适用于 PySimpleGUI 和 PySimpleGUIQt。只需在顶部使用正确的导入语句。

    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')

在以上所有代码中,实现此功能的部分包含在这 4 行代码中。将这些代码行添加到您的事件循环中,然后您的窗口将运行,这样 ENTER 键将单击一个按钮。其余的代码通过点击、布局等来做事。真正实现它的是这些语句。

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()

【讨论】:

  • 在我的情况下,在 Ubuntu 19.04 上,当按下回车按钮时,它的返回事件是 - Return:36 当我在事件检查中添加 ('\r', QT_ENTER_KEY1, QT_ENTER_KEY2, 'Return:36')条件它对我有用,但没有包含'Return:36'它不起作用。
  • 我在 Raspberry Pi 中运行上述程序,但在 Ubuntu 中工作时它在 RaspberryPi 中不起作用。在 Raspberry Pi 中,我收到错误消息:AttributeError: 'Button' object has no attribute 'Click'!
  • 在 GitHub 上回复了这些。 Pi问题一定是安装问题。你有一个旧的 pip 安装和旧的 PySimpleGUI.py 文件。无论如何,已发布说明以帮助您确定您的版本。如有疑问,请始终检查以确保您运行的是正确的东西。为每个人节省时间
【解决方案2】:

我不完全明白你的目标是什么。你想要什么行为?

当按钮获得焦点时,默认情况下按下返回键似乎不会触发按钮。空格键会。

下面是一些基于用户键盘输入单击按钮的代码。我认为这是您在我重新阅读您的问题几次后所描述的。

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()

如果您想使用键盘控制按钮,那么您要做的就是收集键盘按键,然后将它们转换为您想要的任何行为。

当按钮具有焦点(突出显示)时按 ENTER 不会产生按钮点击,空格键会。你可以在这个 tkinter 程序中看到这一点:

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()

[编辑 - 对编辑感到抱歉,但我正在尝试...]

【讨论】:

  • 似乎还使用键盘上的空格键而不是返回键来激活 tkinter 按钮。 PySimpleGUI 只能将返回键绑定到其中一个按钮,而不是全部。最后,可能值得在项目 GitHub 上打开一个 Issue 以获得更多想法
  • MikeyB,请查看我更新的问题,希望您能理解我的目标。您给出的示例非常适合鼠标单击事件并按预期返回:事件:1、事件:2 和事件:3。但是我想用键盘做同样的事情不仅仅是用鼠标。我希望当用户通过 Tab 键遍历 OK3 然后按 Enter 键时,我希望返回键为 3 但现在当我在所有这三个按钮上按 Enter 时,我得到的结果相同。如何做到这一点?感谢 MikeyB 的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 2020-03-01
  • 2018-01-07
  • 1970-01-01
  • 2010-10-03
  • 2015-06-01
  • 1970-01-01
相关资源
最近更新 更多