Как заставить окно Tkinter перейти на передний план?
Вопрос
Как мне заставить приложение Tkinter перейти на передний план?В настоящее время окно отображается позади всех моих других окон и не получает фокуса.
Есть ли какой-то метод, который я должен вызывать?
Решение
Предполагая, что вы имеете в виду окна вашего приложения, когда говорите "мои другие окна", вы можете использовать lift()
метод на Высшем уровне или Тз:
root.lift()
Если вы хотите, чтобы окно оставалось выше всех других окон, используйте:
root.attributes("-topmost", True)
Где root
это ваш Топовый уровень или Тз.Не забывайте о -
перед "topmost"
!
Чтобы сделать это временный, отключите самый верхний сразу после:
def raise_above_all(window):
window.attributes('-topmost', 1)
window.attributes('-topmost', 0)
Просто передайте окно, которое вы хотите вызвать в качестве аргумента, и это должно сработать.
Другие советы
Если вы делаете это на Mac, используйте AppleEvents, чтобы сфокусироваться на Python.Например:
import os
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
Добавьте следующие строки перед mainloop():
root.lift()
root.attributes('-topmost',True)
root.after_idle(root.attributes,'-topmost',False)
У меня это работает идеально.Это выводит окно на передний план при создании окна, и оно не всегда будет находиться на переднем плане.
Что касается Mac, я заметил, что может возникнуть проблема в том, что если запущено несколько графических интерфейсов python, каждый процесс будет называться "Python", а AppleScript будет стремиться вывести неправильный на передний план.Вот мое решение.Идея состоит в том, чтобы получить список идентификаторов запущенных процессов до и после загрузки Tkinter.(Обратите внимание, что это идентификаторы процессов AppleScript, которые, похоже, не имеют никакого отношения к своим аналогам posix.Поди разберись.) Тогда лишний человек будет твоим, и ты поставишь его на первое место.(Я не думал, что этот цикл в конце будет необходим, но если вы просто получаете каждый процесс с идентификатором 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''')
В 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()
Что-то вроде комбинации различных других методов, это работает на 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()
На 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, окно приложения остается позади.
Мое решение работает во всех случаях, с которыми я столкнулся.
Есть подсказка о том, как заставить окно 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.
Если окно, над которым вы хотели бы поднять свое целевое окно, известно, вы могли бы просто использовать tkraise
метод с помощью aboveThis
параметр, установленный для окна, которое вы хотите нарисовать поверх.
from tkinter import Tk, ttk, Toplevel
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.title('Main Window')
self.state('zoomed')
self.l1 = ttk.Label(self, text='Hello World!')
self.l1.pack()
self.s = Splash()
self.s.tkraise(aboveThis=self)
class Splash(Toplevel):
def __init__(self):
Toplevel.__init__(self)
self.title('Splash Screen')
self.lift()
app = App()
app.mainloop()