PYSimpleGUI点击按钮时输入框未触发FOCUSOUT事件的解决方法
解决PySimpleGUI输入框点击按钮时未触发FocusOut事件的问题
原问题代码
import PySimpleGUI as sg def dialog(): layout = [[sg.Text("Value1:",size=(5,1)), sg.I(key="-VALUE1-",size=(10,1),focus=True)], [sg.Text("Value2:", size=(5, 1)), sg.I(key="-VALUE2-", size=(10, 1),focus=True)], [sg.Text("",size=(5,1)),sg.OK(key="-OK-"),sg.B("Show",key="-SHOW-"),sg.Cancel(key="-CANCEL-")]] window = sg.Window("Inputdialog", layout,modal=True,finalize=True) window.Element("-VALUE1-").SetFocus() window["-VALUE1-"].bind('<FocusOut>', 'FOCUS OUT') window["-VALUE2-"].bind('<FocusOut>', 'FOCUS OUT') while True: event, values = window.read() print(event) if event in (sg.WIN_CLOSED, "-CANCEL-"): break if event in ("-SHOW-"): print(values) if event in ("-OK-"): return values window.close() result = dialog()
问题说明
输入框之间按Tab键切换时,会正常生成FocusOut事件;但光标处于输入框中直接点击按钮时,当前输入框的FocusOut事件不会触发,需要强制触发该事件。
解决方案
方法1:通过焦点转移触发事件
添加一个隐藏控件,点击按钮时让该控件获取焦点,迫使当前输入框失去焦点从而触发FocusOut。修改后的代码如下:
import PySimpleGUI as sg def dialog(): # 新增隐藏文本框用于接收焦点 layout = [[sg.Text("Value1:",size=(5,1)), sg.I(key="-VALUE1-",size=(10,1),focus=True)], [sg.Text("Value2:", size=(5, 1)), sg.I(key="-VALUE2-", size=(10, 1))], [sg.Text("",size=(5,1)),sg.OK(key="-OK-"),sg.B("Show",key="-SHOW-"),sg.Cancel(key="-CANCEL-")], [sg.Text("", key="-HIDDEN-", visible=False)]] window = sg.Window("Inputdialog", layout,modal=True,finalize=True) window.Element("-VALUE1-").SetFocus() window["-VALUE1-"].bind('<FocusOut>', 'FOCUS OUT') window["-VALUE2-"].bind('<FocusOut>', 'FOCUS OUT') def trigger_focus_out(): # 让隐藏控件获取焦点,触发当前输入框的FocusOut window["-HIDDEN-"].set_focus() while True: event, values = window.read() print(event) if event in (sg.WIN_CLOSED, "-CANCEL-"): trigger_focus_out() break if event in ("-SHOW-", "-OK-"): trigger_focus_out() if event == "-SHOW-": print(values) else: return values window.close() result = dialog()
方法2:直接模拟触发FocusOut事件
利用Tkinter的事件生成方法,直接给当前获焦的输入框发送<<FocusOut>>事件,无需额外控件。修改后的代码如下:
import PySimpleGUI as sg def dialog(): layout = [[sg.Text("Value1:",size=(5,1)), sg.I(key="-VALUE1-",size=(10,1),focus=True)], [sg.Text("Value2:", size=(5, 1)), sg.I(key="-VALUE2-", size=(10, 1))], [sg.Text("",size=(5,1)),sg.OK(key="-OK-"),sg.B("Show",key="-SHOW-"),sg.Cancel(key="-CANCEL-")]] window = sg.Window("Inputdialog", layout,modal=True,finalize=True) window.Element("-VALUE1-").SetFocus() window["-VALUE1-"].bind('<FocusOut>', 'FOCUS OUT') window["-VALUE2-"].bind('<FocusOut>', 'FOCUS OUT') def trigger_focus_out(): # 获取当前获焦的输入框 focused_elem = window.find_element_with_focus() if focused_elem and focused_elem.Key in ("-VALUE1-", "-VALUE2-"): # 直接触发FocusOut事件 focused_elem.Widget.event_generate('<<FocusOut>>') while True: event, values = window.read() print(event) if event in (sg.WIN_CLOSED, "-CANCEL-"): trigger_focus_out() break if event in ("-SHOW-", "-OK-"): trigger_focus_out() if event == "-SHOW-": print(values) else: return values window.close() result = dialog()
方案说明
- 方法1逻辑简单,兼容性强,通过焦点转移的原生行为触发事件;
- 方法2更贴近原生事件触发逻辑,无需额外添加控件,代码更简洁。
内容的提问来源于stack exchange,提问作者Phil De Blanck
相关产品推荐
相关产品推荐

