Как автоматически активировать всплывающее окно tkinter simpledialog?

У меня есть эта функция внутри одного из моих скриптов на Python, который выдает простое диалоговое окно Tkinter, чтобы запросить некоторый простой ввод данных пользователем. Функция работает. Однако есть 2 проблемы с этим.

  1. Он открывает два окна, пока все, что мне нужно, это одно. Но если я удаляю master = Tk(), я получаю ошибку:

AttributeError: у объекта 'NoneType' нет атрибута 'winfo_viewable'

Было бы неплохо в один момент понять это, но моя главная проблема, однако, вторая:

  1. Всякий раз, когда появляется простой диалоговый экран, я должен сначала щелкнуть его, прежде чем он активируется, что раздражает. Чтобы исправить это, я попробовал решения, предлагаемые здесь и здесь, но они не работают. Первая ссылка для меня ничего не сделала, вторая ссылка помогла мне поднять окно master. Tk () вперед, но это не то, что мне нужно. Мне нужно, чтобы простое диалоговое окно стало самым верхним окном, и мне нужно, чтобы оно автоматически активировалось, чтобы при запуске моего кода и всплывающем экране я мог автоматически набирать его, не нажимая сначала на него.

Любая помощь будет принята с благодарностью!

Мой код:

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()

2 ответа

Решение

Во-первых, кредиты для Lafexlos за показ решения о том, как подать заявку .lift() и аналогичные команды в окне Tkinter simpledialog.askinteger() путем воссоздания такого окна как экземпляр Tk().

Тем не менее, для тех, кто ищет автоматическую активацию Tk-окна (чтобы вам не приходилось нажимать на него, прежде чем вы сможете ввести его), существует несколько вариантов.

Наиболее распространенным решением является использование .focus() или же .force_focus() как видно, реализовано здесь и здесь. Однако здесь кажется, что эти опции могут не работать (по крайней мере, в некоторых версиях) ОС Windows. Этот вопрос показывает возможное решение для этих систем. Кроме того, предыдущие решения, похоже, не работают на нескольких версиях OS X. Основываясь на предложенном здесь решении, используя osascript от Apple, я смог решить свою проблему.

Рабочий код в конечном итоге выглядит так:

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, когда несколько экземпляров Tkinter и / или python работают одновременно, вы можете посмотреть здесь.

Я не думаю, что есть способ поднять / уделить внимание этому, но 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
Другие вопросы по тегам