Как заставить окно Tkinter перейти на передний план?

Как заставить приложение Tkinter перейти на передний план? В настоящее время окно появляется за всеми моими другими окнами и не фокусируется.

Есть какой-то метод, который я должен вызывать?

12 ответов

Решение

Предполагая, что вы имеете в виду окна своего приложения, когда говорите "другие мои окна", вы можете использовать lift() метод на топлевел или тк:

root.lift()

Если вы хотите, чтобы окно оставалось выше всех других окон, используйте:

root.attributes("-topmost", True)

куда root это ваш Toplevel или Tk. Не забывайте - перед "topmost"!

Чтобы сделать его временным, отключите самый верхний сразу после:

def raise_above_all(window):
    window.attributes('-topmost', 1)
    window.attributes('-topmost', 0)

Просто перейдите в окно, которое вы хотите поднять в качестве аргумента, и это должно сработать.

Добавьте следующие строки перед mainloop():

root.lift()
root.attributes('-topmost',True)
root.after_idle(root.attributes,'-topmost',False)

Это прекрасно работает для меня. Когда окно генерируется, оно выходит вперед, и оно не будет всегда оставаться впереди.

Если вы делаете это на Mac, используйте AppleEvents, чтобы сфокусироваться на Python. Например:

import os

os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')

Что касается Mac, я заметил, что может быть проблема в том, что если запущено несколько графических интерфейсов Python, каждый процесс будет называться "Python", а AppleScript будет стремиться выдвинуть неправильный текст вперед. Вот мое решение. Идея состоит в том, чтобы получить список ID запущенных процессов до и после загрузки Tkinter. (Обратите внимание, что это идентификаторы процессов AppleScript, которые, по-видимому, не имеют отношения к их аналогам posix. Поймите.) Тогда странный человек будет вашим, и вы переместите его вперед. (Я не думал, что цикл в конце будет необходим, но если вы просто получите каждый процесс, чей ID является procID, AppleScript, очевидно, возвращает один объект, идентифицируемый по имени, что, конечно, является неуникальным "Python", поэтому мы вернемся к исходной точке, если я что-то упустил.)

import Tkinter, subprocess
def applescript(script):
    return subprocess.check_output(['/usr/bin/osascript', '-e', script])
def procidset():
    return set(applescript(
        'tell app "System Events" to return id of every process whose name is "Python"'
        ).replace(',','').split())
idset = procidset()
root = Tkinter.Tk()
procid = iter(procidset() - idset).next()
applescript('''
    tell app "System Events"
        repeat with proc in every process whose name is "Python"
            if id of proc is ''' + procid + ''' then
                set frontmost of proc to true
                exit repeat
            end if
        end repeat
    end tell''')

В некоторой степени это комбинация различных других методов, это работает на OS X 10.11 и Python 3.5.1, работающих в venv, и должно работать на других платформах. Он также нацелен на приложение по идентификатору процесса, а не по имени приложения.

from tkinter import Tk
import os
import subprocess
import platform


def raise_app(root: Tk):
    root.attributes("-topmost", True)
    if platform.system() == 'Darwin':
        tmpl = 'tell application "System Events" to set frontmost of every process whose unix id is {} to true'
        script = tmpl.format(os.getpid())
        output = subprocess.check_call(['/usr/bin/osascript', '-e', script])
    root.after(0, lambda: root.attributes("-topmost", False))

Вы называете это прямо перед mainloop() позвони, вот так:

raise_app(root)
root.mainloop()

В Mac OS X PyObjC предоставляет более чистый и менее подверженный ошибкам метод, чем выделение в osascript:

import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps

app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)

Недавно у меня был такой же вопрос на Mac. Я объединил несколько ответов, используя @MagerValp для Mac и @D K для других систем:

import platform

if platform.system() != 'Darwin':
    root.lift()
    root.call('wm', 'attributes', '.', '-topmost', True)
    root.after_idle(root.call, 'wm', 'attributes', '.', '-topmost', False)
else:
    import os
    from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps

    app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
    app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)

root.mainloop()

Есть подсказка о том, как заставить окно Tkinter сфокусироваться при вызове mainloop() в функции Tkinter._test().

# The following three commands are needed so the window pops
# up on top on Windows...
root.iconify()
root.update()
root.deiconify()
root.mainloop()

Это самый чистый и правильный способ, который я нашел для этого, но он нужен только для систем Windows.

Этот ответ - заставить одно окно Tkinter всплывать поверх других окон Tkinter.

В моем приложении большое окно toplevel который вызывает гораздо меньшее окно top2 который изначально появляется поверх toplevel.

Если пользователь нажимает в toplevel окно фокусируется и гораздо меньше задыхается top2 окно до toplevel окно оттаскивается от него.

Решение - нажать кнопку в toplevel запускать top2еще раз. Вtop2 Функция open знает, что она уже запущена, поэтому просто поднимает ее наверх и фокусирует:

def play_items(self):
    ''' Play 1 or more songs in listbox.selection(). Define buttons:
            Close, Pause, Prev, Next, Commercial and Intermission
    '''

    if self.top2_is_active is True:
        self.top2.focus_force()     # Get focus
        self.top2.lift()            # Raise in stacking order
        root.update()
        return                      # Don't want to start playing again

В macOS High Sierra, py3.6.4, вот мое решение:

def OnFocusIn(event):
    if type(event.widget).__name__ == 'Tk':
        event.widget.attributes('-topmost', False)

# Create and configure your root ...

root.attributes('-topmost', True)
root.focus_force()
root.bind('<FocusIn>', OnFocusIn)

Идея состоит в том, чтобы вынести это на передний план, пока пользователь не будет взаимодействовать с ним, то есть сфокусироваться.

Я попробовал принятый ответ, .after_idle(), а также .after(), Все они терпят неудачу в одном случае: когда я запускаю свой скрипт прямо из IDE, такой как PyCharm, окно приложения остается позади.

Мое решение работает во всех случаях, с которыми я столкнулся.

Еще одна строка (необходима для Python 3.11 и tkinter 8.6):

      def lift_window(window):
    window.attributes('-topmost', True)
    window.update_idletasks()  # get window on top
    window.attributes('-topmost', False)  # prevent permanent focus 
    window.focus_force()  # focus to the window

Это поднимет окно вперед, а также сфокусирует внимание на окне.

      def lift_window(window):
    window.attributes('-topmost',True)
    window.attributes('-topmost',False) # disable the topmost attribute after it is at the front to prevent permanent focus 
    window.focus_force() # focus to the window
Другие вопросы по тегам