在按钮的回调函数内从 for 循环访问数据时连续更新标签

Update label continuously while accessing data from a for loop inside a button's callback function

我认为这个问题会让我更改很多代码。

该程序基本上是一种遗传算法,可以找到给定函数的最佳解决方案并将它们绘制成几代人的图。

它只有一些输入和 运行 按钮。 运行按钮使用for循环输出两个列表中的数据,然后绘制它们

def run(self):
     
     b = []
     a = []
     self.ga = Ga()
     for i in range(self.generations):
         
         ga.run(self.v.get())
         b.append(ga.best().fitness) 
         a.append(ga.fitness_average)
     self.graph(a,b)

有没有一种方法可以在期间运行访问正在解析到列表中的数据并使用它们来不断更新标签?该算法可能需要一些时间才能 运行,我认为在屏幕上显示一些值,而 运行ning 将是一个不错的功能。

抱歉让您久等了,互联网中断了几个小时

希望评论能给你足够的理解,将其放入你的代码中并让它按照你想要的方式工作,但如果他们不这样做,请随时寻求帮助,这就是我的意思这里是

无论如何,我假设你的“运行”函数是 class 的一部分,因为 self 所以一定要改变目标线程适合

#----------------- NEED THESE BEFORE EVERYTHING ELSE BUT DON'T NEED THEM EXACTLY HERE(but can get rid of time import if you dont want to use it)
import threading
import time
gettingData = True
#----------------- NEED THESE BEFORE EVERYTHING ELSE BUT DON'T NEED THEM EXACTLY HERE(but can get rid of time import if you dont want to use it)want to use it

def run(self):
     
    b = []
    a = []
    self.ga = Ga()
    while gettingData:
      time.sleep(1) #without this, it will be looping as soon as it finishes, which may use too many resources
      ga.run(self.v.get())
      b.append(ga.best().fitness) 
      a.append(ga.fitness_average)
      self.graph(a,b)

#threading stuff, just starts a new thread and continues along with its day
thread = threading.Thread(target=whateverThisClassIsCalled.run) 
thread.start()

#continue with other code you want to use as the while loop in "run" will now be constantly running

如果您想随时停止循环:

gettingData = False #this stops the while loop which will allow your thread to run through the function to completion
#you can add a thread.join() after gettingData if you wish to wait for the thread to close(it to stop appending and graphing etc) before executing code coming after

虽然 multi-threading 可能是 tkinter 应用程序的出路,但 tkinter 本身不是 thread-safe,并且从其他线程发出的事件或对 tkinter 的调用可能会导致奇怪的错误。

这可以在单个线程中 运行 - 问题是 tkinter 默认情况下不会更新屏幕上的任何内容,直到您的长 run 函数结束并恢复控制到 tkinter 循环。

但是,随时更新屏幕所需要做的就是在您的小部件或 top-level 个小部件上调用 .update() 方法。

由于您的函数进行计算,因此在其中调用 hard-code“window.update()”并不是一个好的设计。相反,将可选的“更新”回调传递到您的“运行”函数的设计将更加优雅,并允许相同的函数与其他界面一起使用 运行 作为文本用户界面程序终端、Qt 或 GTK 等其他图形用户界面工具包,甚至是 Web 应用程序。

我很想写这个例子的“工作代码”,但是因为你没有 post 一个独立的例子,我不能花时间写一个 tkinter UI带有要从头开始更新的标签。

当我写下面的代码片段时,我看到你的“运行”应该是一个方法。 post 在提问时自包含最小的、完整的、可执行的示例,而不是脱离上下文的函数。如果您的应用程序被组装为 class,那么 update 可能是一个方法,而不是我上面描述的作为参数传递的回调。

想法是这样的:

import tkinter as tk

class Mistery:
    def __init__(mistery_instance):
 
        # code to create the main window assigned
        # to "selfroot", the needed widgets, and an 
        # action that will trigger the "run"
        # function
        self.root = tkinter.Tk()  
        """you did not show your code. A lot of 
 over 15 year old documentation suggest inheriting
 your own class
 from "tk.Tk" and build your app on that class - 
that definetelly is not a good 
thing to do: there are _hundreds_ of methods on
 a tkinter class that would 
name-clash with your methods and you would never
 know it. Just associate
 your widet as an 
attribute as in the line above
        """
        self.label1 = ...
        self.label2 = ...
        # code to create the remainder of the UI
        # and at some point, create a callback to execute "self.run"
        ...
    

 
    def update(self,a, b):
        #code to set the display entries in label1 and label2
        ...
        root.update()  # <- this ensures the window is repainted with the new values


    def run(self, update_interval=100):
        
        b = []
        a = []
        self.ga = Ga()
        for i in range(self.generations):
            
            ga.run(self.v.get())
            b.append(ga.best().fitness) 
            a.append(ga.fitness_average)
            if i % update_interval == 0:
                self.update(a, b)
        self.graph(a,b)

m = Mistery()
tkinter.mainloop()