从另一个模块更新tkinter窗口

时间:2015-08-21 11:22:55

标签: python tkinter

我有一段代码可以进行一些文本分析,并在tkinter窗口中显示结果。 由于用户可以选择对多个源进行相同的分析,这可能需要相当长的时间,因此我希望在结果可用时显示结果。 但是,只有在最后一个结果可用后才会弹出tkinter窗口。从Stackoverflow上的其他问题,我理解为什么这不起作用(我的代码的简化版本):

class Output:
    def __init__(self):
        self.set_main_variables()

    def set_main_variables(self):
        self.names= []
        #and other variables...

    def initialize(self):
        self.t = Tk()
        self.make_frames()
        self.populate_frames()
        self.t.mainloop()

    def update(self):
        self.populate_frames()

    def populate_frames(self):
        <uses the data in self.names to display the results>

output = Output()
for i, s in enumerate(sources):
    results = analyze(s)
    output.names = results
    if i == 0:
        output.initialize()
    else:
        output.update()

因此,我尝试将initialize()从循环中取出,并在窗口中创建一个按钮,用户可以通过该按钮更新结果(如果有的话):

output = Output()
first_results = analyze(s[0])
output.names = first_results
output.initialize()

for i, s in enumerate(sources):
    results = analyze(s)
    output.names = results

但这并没有解决问题;只有在分析完最后一个来源后,窗口才会弹出。

我已经阅读了许多可能的选项来处理这个问题(使用after,guiloop等),但我不知道这些可以在这种情况下如何帮助我。

有人能让我走上正确的道路吗?

1 个答案:

答案 0 :(得分:0)

一位同事找到了我的问题的解决方案。

埃里克在评论中提到了我正确的道路。他建议在GUI中使用update_idletasks(),但这不起作用:它打开了一个空白窗口,只有在“sources”循环完成时才会填充小部件。 解决方案是将update()放在GUI内部,但放在将更新发送到GUI的循环中。 工作代码的简化示例:

from tkinter import *

class SimpleTestClass:
    def __init__(self):
        self.names = []
        self.top = Tk()
        self.names_string = StringVar()
        self.label = Label(self.top, textvar=self.names_string).pack()
        #self.top.mainloop()

    def updateLabel(self):
        self.names_string.set("\n".join(self.names))


def test(gui):
    names = ["a", "b", "c"]
    sources = [11, 2, 3]
    for i, s in enumerate(sources):
        print(i)
        gui.names.append(names[i])
        print(gui.names)
        gui.updateLabel()
        gui.top.update()
        #gui.top.update_idletasks() 
        time.sleep(3) # this simulates the program taking /
                      # some time to do its analysis of the source

s = SimpleTestClass()
test(s)

两个注释:

  • 使用update_idletasks()也可以,但显示一个奇怪的黑色 窗口底部的边框,直到源循环为止 完了。
  • 调用self.top.mainloop()阻止窗口更新

我还尝试了一个替代版本,用户可以按下按钮手动更新结果列表,但这不能很好地工作(按钮仅在完成源循环时才会响应):

class SimpleTestClass:
    def __init__(self):
        self.names = []
        self.top = Tk()
        self.names_string = StringVar()
        self.label = Label(self.top, textvar=self.names_string).pack()
        Button(self.top, text="update", command=self.updateLabel).pack()

    def updateLabel(self):
        self.names_string.set("\n".join(self.names))


def test(gui):
    names = ["a", "b", "c"]
    sources = [11, 2, 3]
    for i, s in enumerate(sources):
        gui.names.append(names[i])
        print(gui.names)
        gui.top.update()
        time.sleep(3) # this simulates the program taking /
                      # some time to do its analysis of the source

s = SimpleTestClass()
test(s)
相关问题