Comment faire en sorte qu'une application Tkinter passe au premier plan? Actuellement, la fenêtre apparaît derrière toutes mes autres fenêtres et ne reçoit pas le focus.
Y a-t-il une méthode que je devrais appeler?
En supposant que vous entendiez les fenêtres de votre application lorsque vous dites "mes autres fenêtres", vous pouvez utiliser la méthode lift()
sur un Toplevel ou un Tk:
root.lift()
Si vous voulez que la fenêtre reste au-dessus de toutes les autres fenêtres, utilisez:
root.attributes("-topmost", True)
Où root
est votre Toplevel ou Tk. N'oubliez pas le -
en face de "topmost"
!
Pour le rendre temporaire , désactivez en haut à droite après:
def raise_above_all(window):
window.attributes('-topmost', 1)
window.attributes('-topmost', 0)
Passez simplement dans la fenêtre que vous voulez soulever comme argument, et cela devrait fonctionner.
Si vous le faites sur un Mac, utilisez AppleEvents pour mettre en évidence Python. Par exemple:
import os
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
Ajoutez les lignes suivantes avant le mainloop ():
root.lift()
root.attributes('-topmost',True)
root.after_idle(root.attributes,'-topmost',False)
Cela fonctionne parfaitement pour moi. Cela fait apparaître la fenêtre au premier plan lorsque celle-ci est générée et ne le garde pas toujours au premier plan.
En ce qui concerne le Mac, j’ai remarqué qu’il pouvait y avoir un problème en ce sens que s’il y avait plusieurs interfaces graphiques python en cours d’exécution, chaque processus serait nommé "Python" et AppleScript aurait tendance à promouvoir le mauvais. Voici ma solution. L'idée est de récupérer une liste d'ID de processus en cours d'exécution avant et après le chargement de Tkinter. (Notez que ce sont des identifiants de processus AppleScript qui ne semblent pas avoir de relation avec leurs homologues posix. Allez comprendre.) Ensuite, l’homme étrange à l’extérieur sera à vous et vous le déplacerez au premier plan. (Je ne pensais pas que cette boucle à la fin serait nécessaire, mais si vous obtenez simplement tous les processus dont l'ID est procID, AppleScript retourne apparemment le seul objet identifié par son nom, qui est bien sûr ce "Python" non unique, nous revenons à la case départ à moins que quelque chose ne me manque.)
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''')
Un peu comme une combinaison de diverses autres méthodes, cela fonctionne sur OS X 10.11 et Python 3.5.1 s’exécutant dans un environnement de jeu, et devrait également fonctionner sur d’autres plateformes. Il cible également l'application par ID de processus plutôt que par nom d'application.
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))
Vous l'appelez juste avant l'appel mainloop()
, comme suit:
raise_app(root)
root.mainloop()
Récemment, j'ai eu la même question sur le Mac. J'ai combiné plusieurs réponses en utilisant @MagerValp
pour Mac et @D K
pour d'autres systèmes:
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()
Sur Mac OS X, PyObjC fournit une méthode plus propre et moins sujette aux erreurs que de recourir à osascript:
import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps
app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)
Sur macOS High Sierra, py3.6.4, voici ma solution:
def OnFocusIn(event):
if type(event.widget).__== 'Tk':
event.widget.attributes('-topmost', False)
# Create and configure your root ...
root.attributes('-topmost', True)
root.focus_force()
root.bind('<FocusIn>', OnFocusIn)
L'idée est de le mettre au premier plan jusqu'à ce que l'utilisateur interagisse avec lui, c'est-à-dire de prendre le focus.
J'ai essayé la réponse acceptée, .after_idle()
et .after()
. Ils échouent tous dans un cas: lorsque je lance mon script directement à partir d'un IDE comme PyCharm, la fenêtre de l'application reste en arrière.
Ma solution fonctionne dans tous les cas que j'ai rencontrés.