18
votes

I have the following code

window = Tk()
window.lift()
window.attributes("-topmost", True)

This code works in that it displays my Tkinter window above all other windows, but it still only solves half of the problem. While the window is in fact displayed above all other windows, the window does not have focus. Is there a way not only to make the window the frontmost window in Tkinter, but also put focus on it?

6
What makes you think it doesn't have focus? Have you tried calling focus_force on the window? - Bryan Oakley
I think it does not have focus because the window is grayed out, and I have to click in for it to recognize keystrokes, also focus_force does not resolve the problem - Python Spoils You
@marczellm, can you specify the issue? I ran the code on Python 3.6 and Windows 10 and it works - Tarun Lalwani
@TarunLalwani To be specific, I would like my Tkinter window to steal global focus from all applications and set it to an Entry field. The window does appear on top of all windows with -topmost but none of the methods puts the focus on the Entry field - the previously active applications remains the active/focused window. - marczellm
Please provide a sample test app that you use. also python version and how you launch the script? @marczellm - Tarun Lalwani

6 Answers

12
votes

If focus_force() is not working you can try doing:

window.after(1, lambda: window.focus_force())

It's essentially the same thing, just written differently. I just tested it on python 2.7.

root.focus_force() wouldn't work but the above method did.

12
votes

Solution for Windows is a littlebit tricky - you can't just steal the focus from another window, you should move your application to foreground somehow. But first, I suggest you to consume a littlebit of windows theory, so we're able to confirm, that this is what we want to achieve.

As I mentioned in comment - it's a good opportunity to use the SetForegroundWindow function (check restrictions too!). But consider such stuff as a cheap hack, since user "owns" foreground, and Windows would try to stop you at all cost:

An application cannot force a window to the foreground while the user is working with another window. Instead, Windows flashes the taskbar button of the window to notify the user.

Also, check a remark on this page:

The system automatically enables calls to SetForegroundWindow if the user presses the ALT key or takes some action that causes the system itself to change the foreground window (for example, clicking a background window).

Here's goes a simplest solution, since we're able to emulate Alt press:

import tkinter as tk
import ctypes

#   store some stuff for win api interaction
set_to_foreground = ctypes.windll.user32.SetForegroundWindow
keybd_event = ctypes.windll.user32.keybd_event

alt_key = 0x12
extended_key = 0x0001
key_up = 0x0002


def steal_focus():
    keybd_event(alt_key, 0, extended_key | 0, 0)
    set_to_foreground(window.winfo_id())
    keybd_event(alt_key, 0, extended_key | key_up, 0)

    entry.focus_set()


window = tk.Tk()

entry = tk.Entry(window)
entry.pack()

#   after 2 seconds focus will be stolen
window.after(2000, steal_focus)

window.mainloop()

Some links and examples:

5
votes

Not sure what issue you face. But below is sample code which worked great for me.

from tkinter import *

window = Tk()

def handle_focus(event):
    if event.widget == window:
        window.focus_set()
        input1.focus_set()


label1 = Label(window,text = "Enter Text 2")
input1 = Entry(window, bd=5)

label2 = Label(window,text = "Enter Text 2")
input2 = Entry(window, bd=5)

submit = Button(window, text="Submit")

label1.pack()
input1.pack()
label2.pack()
input2.pack()
submit.pack(side=BOTTOM)

window.lift()
window.attributes("-topmost", True)

window.bind("<FocusIn>", handle_focus)

hwnd = window.winfo_id()

window.mainloop()

This was tested using Latest Python 3.6 on Windows 10.

Test Results

The result was that after running the program, I could just start typing and and he input would go to the first text box

4
votes

Note: this is Windows specific. This focuses the whole main window. Essentially forcing an alt-tab to reach the window.


None of these answers worked for me, the tk window would appear on top of everything with the -topmost flag, my input box would have focus, but the window itself wouldn't, which meant that typing wouldn't appear in the tk window. It looks like like this:

enter image description here

What helped was adding a call to the Windows API to steal focus:

import win32gui    
root = tk.Tk()

# Application specific setup ...

win32gui.SetForegroundWindow(root.winfo_id())

Disclaimer: Stealing focus is bad behaviour, so only use it if you must and if it makes sense, e.g. input box the user will instantly type into.

1
votes

It works for me. I am on Macos Mojave, python 3.6.4. Place this code before root.mainloop()

import os
os.system("open -a Python")

When you open -a an application that already be opened, this application will be focus on.

0
votes

For Linux (Ubuntu 16.04.6 LTS) I tried many suggestions including .grab which broke things. In the end I used:

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

It's not really "stealing" focus because I have a button on the main window defined as:

''' ▶  Play Button '''
self.play_text="▶  Play"                # play songs window is opened.
self.listbox_btn2 = tk.Button(frame3, text=self.play_text, \
                    width=BTN_WID, command=self.play_items)
self.listbox_btn2.grid(row=0, column=1, padx=2)

After clicking this button the text is changed to:

self.listbox_btn2 ["text"] = "🎵  Show playing"     # Play button