PySimpleGUI函数式创建多窗口时输入验证报错求助
解决PySimpleGUI双窗口函数式创建时的元素更新错误
问题场景
基于PySimpleGUI开发双窗口应用,采用函数式方法创建窗口并实现输入验证时,触发如下错误:
You cannot Update element with key = - until the window.read() is called or finalized
仅当不通过函数声明窗口时功能正常。
错误原因
- 跨窗口访问不存在的元素:每次主循环都执行
for key in validate_inputs: window[key].bind(...),但validate_inputs包含两个窗口的输入key,当当前window是window1时,不存在IN2对应的元素;当是window2时,不存在IN1对应的元素,导致尝试访问不存在的key触发错误。 - 重复绑定事件:每次循环都执行绑定操作,会导致同一事件被多次绑定,引发异常。
- key格式不匹配:
validate_inputs定义的是('IN1', 'IN2'),但窗口中输入框的key是'-IN1-'、'-IN2-',导致验证逻辑无法正确匹配事件。
解决方案
- 在窗口创建函数内完成事件绑定:每个窗口只绑定自身存在的输入框事件,避免跨窗口访问无效元素。
- 统一key格式:将
validate_inputs和窗口内的key统一为带短横线的格式(如'-IN1-'),确保事件匹配正确。 - 优化主循环逻辑:只处理当前窗口对应的事件和元素,避免无效操作。
修改后的完整代码
import PySimpleGUI as sg import re def select(element): element.Widget.select_range(0, 'end') element.Widget.icursor('end') def validate(text): result = re.match(regex, text) return False if result is None or result.group() != text else True regex = "^[+-]?([0-5](\.(\d{0,2}))?)?$" old = {'-IN1-':'0.00', '-IN2-':'0.00'} validate_inputs = ('-IN1-', '-IN2-') def make_window1(): layout = [ [sg.Text('Window 1')], [sg.Input(enable_events=True, k='-IN1-', default_text='0.00')], [sg.Text(size=(20,1), k='-OUTPUT-')], [sg.Button('Launch 2'), sg.Button('Exit')] ] window = sg.Window('Window 1', layout, finalize=True) # 仅绑定当前窗口存在的元素事件 window['-IN1-'].bind('<FocusIn>', ' IN') window['-IN1-'].bind('<FocusOut>', ' OUT') return window def make_window2(): layout = [ [sg.Text('Window 2')], [sg.Input(enable_events=True, k='-IN2-', default_text='0.00')], [sg.Button('Exit')] ] window = sg.Window('Window 2', layout, finalize=True) # 仅绑定当前窗口存在的元素事件 window['-IN2-'].bind('<FocusIn>', ' IN') window['-IN2-'].bind('<FocusOut>', ' OUT') return window def main(): window1, window2 = make_window1(), None while True: window, event, values = sg.read_all_windows() # 处理窗口关闭事件 if window == window1 and event in (sg.WIN_CLOSED, 'Exit'): break if window == window2 and event in (sg.WIN_CLOSED, 'Exit'): window2.close() window2 = None continue # 处理输入验证事件 if event in validate_inputs: element, text = window[event], values[event] if validate(text): try: v = float(text) if v > 5: element.update(old[event]) continue except ValueError: pass old[event] = text else: element.update(old[event]) # 处理焦点进入事件 elif event.endswith(' IN'): key = event.split()[0] if key in window.AllKeysDict: # 确保元素存在 select(window[key]) # 处理焦点离开事件 elif event.endswith(' OUT'): key = event.split()[0] if key in window.AllKeysDict: # 确保元素存在 text = values[key] try: v = float(text) window[key].update(f'{v:.2f}') old[key] = f'{v:.2f}' except ValueError: window[key].update('0.00') old[key] = '0.00' # 启动第二个窗口 elif event == 'Launch 2' and not window2: window2 = make_window2() window1.close() if window2 is not None: window2.close() if __name__ == '__main__': main()
关键修改点说明
- 将事件绑定从主循环移到每个窗口的创建函数中,确保只绑定当前窗口存在的元素。
- 统一了
old字典、validate_inputs和窗口输入框的key格式,避免匹配错误。 - 在处理焦点事件时,增加了
key in window.AllKeysDict的判断,确保只操作当前窗口存在的元素。 - 给输入框添加了
default_text,初始化值与old字典保持一致。
内容的提问来源于stack exchange,提问作者Amaru Carhuarupay
相关产品推荐
相关产品推荐

