How to make a Tkinter window jump to the front?
Asked Answered
Z

12

82

How do I get a Tkinter application to jump to the front? Currently, the window appears behind all my other windows and doesn't get focus.

Is there some method I should be calling?

Zina answered 12/12, 2009 at 4:52 Comment(0)
P
120

Assuming you mean your application windows when you say "my other windows", you can use the lift() method on a Toplevel or Tk:

root.lift()

If you want the window to stay above all other windows, use:

root.attributes("-topmost", True)

Where root is your Toplevel or Tk. Don't forget the - infront of "topmost"!

To make it temporary, disable topmost right after:

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

Just pass in the window you want to raise as a argument, and this should work.

Phrasing answered 22/7, 2011 at 19:32 Comment(5)
what I meant to say is: the windows.attributes(1) does bring to front, but the (0) doesn't seem to be disabling it. It actually sends it to the back.Segmental
root.attributes("-topmost", True) works but it does not bring focus to the window use _root_window.focus_force() afterwardsKatykatya
root.attributes("-topmost", True) worked, root.lift() not (Windows 7). It seems to be OS-dependent (?)Zigmund
Be sure you adding this BEFORE root.mainloop()!Alodee
@Segmental While I am also looking for a better way, I have a workaround for not sending it to back. Bind windows.attributes(0) to the window on <focusOut>. Since it's been so many years, pls share if you have any thing betterKora
V
50

Add the following lines before the mainloop():

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

It works perfectly for me. It makes the window come to the front when the window is generated, and it won't keep it always be in the front.

Visconti answered 24/3, 2016 at 0:56 Comment(2)
I'm running 10.11 And this is the only answer that worked for me.Heiney
This and the osascript version (https://mcmap.net/q/241830/-how-to-make-a-tkinter-window-jump-to-the-front) worked for me (10.14), but this looks better to me, probably runs faster and seems less likely to have unintended side effectsPrognostication
M
31

If you're doing this on a Mac, use AppleEvents to give focus to Python. Eg:

import os

os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
Marshamarshal answered 8/1, 2012 at 3:7 Comment(4)
Needs to happen before the root.mainloop()Metatarsus
For me, it needed to happen after root = tk.Tk() and before root.mainloop(). Also, for my anaconda installation, it had to be lower case process "python".K2
The drawback is: it move ALL python Tk processes to foreground which may not be the expectation.Varick
Beware, this will cause request of 'Finder' app permission from the user for newer macOS.Saideman
H
6

Regarding the Mac, I noticed there can be a problem in that if there are multiple python GUIs running, every process will be named "Python" and AppleScript will tend to promote the wrong one to the front. Here's my solution. The idea is to grab a list of running process IDs before and after you load Tkinter. (Note that these are AppleScript process IDs which seem to bear no relation to their posix counterparts. Go figure.) Then the odd man out will be yours and you move that one to frontmost. (I didn't think that loop at the end would be necessary, but if you simply get every process whose ID is procID, AppleScript apparently returns the one object identified by name, which of course is that non-unique "Python", so we are back to square one unless there's something I'm missing.)

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''')
Hirsch answered 9/5, 2014 at 18:6 Comment(0)
N
4

On Mac OS X PyObjC provides a cleaner and less error prone method than shelling out to osascript:

import os
from Cocoa import NSRunningApplication, NSApplicationActivateIgnoringOtherApps

app = NSRunningApplication.runningApplicationWithProcessIdentifier_(os.getpid())
app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)
Nuclei answered 5/3, 2015 at 9:29 Comment(2)
when close the window, there is an error: Segmentation fault: 11Ulterior
It runs in a Tkinter application here without segfaulting on 10.10.2 with system python. Try removing other parts of your code, it's likely something else that's crashing.Nuclei
C
4

Recently, I had the same question on the Mac. I have combined several answers using @MagerValp for the Mac and @D K for other systems:

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()
Cadel answered 20/8, 2015 at 15:5 Comment(3)
what programming language is thisRheims
The language is PythonCadel
Adding and removing -topmost worked for me on Sierra, unlike the other branch (there is no Cocoa module in it). I'm running a OS X default tk.Turgescent
C
4

Somewhat of a combination of various other methods, this works on OS X 10.11, and Python 3.5.1 running in a venv, and should work on other platforms too. It also targets the app by process id rather than app name.

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

You call it right before the mainloop() call, like so:

raise_app(root)
root.mainloop()
Chaffee answered 15/5, 2016 at 7:8 Comment(0)
B
3

There's a hint on how to make the Tkinter window take focus when you call mainloop() in the Tkinter._test() function.

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

This is the cleanest most proper way I've found to do this, but it's only needed for Windows systems.

Benyamin answered 22/7, 2017 at 20:16 Comment(0)
A
2

This answer is to make one Tkinter Window pop up overtop of other Tkinter windows.

In my app I have a large window toplevel which calls a much smaller window top2 which initially appears on top of toplevel.

If user clicks within toplevel window it gains focus and smothers much smaller top2 window until toplevel window is dragged off of it.

The solution is to click the button in toplevel to launch top2 again. The top2 open function knows it is already running so simply lifts it to the top and gives it focus:

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
Adhibit answered 4/8, 2020 at 1:22 Comment(0)
S
1

On macOS High Sierra, py3.6.4, here is my solution:

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)

The idea is to bring it to the front until user interacts with it, i.e., taking focus.

I tried the accepted answer, .after_idle(), and .after(). They all fail in one case: When I run my script directly from an IDE like PyCharm, the app window will stay behind.

My solution works in all the cases that I encountered.

Swat answered 6/12, 2018 at 4:52 Comment(0)
H
1

This will lift the window to the front, and also focus on 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
Houri answered 10/5, 2022 at 10:58 Comment(1)
I'm glad I stumbled on this clever answer. Has worked like a charm to both display messageboxes over windows with -topmost and to get the tk app in the front of other Windows applications when you don't need to fully activate the jumper. The best about it is that this doesn't rely on SetForegroundWindow, and presumably works in other OS.Zootomy
A
1

One more line (needed for Python 3.11 and 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
Antimere answered 25/11, 2022 at 17:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.