I'm trying to write a utility that will allow me to query a database, display the returned data and then allow the user to double click on one item to load/expand it. I've come up with the class below; each line will be an instance of this object, packed into a parent frame.
class PickerObject(tk.Frame):
def __init__(self, parent, row_id, row_items, callbacks):
super().__init__(parent)
self.callbacks = callbacks
self.configure(highlightbackground='black')
self.configure(highlightthickness=1)
self.rowconfigure(20, weight=1)
self.columnconfigure(3, weight=1)
self.row_id=row_id
self.widgets = {}
if self.row_id == 'new_prompt':
self.widgets['prompt'] = ttk.Label(self, text=row_items)
self.widgets['prompt'].grid(row=0, column=0, rowspan=2, sticky=tk.W, pady=10)
else:
for k, v in row_items.items():
self.widgets[k] = ttk.Label(self, **v['text'])
self.widgets[k].grid(padx=(0,25), **v['grid'])
self.grid(in_=parent, padx=5, pady=(5, 0), sticky=tk.W + tk.E)
self.bind('<Enter>', self.enter)
self.bind('<Leave>', self.leave)
self.bind('<Double-Button-1>', self.on_double_click)
def enter(self, event=None):
self.config(background='light blue')
for widget in self.widgets:
self.widgets[widget].config(background='light blue')
def leave(self, event=None):
self.config(background='light grey')
for widget in self.widgets:
self.widgets[widget].config(background='light grey')
def on_double_click(self, event=None):
self.callbacks['open'](self.row_id)
The code seems to work OK - the objects are being displayed as intended and the highlighting on mouse-over works, but the double click event only works on the first instance created.
I've tried googling with no success and I've read the Python and Tkinter documentation to try and understand what I'm doing wrong, but I just can't work it out.
Python 3.9.7, Tkinter 8.6
Edit:
As suggested, here's a minimum workable example - only difference is that, now, double click doesn't work at all.
import tkinter as tk
import tkinter.ttk as ttk
class Main(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
items = {}
callback = {'open': self.open}
f = tk.Frame(self)
for i in range(5):
items[i] = PickerObject(i, callback)
items[i].pack(in_=f)
f.pack()
def open(self, id):
print(f'ID = {id}')
class PickerObject(tk.Frame):
def __init__(self, i, callback):
super().__init__()
self.id = i
self.callbacks = callback
self.widget = ttk.Label(self, text = f'Label: {i}')
self.widget.pack()
self.bind('<Enter>', self.enter)
self.bind('<Leave>', self.leave)
self.bind('<Double-Button-1>', self.on_double_click)
def enter(self, event=None):
self.config(background='light blue')
self.widget.config(background='light blue')
def leave(self, event=None):
self.config(background='light grey')
self.widget.config(background='light grey')
def on_double_click(self, event=None):
self.callbacks['open'](self.id)
if __name__ == '__main__':
mw = tk.Tk()
list_frame = Main(mw)
list_frame.pack()
mw.mainloop()
Edit:
For anyone interested, my full code, including database etc. is at https://github.com/tihnessa/almanac
in_option in.pack()instead of creating the instance ofPickerObjectas child off.