代码之家  ›  专栏  ›  技术社区  ›  Flash_Steel

如何在函数期间禁用Tkinter列表框

  •  0
  • Flash_Steel  · 技术社区  · 6 年前

    我有一个用Python3.x创建的图形用户界面,使用的是来自Visual Studio 2017社区的Tkinter。创建一个顶部小部件,并在其中添加一个框架和列表框。当用户单击列表框中的条目时,所选内容的索引将传递给 twoSecondFunction() 大约需要2秒钟才能完成。

    在此期间,如何阻止用户进行其他选择?

    我试过用这条线 myListbox.config(state=tkinter.DISABLED) 若要在进行选择时禁用列表框,并且仅在 TwoSecondFunction() 已完成。

    当我从visual studio运行代码时 myListbox 单击事件由处理 myListboxSelection 以及“twosecondFunction()”和 print() 被称为。在 myListboxSelection() .

    如果用户在

    函数已完成

    已输出 MyListBox选择() 是另一次。

    在输出“Function Finished”(功能完成)之前,通过快速单击,我可以将超过10个命令排队。在所有排队事件的持续时间内,gui似乎没有响应,只有在执行所有排队的myListBoxSelection()调用后才会响应其他命令。

    我试过把线拔掉 myListbox.config(state=tkinter.NORMAL) 然后在程序运行期间只注册一次点击,所以 mylistbox.config(state=tkinter.disabled) 当它被调用时正在按它应该的方式工作。 MyListbox 也会变灰。

    我也增加了额外的 打印() 在整个程序中的行,以确保所有操作都按预期的顺序进行。

    似乎逻辑的执行速度比gui本身的响应快得多,所以 MyListbox 比gui的响应快得多。我看不见 MyListbox 在执行“twosecondFunction()”期间灰显。

    是因为 mylistbox.config(state=tkinter.disabled) 仅在事件处理程序完成其执行后生效?即。 mylistbox.config(state=tkinter.disabled) 从未生效,因为 mylistbox.config(state=tkinter.normal) 在之前设置 MyListbox 实际上是残疾?

    import tkinter #For the GUI tools
    
    #Event handler for mouse click of myListbox
    def myListboxSelection(event):
        myListbox.config(state=tkinter.DISABLED) #Disable myListbox
        myListboxIndex = int(myListbox.curselection()[0]) #Get selection index
        twoSecondFunction(myListboxIndex) #Call function that takes 2 seconds
        print("Function finished") #Output to console on completion
        myListbox.config(state=tkinter.NORMAL) #Enable Listbox
    
    #Create GUI
    GUITopWidget = tkinter.Tk(screenName = "myListboxGUI") #Create Top Level Widget
    myFrame = tkinter.Frame(GUITopWidget, name = "myFrame") #Create frame
    myFrame.pack() #Pass to Geometry Manager
    myListbox = tkinter.Listbox(authoritiesListFrame) #Create myListbox
    myListbox.bind('<<ListboxSelect>>', myListboxSelection) #Bind mouse click event
    populateListbox(myListbox) #Add entries to the listbox
    myListbox.pack() #Pass to Geometry Manager
    
    #Run the GUI loop
    GUITopWidget.mainloop() 
    
    0 回复  |  直到 6 年前
        1
  •  0
  •   Flash_Steel    6 年前

    如果您有一个事件处理程序并使用 mainloop() 它确实会在回调期间停止执行任何逻辑。相反,定义一个可以处理事件调用、其他逻辑和调用的循环 update() 在图形用户界面上手动:

    import tkinter #For the GUI tools
    
    rootWindowClosed = False
    requestQueued  = False #True request is queued
    myListboxIndex= -1 #Set to -1 between requests
    
    #Event handler for mouse click of myListbox
    def myListboxSelection(event):
        myListbox.config(state=tkinter.DISABLED) #Disable myListbox
        myListboxIndex = int(myListbox.curselection()[0]) #Get selection index
    
    #On closing of root window
    def closeGUIHandler():
        #Set the rootWindowClosed flag to True
        global rootWindowClosed
        rootWindowClosed = True
        #Destroy GUI Root
        GUITopWidget.destroy()
    
    #Create GUI
    GUITopWidget = tkinter.Tk(screenName = "myListboxGUI") #Create Top Level Widget
    GUITopWidget.protocol("WM_DELETE_WINDOW", closeGUIHandler) #Set delete window protocol
    myFrame = tkinter.Frame(GUITopWidget, name = "myFrame") #Create frame
    myFrame.pack() #Pass to Geometry Manager
    myListbox = tkinter.Listbox(authoritiesListFrame) #Create myListbox
    myListbox.bind('<<ListboxSelect>>', myListboxSelection) #Bind mouse click event
    populateListbox(myListbox) #Add entries to the listbox
    myListbox.pack() #Pass to Geometry Manager
    
    #Run the GUI loop
    while rootWindowClosed == False:
        #If requestQueued then execute queued request
        if requestQueued  == True:
            twoSecondFunction(myListboxIndex) #Call function that takes 2 seconds
            myListbox.config(state=tkinter.NORMAL) #Enable Listbox
            myListboxIndex = -1
    
        #Update GUI window if not closed
        time.sleep(0.05) #Sleep for 50 ms to allow event handling before executing code
        if rootWindowClosed == False:
            GUIRootWidget.update()