在外部循环中更新 Tkinter GUI

Posted

技术标签:

【中文标题】在外部循环中更新 Tkinter GUI【英文标题】:Update Tkinter GUI while in outside loop 【发布时间】:2019-04-16 21:15:44 【问题描述】:

我的代码设置为打印出来以控制它的进度,因为它循环了几千个项目。这工作得非常好,直到我将它打包并分发给其他人,因为不再有控制台。我当前的方法有效,但在循环继续运行时,GUI 在几次迭代后始终挂起。

下面的示例代码运行,但我的循环要复杂得多并且挂断了。我很好奇是否有更好的方法来实现这一点,因为我喜欢使用这些 GUI,但是当我处于不同的循环中时,我还没有找到一种将数据发送到 GUI 的好方法。

from tkinter import *
import time

def do_loop(num_cycles):
    for i in range(0, int(num_cycles)):
        time.sleep(.25)
        # print(i)
        GUI_MSG.set(str(i))
        Tk.update_idletasks(FORM)

FORM = Tk()
GUI_MSG = StringVar()
FORM.wm_title('Perform Element Analysis')

IO_FRAME = LabelFrame(FORM, text=' Input/Output Directories ')
IO_FRAME.grid(row=0, sticky='W', padx=5, pady=5, ipadx=5, ipady=5)

Label(IO_FRAME, text="Numer of Loops").grid(
    row=1, column=1, padx=5, pady=(10, 2), sticky='E')
NUMBER_LOOPS = Entry(IO_FRAME, width=10)
NUMBER_LOOPS.grid(row=1, column=2, columnspan=4)

Button(FORM, text='Generate Tables', command=lambda: do_loop(
    NUMBER_LOOPS.get())).grid(row=3, column=0, sticky='WE', padx=5, pady=5)

Label(FORM, textvariable=GUI_MSG).grid(row=2, sticky='WE', padx=5, pady=20)

FORM.mainloop()

【问题讨论】:

【参考方案1】:
time.sleep()

Sleep 会冻结 tkinter GUI,因此您无法在 GUI 运行时执行任何其他操作。如python文档中所述(https://docs.python.org/3/library/time.html#time.sleep)

在给定的秒数内暂停执行调用线程

考虑到您想要使用的输出,您会得到更好的服务

.after()

而且您可能真的不需要 update_idletasks()。看看这是否适合你:

 from tkinter import *

class myFormWindow():
   def __init__(self,FORM):
      self.count=0
      self.GUI_MSG = StringVar()
      self.FORM=FORM
      self.FORM.wm_title('Perform Element Analysis')

      IO_FRAME = LabelFrame(self.FORM, text=' Input/Output Directories ')
      IO_FRAME.grid(row=0, sticky='W', padx=5, pady=5, ipadx=5, ipady=5)

      Label(IO_FRAME, text="Numer of Loops").grid(
      row=1, column=1, padx=5, pady=(10, 2), sticky='E')
      self.NUMBER_LOOPS = Entry(IO_FRAME, width=10)
      self.NUMBER_LOOPS.grid(row=1, column=2, columnspan=4)
      Button(self.FORM, text='Generate Tables', command=self.get_cycles).grid(row=3, column=0, sticky='WE', padx=5, pady=5)
      Label(self.FORM, textvariable=self.GUI_MSG).grid(row=2, sticky='WE', padx=5, pady=20)



   def get_cycles(self):
      self.num_cycles=self.NUMBER_LOOPS.get()
      self.do_loop()

   def do_loop(self):
       if self.count<int(self.num_cycles):
       self.GUI_MSG.set(str(self.count))
       self.count+=1
       self.FORM.after(1000,self.do_loop)


if __name__=="__main__":
   FORM=Tk()
   form_window=myFormWindow(FORM)
   FORM.mainloop()

【讨论】:

这行得通,但理想情况下,循环将在课堂之外工作。正如我所说,我有相当广泛的函数集,这些函数没有意义包含在 GUI 类中。睡眠也仅用于示例。具体来说,我的代码所做的是它使用 GUI 让用户选择一组数据作为输入,它使用这些输入来创建断裂分析输入文件,然后使用 os.system(frac_analysis.exe )。 exe运行后,代码解析生成的文件,然后继续运行列表中的下一个文件。 太棒了,抱歉我没有按照你想要的行为。 .after() 可用于调用类外的函数。您将需要重新排列代码以适合您所需的行为。这个 NMT 文档 after doc 可能会有所帮助。【参考方案2】:

按照您问题的初始逻辑并使用.after() 在函数外部进行引用:

from tkinter import *

def do_loop():
     global count,num_cycles,GUI_MSG
     if count<int(num_cycles):
         GUI_MSG.set(str(count))
         count+=1
         FORM.after(1000,do_loop)

def get_cycles():
     global num_cycles
     num_cycles=NUMBER_LOOPS.get()
     do_loop()

count=0    
FORM = Tk()
GUI_MSG = StringVar()
FORM.wm_title('Perform Element Analysis')

IO_FRAME = LabelFrame(FORM, text=' Input/Output Directories ')
IO_FRAME.grid(row=0, sticky='W', padx=5, pady=5, ipadx=5, ipady=5)

Label(IO_FRAME, text="Numer of Loops").grid(
row=1, column=1, padx=5, pady=(10, 2), sticky='E')
NUMBER_LOOPS = Entry(IO_FRAME, width=10)
NUMBER_LOOPS.grid(row=1, column=2, columnspan=4)

Button(FORM, text='Generate Tables', command=get_cycles).grid(row=3, column=0, sticky='WE', padx=5, pady=5)

Label(FORM, textvariable=GUI_MSG).grid(row=2, sticky='WE', padx=5, pady=20)

FORM.mainloop()

【讨论】:

以上是关于在外部循环中更新 Tkinter GUI的主要内容,如果未能解决你的问题,请参考以下文章

可以在外部阶段列出文件但不能访问其中的文件?

在外部文本文件中查找字符串所在的行号

如何使用Python在外部控制台中编写/执行命令

Linux Shell编程(17)——嵌套循环

创建 web 应用程序的最佳方法,该应用程序在外部客户端调用他自己的休息服务时动态更新 UI [关闭]

微信网页中打开网址弹出引导页引导在外部浏览器中打开