0

I'm trying to create a custom looking dropdown in Tkinter and I decided to go with Toplevel. Everything works as expected except for the focus isn't taking place. When the window gets created, it stays on top of my other windows, but the <Enter>/<Leave> bindings aren't working until I click on the window. Here's a rebuilt example of the exact problem.

import tkinter as tk
from tkinter import ttk


class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.mainframe = ttk.Frame(self)

        self.init_ui()
        self.mainloop()

    def init_ui(self):
        self.mainframe.grid(row=0, column=0, sticky='nsew')
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        self.mainframe.rowconfigure(0, weight=1)
        self.mainframe.columnconfigure(0, weight=1)

        l = ttk.Label(self.mainframe, text='Test ▾')
        l.config(cursor='hand', font=('Helvetica', 12, 'underline'))
        l.bind('<Button-1>', self.dropdown)
        l.grid(row=0, column=0, padx=50, pady=(5, 300), sticky='new')

    def dropdown(self, *args):
        top = tk.Toplevel(self)
        top.overrideredirect(1)
        top.transient(self)

        def create_label(n):
            nonlocal top
            l = tk.Label(top, text='Test{}'.format(n))
            l.config(cursor='hand', relief='ridge')
            l.bind('<Enter>', enter_leave)
            l.bind('<Leave>', enter_leave)
            l.bind('<Button-1>', lambda _: top.destroy())
            l.grid(row=n, column=0)

        def enter_leave(e):
            # 7 = enter
            # 8 = leave
            if e.type == '7':
                e.widget.config(bg='grey')
            else:
                e.widget.config(bg='white')

        # populate some labels
        for x in range(9):
            create_label(x)

        self.update_idletasks()

        top_width = top.winfo_width()
        top_height = top.winfo_height()

        root_x = self.winfo_x()
        root_y = self.winfo_y()

        top.geometry('{}x{}+{}+{}'.format(
            top_width, top_height,
            int(root_x + (self.winfo_width() / 2)),
            root_y + 50
        ))

if __name__ == '__main__':
    App()

This is what is looks like:

tk window

If I take out top.overrideredirect(1) then it works as expected but I get it with the title bar which I don't want:

tk window with overrideredirect off

One other interesting occurrence is when I run self.update_idletasks() right before calling top.overrideredirect(1) then it again works but with a frozen title bar. I'm not sure why that doesn't happen without self.update_idletasks() (this may be a different question):

tk window with update_idletasks

I have tried a number of combinations of the following with no wanted results:

top.attributes('-topmost', True)
top.lift(aboveThis=self)
top.focus_force()
top.grab_set()

All in all, I would just like to get the "highlighting" effect to work but with the look of image 1 with no title bar. I'm open to all other suggestions or approaches.

double_j
  • 1,636
  • 1
  • 18
  • 27
  • does [this post](https://stackoverflow.com/questions/17774859/tkinter-window-focus-on-mac-os-x) solve anything ? it looks to work fine on ubuntu (except the hand cursor > must be hand1) – PRMoureu Jun 29 '17 at 16:50
  • @PRMoureu Unfortunately no. That solution is for an entire app that doesn't have focus in relation to other open programs. My issue is the focus within the app itself. That's interesting about it working on ubuntu though. – double_j Jun 29 '17 at 17:07
  • Yep, that is a window manager difference. When you remove the border decorations in Windows (overrideredirect), the window manager ignores the window entirely when it comes to propagating events. This is documented somewhat in the Tk manual, but it does *not* tell you that the Enter/Leave events are ignored, but they are. – Ron Norris Jun 29 '17 at 18:39

0 Answers0