TkMessageBox 在点击确定后没有关闭的问题

8
我已经用Python编写了一个脚本,可以在给定事件发生时通知我。 我正在使用以下函数来生成警告窗口:
def window_warn():
    '''
    This function will throw up a window with some text
    '''
    #These two lines get rid of tk root window
    root = Tkinter.Tk()
    root.withdraw()
    #tkMessageBox.deiconify() 
    TkMessageBox.showwarning("New Case", "You have a new case\n Please restart pycheck")
    return

窗口可以正常显示,但是当我点击“确定”按钮后,窗口仍然停留在原地并且按钮处于按下状态。我使用的是xfce。 有没有办法让窗口在“确定”按钮被点击后关闭? 评论中提到这可能与周围的代码有关,为了完整起见:
print "Just started newcase check"
while True:
    if "Uncommitted" in webpage:
        print "oh look, 'Uncommitted' is in the url returned from the last function"
        #If this hits we call a notification window
        window_warn()
        print "sleeping"
        time.sleep(10)

        webpage = scrape_page()
    else:
        print "nothing"
        time.sleep(20)
        webpage = scrape_page()

我刚刚添加了调用上下文函数的代码。 - Rqomey
此外,当我在交互式 shell 中运行它时,它可以正常工作。不确定是否因为我没有捕获返回的“ok”。 - Rqomey
5个回答

9

在函数返回之前尝试调用 root.update()。 这将处理所有挂起的Tk/X窗口事件。

(理想情况下,在显示窗口之前建立一个主事件循环,但这假定您的整个程序都是基于事件驱动的,这可能并不总是有效。)


谢谢,这似乎正是我需要的! - Rqomey
抱歉,您能解释一下主事件循环是什么意思吗?该程序每分钟扫描一个网页。 - Rqomey
Tkinter程序通常(但并非总是)由Tk“在顶部”和您的代码通过回调运行组成 - 即,您首先设置Tk部分,调用mainloop,然后等待Tk调用您,通常是响应用户与程序交互。但对于您的情况来说,这可能有点不切实际。 - Fredrik
啊,是的。这样就清楚多了。谢谢! - Rqomey

0
我是这样做的:
import Tkinter as tk
import tkMessageBox
root = tk.Tk()
root.withdraw()
t = tkMessageBox.askyesno ('Title','Are you sure?')
if t:
    print("Great!!!")
    root.update()
else:
    print("Why?")
    root.update()

0
另一个解决方案是跟踪是否发生了tk.messagebox,如果发生了,就使用break/continue/pass来跳过重复出现的tk.messagebox
Flag = False
if Flag: 
    messagebox.showerror("Error", "Your massage here.")
    Flag = True
else:
    break

我提出这个方案是因为我在StackOverflow上遇到了其他解决方案的问题,因为我没有专门的root.mainloop(),而只有类Root()中的self.mainloop()
我的根看起来像这样,消息事件在一些内部类中生成,在那里我无法访问self.root
    class Root(tk.Tk):
        def __init__(self):
            tk.Tk.__init__(self)
            ....
            class 1..
            class 2..
            self.mainloop()

0
一个问题是你的代码每次调用函数window_warn时都会创建一个新的Tk元素。这可能不是导致你的问题的原因,但创建多个Tk元素是一种应该避免的不良做法。例如,在开始时初始化根元素,然后只保留对showwarning的调用。
root = Tkinter.Tk()
root.withdraw()

def window_warn():
    '''This function will throw up a window with some text'''
    tkMessageBox.showwarning("New Case", "You have a new case\n Please restart pycheck")
    return

print "Just started newcase check"
while True:
    # ...

我理解你的观点。如果我在函数外部调用root,那么我就无法在函数内部使用root.update()来运行它。也许我设置得有问题,应该先加入一个初始运行部分来启动root = Tkinter.Tk()。暂时来说,在终端框中运行似乎工作得很好(没有重复出现的窗口)。 - Rqomey
如果函数中的代码在同一模块内定义(这在Python中被称为“全局”变量,尽管它只对同一模块内的代码直接可见),则仍然可以访问root。不过,我认为重新创建Tk根窗口并没有什么大问题。 - Fredrik

0

你需要调用 root.mainloop() 来使程序响应事件。


所以我在tkmb.showwarning("New Case", "You have a new case")之后立即调用了root.mainloop(),但它似乎只是挂起了,没有做任何事情。需要以某种特定的方式调用吗?谢谢。 - Rqomey
必须在打开对话框之前运行,因为打开对话框会阻塞,直到对话框关闭。 - Bryan Oakley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接