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.