当 Tkinter 消息框等待用户响应时处理 Python 中的信号

Handle signal in Python when Tkinter messagebox is awaiting user response

我希望能够在 Tkinter 消息框(或类似消息框)打开并等待用户输入时处理信号。

我怎样才能调用处理程序并退出程序?

这是我试过的方法。当信号被触发时,消息框保持打开状态。

import signal
import sys
from tkinter import messagebox

def handler(signum, frame):
    print("STOP!")
    sys.exit(1)

signal.signal(signal.SIGINT, handler)

messagebox.showinfo("This is a message box", "This is a message")

使用 Toplevel window 创建您自己的消息框并使用 bind 来处理这种情况。

from tkinter import *
from tkinter import messagebox

def handler(frame):
    print("STOP!")
    sys.exit(1)

root = Tk()

top = Toplevel(root)
top.title("About this application...")
top.bind('<Control-c>', handler)
msg = Message(top, text="###################")
msg.pack()

button = Button(top, text="Dismiss", command=top.destroy)
button.pack()

root.mainloop()

event name list绑定!

from tkinter import *
from tkinter import messagebox

def handler(frame):
    print("STOP!")
    sys.exit(1)

root = Tk()
root.geometry("{0}x{1}".format(root.winfo_screenwidth()-3, root.winfo_screenheight()-3))

top = Toplevel(root, takefocus=True)
top.title("This is a message box")

w = top.winfo_reqwidth()
h = top.winfo_reqheight()
ws = top.winfo_screenwidth()
hs = top.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
top.geometry('%dx%d+%d+%d' % (300, 100, x, y))

top.attributes("-topmost", True)

top.bind('<Control-c>', handler)

lbl = Label(top, text="This is a message...")
lbl.pack(expand=True, fill='x')

button = Button(top, text="OK", command=top.destroy)
button.focus_set()
button.pack(pady=2)

root.mainloop()

如果您的程序引用了 Tk() 实例,例如 root = Tk(),则调用 root.destroy() 而不是 sys.exit(1):

import signal
from tkinter import Tk, messagebox

def handler(signum, frame):
    print("STOP!")
    #sys.exit(1)
    root.destroy()

signal.signal(signal.SIGINT, handler)

root = Tk()
messagebox.showinfo("This is a message box", "This is a message")

正如@varadaraju-g 所建议的,这里最好的方法似乎是从头开始创建一个消息框。绑定到键盘事件不符合我的要求,所以我需要使用信号。

这里的关键是确保这些信号在我们处于主循环中时得到实际处理。 This answer 引用 Guido 是关键,解释了如何使用 after() 定期调用虚拟函数来启用信号处理。

import signal
from tkinter import *

def handler(sig, frame):
    print("STOP!")
    sys.exit(1)

def show_message_box(title, text):

    root = Tk()

    root.withdraw()
    top = Toplevel(root)
    top.title(title)
    msg = Message(top, text=text)
    msg.pack()
    button = Button(top, text="Dismiss", command=root.destroy)
    button.pack()

    def signal_check():
        root.after(50, signal_check)

    root.after(50, signal_check)
    top.protocol("WM_DELETE_WINDOW", root.quit)
    root.mainloop()

    print("End of dialog")

signal.signal(signal.SIGINT, handler)
signal.signal(signal.SIGTERM, handler)

show_message_box(title="message box", text="hello world")