首页 > 解决方案 > 如何在 tkinter 中停止嵌套计算并关闭顶层窗口

问题描述

Toplevel在 tkinter 脚本中有一个窗口,其中包含两个对应于嵌套循环的进度条。我想在 Toplevel 窗口中添加一个停止按钮来终止执行并关闭 Toplevel 窗口而不是根。

from tkinter import Tk, Toplevel,Button,Label,TOP,BOTH,DoubleVar
from tkinter.ttk import Progressbar
import time 

root = Tk()
root.configure(bg='lightgray')
root.wm_title("Main")


progress_window = Toplevel()

progress_window.attributes('-topmost', 'true')
progress_window.configure(bg='lightgrey')
progress_window.wm_title("Progress")
progress_window_label = Label(root, text="")
progress_window.geometry('600x300')
progress_window_label.pack()

M=4 # outer loop
N=5 # inner loop

progress1_var=DoubleVar()
progress1bar=Progressbar(master=progress_window,variable=progress1_var,length=M)    
progress1bar.pack(side=TOP,ipady=5,fill=BOTH,expand=True)
progress1_var.set(0)
progress1bar.update()
progress1bar_label=Label(master=progress_window,text='Bar1',bg='lightgray')
progress1bar_label.pack(side=TOP,pady=5,fill=BOTH, expand=True)

progress2_var = DoubleVar()
progress2bar=Progressbar(master=progress_window,variable=progress2_var,length=N)
progress2bar.pack(side=TOP,ipady=5,fill=BOTH, expand=True)
​progress2_var.set(0)
progress2bar.update()
progress2bar_label=Label(master=progress_window,text='Bar2',bg='lightgray')
progress2bar_label.pack(side=TOP,pady=5,fill=BOTH, expand=True)

def _stop():
    return

stop_button=Button(master=progress_window, text="Cancel",command=_stop)
stop_button.pack(side=TOP,pady=5,fill=BOTH, expand=True)


​for t in range(M):

       ​progress1_var.set(t/M)
       ​progress1bar_label.config(text='Bar 1:   '+str(round((t+1)/M*100,3))+'%')
       ​progress1bar.update()

       ​progress2_var.set(0)
       ​progress2bar.update()
   ​
       ​for i in range(N):
           ​progress2_var.set(i/N)
           ​time.sleep(1.0) #Sleep to slow down execution and view progress window
           ​progress2bar_label.config(text='Bar 2:  '+str(round((i+1)/N*100,3))+'%')
           ​progress2bar.update()


​progress_window.destroy()
root.mainloop()

停止按钮出现在应该但不起作用的位置并停止执行。这必须是一个非常基本的错误,但我不知道如何纠正它。

标签: pythontkinter

解决方案


我做了一些修改,主要是添加了protocolforrootprogress_window.

我还创建了一个名为killed用于中断for循环的标志。我已将它们放在一个由after.

这阻止了TclError: Invalid command name .!toplevel.!label2

from tkinter import Tk, Toplevel, Button, Label, TOP, BOTH, DoubleVar
from tkinter.ttk import Progressbar
import time 

killed  =  False

root  =  Tk()
root.configure(bg = 'lightgray')
root.wm_title("Main")

root.update()

progress_window  =  Toplevel()

def stop():
    global killed
    killed = True
    progress_window.destroy()
    root.destroy()

# Added protocol controls for exit

root.protocol( "WM_DELETE_WINDOW", stop )
progress_window.protocol( "WM_DELETE_WINDOW", stop )

progress_window.attributes('-topmost', 'true')
progress_window.configure(bg = 'lightgrey')
progress_window.wm_title("Progress")
progress_window_label  =  Label(root, text = "")
progress_window.geometry('600x300')
progress_window_label.pack()

M = 4 # outer loop
N = 5 # inner loop

progress1_var = DoubleVar()
progress1bar = Progressbar(master = progress_window, variable = progress1_var, length = M)    
progress1bar.pack(side = TOP, ipady = 5, fill = BOTH, expand = True)
progress1_var.set(0)
progress1bar.update()
progress1bar_label = Label(master = progress_window, text = 'Bar1', bg = 'lightgray')
progress1bar_label.pack(side = TOP, pady = 5, fill = BOTH, expand = True)

progress2_var  =  DoubleVar()
progress2bar = Progressbar(master = progress_window, variable = progress2_var, length = N)
progress2bar.pack(side = TOP, ipady = 5, fill = BOTH, expand = True)

progress2_var.set(0)
progress2bar.update()

progress2bar_label = Label(master = progress_window, text = 'Bar2', bg = 'lightgray')
progress2bar_label.pack(side = TOP, pady = 5, fill = BOTH, expand = True)

def process():
    for t in range(M):
        if killed:
            break
        progress1_var.set(t/M)
        progress1bar_label.config(text = "Bar 1:    " + str( round( (t+1)/M*100, 3)) + "%")
        progress1bar.update()
        progress2_var.set(0)
        progress2bar.update()
        for i in range(N):
            progress2_var.set(i/N)
            time.sleep(1.0)
            if killed:
                break
            progress2bar_label.config(text = "Bar 2:    " + str( round( (i+1)/N*100, 3)) + "%")
            progress2bar.update()

stop_button = Button(master = progress_window, text = "Cancel", command = stop)
stop_button.pack(side = TOP, pady = 5, fill = BOTH, expand = True)

root.after( 1000, process )
root.mainloop()

推荐阅读