如何自动激活 tkinter simpledialog 弹出窗口 window?

How to auto-activate a tkinter simpledialog pop-up window?

我的一个 python 脚本中有这个功能,它会弹出一个 Tkinter 简单对话框屏幕来请求一些简单的用户输入。该功能有效。但是,它存在 2 个问题

  1. 它打开两个 windows,而我只需要一个。但是如果我删除 master = Tk() 我得到错误:

AttributeError: 'NoneType' object has no attribute 'winfo_viewable'

最好能在某一时刻找出其中一个,但我的主要问题然而是第二个:

  1. 每当出现简单对话框屏幕时,我必须先单击它才能激活它,这很烦人。为了修复它,我尝试了 here and here 提供的解决方案,但它们不起作用。第一个link对我一点作用都没有,第二个link帮我解除了master.Tk() window 到前面,但这不是我需要的。我需要简单的对话框 window 成为最顶层的 window 并且我需要它自动激活以便当我 运行 我的代码和屏幕弹出时我可以自动输入无需先点击它。

如有任何帮助,我们将不胜感激!

我的代码:

def getUser():
    master = Tk()
    newList2=str(newList).replace(", ","\n")
    for ch in ['[',']',"'"]:
        if ch in newList2:
            newList5=newList2.replace(ch,"")
    userNr=simpledialog.askinteger("Enter user number", newList2)
    chosenUsernr= userNr - 1
    global chosenUsernrdef
    chosenUsernrdef = chosenUsernr
    master.destroy()

我认为没有办法 lift/give 专注于它,但 askinteger 只是几个小部件的组合,因此您可以轻松地自己重新创建它。

import tkinter as tk
from tkinter import messagebox

class CustomAskInteger(tk.Tk):
    def __init__(self,  numbers):
        tk.Tk.__init__(self)

        self.value = None
        self.label = tk.Label(self, text=", ".join(map(str, numbers))).pack(fill="both", expand=True)
        self.entry = tk.Entry(self)
        self.button = tk.Button(self, text="Ok", command=self.get_number)

        self.entry.pack()
        self.button.pack()

    def get_number(self):
        """
        You can customize these error handlings as you like to
        """
        if self.entry.get():
            try:
                int(self.entry.get())
                self.value = self.entry.get()
                self.destroy()
            except ValueError:
                messagebox.showwarning("Illegal Value", "Not an integer.\nPlease try again.")
        else:
            messagebox.showwarning("Illegal Value", "Not an integer.\nPlease try again.")

要在您的代码中使用它,您可以这样做

def getUser():       
    newList2=str(newList).replace(", ","\n")
    askInteger = CustomAskInteger("Enter user number", newList2)
    #since it is a Tk() instance, you can do lift/focus/grab_set etc. on this
    askInteger.lift()
    askInteger.mainloop()
    userNr = askInteger.value

首先,感谢 Lafexlos 展示了如何通过重新创建 window 在 Tkinter simpledialog.askinteger() window 上应用 .lift() 和类似命令的解决方案作为 Tk() 实例。

对于那些正在寻找如何自动激活 Tk-window(这样您就不必在输入之前单击它)的人来说,似乎有多个选项。

最常见的解决方案似乎是使用 .focus().force_focus() 实现 here and here. However over here it seems those options may not work on (at least some versions of) Windows OS. This question shows a possible solution for those systems. Also, the previous solutions appear not to work on multiple versions of OS X. Based on the solution offered here,使用 Apple 的 osascript,我能够解决我的问题。

工作代码最终如下所示:

def getUser():
    master = Tk()
    newList2=str(newList).replace(", ","\n")
    for ch in ['[',']',"'"]:
        if ch in newList2:
            newList2=newList2.replace(ch,"")
    cmd = """osascript -e 'tell app "Finder" to set frontmost of process "Python" to true'"""
    def stupidtrick():
        os.system(cmd)
        master.withdraw()
        userNr=simpledialog.askinteger("Enter user number", newList2)
        global chosenUsernrdef
        chosenUsernr= userNr - 1
        chosenUsernrdef = chosenUsernr
    stupidtrick()
    master.destroy()

简化/通用解决方案:

import os
from tkinter import Tk
from tkinter import simpledialog

def get_user():
    root = Tk()
    cmd = """osascript -e 'tell app "Finder" to set frontmost of process "Python" to true'"""
    def stupid_trick():
        os.system(cmd)
        root.withdraw()
        new_window=simpledialog.askinteger("Title of window", "Text to show above entry field")
    stupid_trick()
    root.destroy()

get_user()

编辑:现在我正在弄清楚要寻找的解决方案似乎已经被多个帖子找到了。对于 OS X 上的那些想要在 Tkinter and/or python 的多个实例同时 运行 时激活特定 Tkinter window 的用户,您可能需要查看 here.