使用 PySimpleGUI,如何在光标不自动移动到下一个元素的情况下 运行 一个 'FocusOut' 事件?

Using PySimpleGUI, how do I run a 'FocusOut' event without the cursor moving to the next element automatically?

我附上了一个使用 PySimpleGUI 的大型程序的摘录。我正在使用 FocusOut 来测试输入框中是否输入了任何内容(或者是否选择了日期)。每个测试本身都能很好地提供弹出消息,然后将焦点返回到空元素。添加第二个和第三个 etc 元素时会出现问题。然后,如果您未能在第一个元素中输入内容,您会在焦点返回到第一个之前获得 2 或 3 个连续的弹出窗口。显然,缺少某些东西会使每个元素在触发下一个事件之前完成其事件。任何帮助将不胜感激。

enter code here

from datetime import date

import PySimpleGUI as sg

TodayDt=date.today()
print("Today's date is " + str(TodayDt))


layout=[
        
[sg.T("Today's date is:"),sg.InputText(TodayDt, size=(10, 10), key='_TODAYCAL_')],
[sg.T("Select new transaction date:"),sg.CalendarButton('Calendar',  target='-IN4-', key='_DATE_',format='%Y-%m-%d'),sg.In(key='-IN4-', size=(10,1))],
[sg.T("Fuel quantity (in litres):"),sg.In(key="_FUELQUANT_",size=(10,1),enable_events=True),sg.T("Fuel amount N$:"),sg.In(key="_FUELAMNT_", size=(10,1),enable_events=True)],
[sg.T("Oil quantity (in millilitres:"),sg.In(key="_OILQUANT_",size=(10,1)),sg.T("Oil amount N$:"),sg.In(key="_OILAMNT_",size=(10,1))],
    
]

window = sg.Window('My Vehicle Logbook', layout, finalize=True)

iFuelQuant=window['_FUELQUANT_']
iFuelQuant.bind('<FocusOut>','FOCUS OUT')
fFuelAmnt=window['_FUELAMNT_']
fFuelAmnt.bind('<FocusOut>','FOCUS OUT')
dNewDt=window['-IN4-']
dNewDt.bind('<FocusOut>','FOCUS OUT')

while True:
    event, values = window.read()

    if event == sg.WIN_CLOSED or event == 'Cancel':     # if user closes window or clicks cancel
        break

    
    if event=='-IN4-FOCUS OUT':

        text=values['-IN4-']
        print(text)

        if text=='':
            sg.popup("Warning","You haven't selected a date")

            window.find_element('_DATE_')
            window.find_element('_DATE_').SetFocus()
            continue

    if event=='_FUELQUANT_' and values['_FUELQUANT_']:

        try:

            fFuelQuant=float(values['_FUELQUANT_'])
            fFuelQuant="{: .2f}".format(float(fFuelQuant))#(in_as_float)
            print(fFuelQuant)

        except:

            if len(values['_FUELQUANT_'])== 1 and values['_FUELQUANT_'][0]=='-':

                sg.popup()

                continue

            window['_FUELQUANT_'].update(values['_FUELQUANT_'][:-1])



    
    if event=='_FUELQUANT_FOCUS OUT':

        try:

            fFuelQ = (values['_FUELQUANT_'])
            fFuelQ = "{: .2f}".format(float(fFuelQ))
            window.find_element('_FUELQUANT_').update(fFuelQ)
                
            print(fFuelQ)
            continue    

        except:

            if len(fFuelQ) == 0:
                sg.popup("Warning!!!","You have not entered a fuel quantity")
                #window.find_element('_FUELQUANT_').refresh('')
                window.find_element('_FUELQUANT_').SetFocus()
                #continue
    
    if event=='_FUELAMNT_' and values['_FUELAMNT_']:

        try:

            fFuelAmnt=float(values['_FUELAMNT_'])
            fFuelAmnt="{: .2f}".format(float(fFuelAmnt))#(in_as_float)
            print(fFuelQuant)

        except:

            if len(values['_FUELAMNT_'])== 1 and values['_FUELAMNT_'][0]=='-':

                sg.popup()

                continue

            window['_FUELAMNT_'].update(values['_FUELAMNT_'][:-1])

    if event=='_FUELAMNT_FOCUS OUT':

        try:

            fFuelAmnt = (values['_FUELAMNT_'])
            fFuelAmnt = "{: .2f}".format(float(fFuelAmnt))
            window.find_element('_FUELAMNT_').update(fFuelAmnt)
                
            print(fFuelAmnt)
            continue

        except:

            if len(fFuelAmnt) == 0:
                sg.popup("Warning!!!","You have not entered a fuel amount")

                #window.find_element('_FUELQUANT_').refresh('')
                window.find_element('_FUELAMNT_').SetFocus()
                #continue

    

window.close()

FocusIn, FocusOut

The FocusIn and FocusOut events are generated whenever the keyboard focus changes. A FocusOut event is sent to the old focus window, and a FocusIn event is sent to the new one. In addition, if the old and new focus windows do not share a common parent, “virtual crossing” focus events are sent to the intermediate windows in the hierarchy. Thus a FocusIn event indicates that the target window or one of its descendants has acquired the focus, and a FocusOut event indicates that the focus has been changed to a window outside the target window's hierarchy.

The keyboard focus may be changed explicitly by a call to focus, or implicitly by the window manager.

所以当你调用sg.popupsg.set_focus时会产生focus out事件,然后事件会一次又一次地产生,这就是弹出window一次又一次显示的原因.

这是演示它的短代码,五个输入,但只有第二个和第三个检查它为空条目。

import PySimpleGUI as sg

def popup(*args, elem=None):
    for element in elements:
        element.unbind('<FocusOut>')
    window.refresh()                        # Make unbind effect
    layout = [
        [sg.Text('\n'.join(args))],
        [sg.Button('OK')],
    ]
    sg.Window('Popup', layout).read(close=True)
    if elem:
        elem.set_focus()
        window.refresh()                    # Make set_focus effect
    for element in elements:
        element.bind('<FocusOut>','+FOCUS OUT')

layout=[[sg.Input(key=f'-IN{i}-')] for i in range(5)]

window = sg.Window('My Vehicle Logbook', layout, finalize=True)
keys = ('-IN1-', '-IN2-')
elements = [window[key] for key in keys]
for element in elements:
    element.bind('<FocusOut>','+FOCUS OUT')

while True:
    event, values = window.read()

    if event == sg.WIN_CLOSED or event == 'Cancel':     # if user closes window or clicks cancel
        break
    elif event.endswith("+FOCUS OUT"):
        print(event)
        key = event.split('+')[0]
        if values[key] == '':
            popup("Warning", f"Blank entry in {key} is not accept !", elem=window[key])

window.close()