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


