Tkinter Focus 在 askstring 后丢失

Tkinter Focus lost after askstring

我目前正在实施一个使用许多 tkinter 框架的程序,并且在打开子框架时我希望为用户锁定超框架(否则事情将无法解决)。经过一些研究,我发现 grab_set 和 grab_release 方法效果很好。

然而,一旦子框架(由 Toplevel 实例化)调用请求字符串,抓取就是 "losed" 并且用户可以再次与超层交互 window。一个例子是这样的(非常简化的代码):

import tkinter as tk
import tkinter.simpledialog

root = tk.Tk()
def open_sublevel():
    tl = tk.Toplevel(root)
    def ask():
        print(tk.simpledialog.askstring("askstring", "askstring"))
    tk.Button(tl, text="ask", command=ask).pack()
    tl.grab_set()
    root.wait_window(tl)
    tl.grab_release()
    print("release")


tk.Button(root, text="asdf", command=open_sublevel).pack()
tk.mainloop()

一旦用户通过单击 "asdf" 打开子框架,包含 "asdf" 的框架将在子框架打开期间被锁定。然而,一旦用户选择了子框架中的 "ask"-按钮,这个 "lock" 就会以某种方式消失。

根据tkinter库中的注释:

A grab directs all events to this and descendant widgets in the application.

到目前为止,我无法找到任何文档来解释为什么 grab_set() 在您提交完 askstring 后会消失,但我认为这是因为一旦小部件消失了grab_set() 掉下来了。就像您要关闭 Toplevel window.

在这种情况下,tl.grab_release() 似乎并不需要,因为一旦 window 关闭,抓取就会释放。

根据我的测试,如果您在 askstring 完成后重置 grab_set(),它仍然可以正常工作。

您只需在 print(tk.simpledialog.askstring("askstring", "askstring")) 下方添加 tl.grab_set()

修改后的代码如下:

import tkinter as tk
import tkinter.simpledialog

root = tk.Tk()

def open_sublevel():
    tl = tk.Toplevel(root)
    tl.grab_set()

    def ask():
        print(tk.simpledialog.askstring("askstring", "askstring"))
        tl.grab_set()

    tk.Button(tl, text="ask", command=ask).pack()
    print("release")

tk.Button(root, text="asdf", command=open_sublevel).pack()
tk.mainloop()

设置 simpledialog 的父项将使 simpledialog 获得焦点

x = simpledialog(parent = window_x, title = z etc.)

这将确保 x 获得焦点而不是退出