簡體   English   中英

在按鈕回調函數內的 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)

有沒有辦法可以運行時訪問被解析到列表中的數據並使用它們來不斷更新 Label ? 該算法可能需要一些時間才能運行,我認為在運行時在屏幕上顯示一些值將是一個不錯的功能。

抱歉讓您久等了,網絡中斷了幾個小時

希望評論能給你足夠的理解,將它放入你的代碼中,並讓它按照你想要的方式工作,但如果他們沒有,請隨時尋求幫助,這就是我在這里的目的

無論如何,我假設你的“運行”函數是一個類的一部分,因為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

雖然多線程可能是 tkinter 應用程序的出路,但 tkinter 本身不是線程安全的,並且從其他線程進行的事件或對 tkinter 的調用可能會導致奇怪的錯誤。

這可以在單個線程中運行 - 問題是 tkinter 默認情況下不會更新屏幕上的任何內容,直到您的長時間run功能結束並且控制恢復到 tkinter 循環。

但是,隨時更新屏幕所需要做的就是在您的小部件或頂級小部件上調用.update()方法。

由於您的函數進行計算,因此在其中硬編碼“window.update()”調用不是一個好的設計。 相反,將可選的“更新”回調傳遞給“運行”函數的設計將更加優雅,並允許與終端中的文本用戶界面程序、其他 gui 工具包(如 Qt 或GTK,甚至是 Web 應用程序。

我很想寫這個例子的“工作代碼”,但由於你沒有發布一個自包含的例子,我不能花時間寫一個帶有標簽的 tkinter UI 從頭開始​​更新。

當我寫下面的代碼片段時,我看到你的“運行”應該是一種方法。 在提問時發布自包含的最小、完整、可執行的示例,而不是脫離上下文的函數。 如果您的應用程序是作為一個類組裝的,那么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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM