Python方法奇怪地暂停,直到tkinter root被关闭

时间:2016-03-05 20:51:00

标签: python debugging tkinter destroy

我正在使用Python 3.4创建一个tkinter应用程序,它从API收集帖子,过滤它们并允许用户查看它们并为每个应用程序做出决定(忽略,删除,共享等)

用户需要选择日期和一些页面,然后单击“收集”按钮。程序然后从页面中获取帖子并将它们存储在“wholeList”中。 当用户点击第二个按钮“审核”时,必须过滤这些帖子并将其传递给Reviewer

我的问题是评论员根本没有收到任何帖子,Filterer也没有。我在某些地方添加了一些调试print()语句,特别是handlerCollect(),结果令我困惑,因此这篇文章。

当我点击'Collect'时,程序将其置于“DEBUG-> 1”和“DEBUG-> 2”之间的某个位置,而不是完成handlerCollect()回调方法。主窗口不会冻结或任何东西,因为我可以单击“查看”并打印“DEBUG-> 4”并打开Reviewer。当我关闭主窗口时,“DEBUG-> 0”“DEBUG-> 2”和“DEBUG-> 3”最后打印,同时执行handlerCollect()方法的其余部分。

handlerChoosePage()发生同样的行为,“DEBUG-> 0”被延迟,直到tkinter根(TK())被销毁。我对结构编程的了解告诉我它应该是第一个印刷的。相反,这是最后一次。我最好的结论是,我不能正确地结束我的Toplevel mainloop()。我不得不承认我以前从未遇到过这样的事情。我认为在mainloop()上结束Toplevels的正确方法是destroy(),我很困惑为什么调用mainloop()的方法会被搁置到Tk 1}} root被摧毁;不太实际。

Relevant part of my interface

from GUICollector import GUICollector as Collector

class Launcher(tk.Frame):
    def __init__(self, *args, **kwargs):

        ...
        self.allPagesCB     = Checkbutton(self.dateFrame, text="Collect for all pages",
            variable = self.allPagesVar, command=self.handlerChoosePage)
        self.collectBtn = Button(self, text="Collect", command=self.handlerCollect)
        self.reviewBtn  = Button(self, text="Review", command=self.handlerReview)

    def handlerChoosePage(self):
        if self.allPagesVar.get() == 0:
            child = tk.Toplevel(self)
            selector = PageSelector(self.toCollect, child)
            selector.pack(side="top", fill="both", expand=True)
            selector.mainloop()
            print("DEBUG->0")

    def handlerCollect(self):
        print("DEBUG->1")
        self.collect()
        print("DEBUG->4")
        for post in self.collector.getPosts():
            if post not in self.wholeList:
                print("...")
                self.wholeList.append(post.copy())
        self.collector = None
        print(len(self.wholeList), "posts in wholeList")

    def collect(self):
        window = tk.Toplevel(self)
        self.collector = Collector(self.toCollect, self.sinceEpoch, window)
        self.collector.grid(row=0,column=0)
        self.collector.after(500, self.collector.start)
        print("DEBUG->2")
        self.collector.mainloop() # This is what seems to hang indefinetly
        print("DEBUG->3")

    def handlerReview(self):
        print("DEBUG->5")
        print(len(self.wholeList), "posts in wholeList")
        filterer = Filterer(self.wholeList)
        self.wholeList = filterer.done[:]
        window = tk.Toplevel()
        reviewer = Reviewer(self.wholeList[:], window)
        reviewer.grid(row=0,column=0)
        reviewer.mainloop()

GUICollector模块根本不需要用户进行任何交互。 这个模块似乎工作得很好:完成它的工作,显示它已完成,然后在指定的延迟后关闭。 由于GuiCollector mainloop()似乎是悬挂的罪魁祸首,这就是我如何结束它:

class GUICollector(tk.Frame):

    def __init__(self, pagesList, since, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)

    def start(self, event=None):
        if some_logic:
            self.after(250,self.start)
        else:
            self.done() # Does get called.

    def done(self):
        # Some StringVar update to display we are done on screen
        self.after(1250, self.validate)

    def validate(self):
        self.master.destroy()

只需按一下按钮,即可通过相同的调用销毁PageSelector模块:self.master.destroy()

以下是该程序的重​​要输出:

DEBUG->1
DEBUG->2
=> collected data of page [PageName]
=> Found 3 posts in page 
DEBUG->5
0 posts in wholeList

[The main window (Launcher) is manually closed at this point]
DEBUG->3
DEBUG->4
...
...
...
3 posts in wholeList
DEBUG->0

2 个答案:

答案 0 :(得分:1)

mainloop 的概念假定您首先创建和初始化对象(好吧,至少是应用程序启动时需要的,即动态不使用的),设置事件处理程序(实现接口逻辑)和然后进入无限事件处理(用户界面本质上是什么),即主循环。所以,这就是为什么你会把它看成是#34;挂起"。这称为event-driven programming

重要的是,这个事件处理是在一个地方完成的,就像那样:

class GUIApp(tk.Tk):
   ...


app = GUIApp()
app.mainloop()

因此,当窗口死亡时,mainloop会返回。

答案 1 :(得分:0)

在我有时间重构代码之前,我通过在destroy()次调用中添加以下行来解决问题:

self.quit() # Ends mainloop
self.master.destroy() # Destroys master (window)

我理解这并不能解决我的代码的错误结构,但它回答了我的具体问题。 destroy()并未结束mainloop的{​​{1}},TopLevel也是如此。添加此行会使我的代码以可预测的方式执行。

一旦我重构了我的代码并验证他声称quit()主循环将涵盖所有孩子Tk(),我将接受@pmod的答案。