feat: Improve canvas scrolling functionality with enhanced mouse wheel event handling
This commit is contained in:
+119
-23
@@ -70,18 +70,6 @@ class UIManager:
|
|||||||
input_frame = ttk.Frame(canvas)
|
input_frame = ttk.Frame(canvas)
|
||||||
input_frame.grid_columnconfigure(1, weight=1)
|
input_frame.grid_columnconfigure(1, weight=1)
|
||||||
|
|
||||||
# Configure canvas scrolling
|
|
||||||
def configure_scroll_region(event=None):
|
|
||||||
canvas.configure(scrollregion=canvas.bbox("all"))
|
|
||||||
|
|
||||||
def on_mousewheel(event):
|
|
||||||
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
|
||||||
|
|
||||||
input_frame.bind("<Configure>", configure_scroll_region)
|
|
||||||
canvas.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
|
||||||
canvas.bind("<Button-4>", lambda e: canvas.yview_scroll(-1, "units")) # Linux
|
|
||||||
canvas.bind("<Button-5>", lambda e: canvas.yview_scroll(1, "units")) # Linux
|
|
||||||
|
|
||||||
# Place canvas and scrollbar in the container
|
# Place canvas and scrollbar in the container
|
||||||
canvas.grid(row=0, column=0, sticky="nsew")
|
canvas.grid(row=0, column=0, sticky="nsew")
|
||||||
scrollbar.grid(row=0, column=1, sticky="ns")
|
scrollbar.grid(row=0, column=1, sticky="ns")
|
||||||
@@ -94,8 +82,53 @@ class UIManager:
|
|||||||
canvas_width = canvas.winfo_width()
|
canvas_width = canvas.winfo_width()
|
||||||
canvas.itemconfig(canvas_window, width=canvas_width)
|
canvas.itemconfig(canvas_window, width=canvas_width)
|
||||||
|
|
||||||
|
# Configure canvas scrolling
|
||||||
|
def configure_scroll_region(event=None):
|
||||||
|
canvas.configure(scrollregion=canvas.bbox("all"))
|
||||||
|
|
||||||
|
def on_mousewheel(event):
|
||||||
|
# Check if canvas is scrollable before scrolling
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
||||||
|
|
||||||
|
def on_mousewheel_linux_up(event):
|
||||||
|
# Linux mouse wheel up
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(-1, "units")
|
||||||
|
|
||||||
|
def on_mousewheel_linux_down(event):
|
||||||
|
# Linux mouse wheel down
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(1, "units")
|
||||||
|
|
||||||
|
input_frame.bind("<Configure>", configure_scroll_region)
|
||||||
canvas.bind("<Configure>", configure_canvas_width)
|
canvas.bind("<Configure>", configure_canvas_width)
|
||||||
|
|
||||||
|
# Bind mouse wheel events to canvas and main container
|
||||||
|
canvas.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
||||||
|
canvas.bind("<Button-4>", on_mousewheel_linux_up) # Linux
|
||||||
|
canvas.bind("<Button-5>", on_mousewheel_linux_down) # Linux
|
||||||
|
main_container.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
||||||
|
main_container.bind("<Button-4>", on_mousewheel_linux_up) # Linux
|
||||||
|
main_container.bind("<Button-5>", on_mousewheel_linux_down) # Linux
|
||||||
|
|
||||||
|
# Bind mouse wheel to input frame and its children for better scrolling
|
||||||
|
self._bind_mousewheel_to_widget_tree(input_frame, canvas)
|
||||||
|
|
||||||
|
# Set focus to canvas to ensure it receives scroll events
|
||||||
|
canvas.focus_set()
|
||||||
|
|
||||||
|
# Add mouse enter/leave events to manage focus for scrolling
|
||||||
|
def on_mouse_enter(event):
|
||||||
|
canvas.focus_set()
|
||||||
|
|
||||||
|
def on_mouse_leave(event):
|
||||||
|
# Don't change focus when leaving to avoid disrupting user interaction
|
||||||
|
pass
|
||||||
|
|
||||||
|
main_container.bind("<Enter>", on_mouse_enter)
|
||||||
|
canvas.bind("<Enter>", on_mouse_enter)
|
||||||
|
|
||||||
# Create variables for symptoms
|
# Create variables for symptoms
|
||||||
symptom_vars: dict[str, tk.IntVar] = {
|
symptom_vars: dict[str, tk.IntVar] = {
|
||||||
"depression": tk.IntVar(value=0),
|
"depression": tk.IntVar(value=0),
|
||||||
@@ -168,6 +201,11 @@ class UIManager:
|
|||||||
# Set default date to today
|
# Set default date to today
|
||||||
date_var.set(datetime.now().strftime("%m/%d/%Y"))
|
date_var.set(datetime.now().strftime("%m/%d/%Y"))
|
||||||
|
|
||||||
|
# Ensure mouse wheel binding is applied to all newly created widgets
|
||||||
|
main_container.update_idletasks()
|
||||||
|
canvas.configure(scrollregion=canvas.bbox("all"))
|
||||||
|
self._bind_mousewheel_to_widget_tree(input_frame, canvas)
|
||||||
|
|
||||||
# Return all UI elements and variables
|
# Return all UI elements and variables
|
||||||
return {
|
return {
|
||||||
"frame": main_container,
|
"frame": main_container,
|
||||||
@@ -311,17 +349,48 @@ class UIManager:
|
|||||||
canvas.itemconfig(canvas_window, width=canvas_width)
|
canvas.itemconfig(canvas_window, width=canvas_width)
|
||||||
|
|
||||||
def on_mousewheel(event):
|
def on_mousewheel(event):
|
||||||
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
# Check if canvas is scrollable before scrolling
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
||||||
|
|
||||||
|
def on_mousewheel_linux_up(event):
|
||||||
|
# Linux mouse wheel up
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(-1, "units")
|
||||||
|
|
||||||
|
def on_mousewheel_linux_down(event):
|
||||||
|
# Linux mouse wheel down
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(1, "units")
|
||||||
|
|
||||||
main_container.bind("<Configure>", configure_scroll_region)
|
main_container.bind("<Configure>", configure_scroll_region)
|
||||||
canvas.bind("<Configure>", configure_canvas_width)
|
canvas.bind("<Configure>", configure_canvas_width)
|
||||||
|
|
||||||
|
# Bind mouse wheel events to canvas and edit window
|
||||||
canvas.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
canvas.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
||||||
canvas.bind("<Button-4>", lambda e: canvas.yview_scroll(-1, "units")) # Linux
|
canvas.bind("<Button-4>", on_mousewheel_linux_up) # Linux
|
||||||
canvas.bind("<Button-5>", lambda e: canvas.yview_scroll(1, "units")) # Linux
|
canvas.bind("<Button-5>", on_mousewheel_linux_down) # Linux
|
||||||
|
edit_win.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
||||||
|
edit_win.bind("<Button-4>", on_mousewheel_linux_up) # Linux
|
||||||
|
edit_win.bind("<Button-5>", on_mousewheel_linux_down) # Linux
|
||||||
|
|
||||||
# Bind mouse wheel to main container and its children for better scrolling
|
# Bind mouse wheel to main container and its children for better scrolling
|
||||||
self._bind_mousewheel_to_widget_tree(main_container, canvas)
|
self._bind_mousewheel_to_widget_tree(main_container, canvas)
|
||||||
|
|
||||||
|
# Set focus to canvas to ensure it receives scroll events
|
||||||
|
canvas.focus_set()
|
||||||
|
|
||||||
|
# Add mouse enter/leave events to manage focus for scrolling
|
||||||
|
def on_mouse_enter(event):
|
||||||
|
canvas.focus_set()
|
||||||
|
|
||||||
|
def on_mouse_leave(event):
|
||||||
|
# Don't change focus when leaving to avoid disrupting user interaction
|
||||||
|
pass
|
||||||
|
|
||||||
|
edit_win.bind("<Enter>", on_mouse_enter)
|
||||||
|
canvas.bind("<Enter>", on_mouse_enter)
|
||||||
|
|
||||||
# Unpack values - handle both old and new CSV formats
|
# Unpack values - handle both old and new CSV formats
|
||||||
if len(values) == 10:
|
if len(values) == 10:
|
||||||
# Old format: date, dep, anx, slp, app, bup, hydro, gaba, prop, note
|
# Old format: date, dep, anx, slp, app, bup, hydro, gaba, prop, note
|
||||||
@@ -427,6 +496,9 @@ class UIManager:
|
|||||||
edit_win.update_idletasks()
|
edit_win.update_idletasks()
|
||||||
canvas.configure(scrollregion=canvas.bbox("all"))
|
canvas.configure(scrollregion=canvas.bbox("all"))
|
||||||
|
|
||||||
|
# Ensure mouse wheel binding is applied to all newly created widgets
|
||||||
|
self._bind_mousewheel_to_widget_tree(main_container, canvas)
|
||||||
|
|
||||||
# Make window modal
|
# Make window modal
|
||||||
edit_win.focus_set()
|
edit_win.focus_set()
|
||||||
edit_win.grab_set()
|
edit_win.grab_set()
|
||||||
@@ -968,18 +1040,42 @@ class UIManager:
|
|||||||
"""Recursively bind mouse wheel events to all widgets in the tree."""
|
"""Recursively bind mouse wheel events to all widgets in the tree."""
|
||||||
|
|
||||||
def on_mousewheel(event):
|
def on_mousewheel(event):
|
||||||
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
# Check if canvas is scrollable before scrolling
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
||||||
|
|
||||||
|
def on_mousewheel_linux_up(event):
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(-1, "units")
|
||||||
|
|
||||||
|
def on_mousewheel_linux_down(event):
|
||||||
|
if canvas.cget("scrollregion"):
|
||||||
|
canvas.yview_scroll(1, "units")
|
||||||
|
|
||||||
# Bind to the widget itself
|
# Bind to the widget itself
|
||||||
widget.bind("<MouseWheel>", on_mousewheel)
|
try:
|
||||||
widget.bind("<Button-4>", lambda e: canvas.yview_scroll(-1, "units"))
|
widget.bind("<MouseWheel>", on_mousewheel)
|
||||||
widget.bind("<Button-5>", lambda e: canvas.yview_scroll(1, "units"))
|
widget.bind("<Button-4>", on_mousewheel_linux_up)
|
||||||
|
widget.bind("<Button-5>", on_mousewheel_linux_down)
|
||||||
|
except tk.TclError:
|
||||||
|
# Some widgets might not support binding
|
||||||
|
pass
|
||||||
|
|
||||||
# Recursively bind to all children
|
# Recursively bind to all children
|
||||||
for child in widget.winfo_children():
|
try:
|
||||||
# Skip certain widgets that have their own scrolling behavior
|
for child in widget.winfo_children():
|
||||||
if not isinstance(child, tk.Text | tk.Listbox | tk.Canvas):
|
# Skip widgets that have their own scrolling behavior or are problematic
|
||||||
self._bind_mousewheel_to_widget_tree(child, canvas)
|
skip_types = (tk.Text, tk.Listbox, tk.Canvas, ttk.Notebook)
|
||||||
|
if not isinstance(child, skip_types):
|
||||||
|
self._bind_mousewheel_to_widget_tree(child, canvas)
|
||||||
|
elif isinstance(child, ttk.Notebook):
|
||||||
|
# For notebooks, bind to their tab frames
|
||||||
|
for tab_id in child.tabs():
|
||||||
|
tab_widget = child.nametowidget(tab_id)
|
||||||
|
self._bind_mousewheel_to_widget_tree(tab_widget, canvas)
|
||||||
|
except tk.TclError:
|
||||||
|
# Handle potential errors when accessing children
|
||||||
|
pass
|
||||||
|
|
||||||
def _create_edit_fields(
|
def _create_edit_fields(
|
||||||
self,
|
self,
|
||||||
|
|||||||
Reference in New Issue
Block a user