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.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
|
||||
canvas.grid(row=0, column=0, sticky="nsew")
|
||||
scrollbar.grid(row=0, column=1, sticky="ns")
|
||||
@@ -94,8 +82,53 @@ class UIManager:
|
||||
canvas_width = canvas.winfo_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)
|
||||
|
||||
# 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
|
||||
symptom_vars: dict[str, tk.IntVar] = {
|
||||
"depression": tk.IntVar(value=0),
|
||||
@@ -168,6 +201,11 @@ class UIManager:
|
||||
# Set default date to today
|
||||
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 {
|
||||
"frame": main_container,
|
||||
@@ -311,17 +349,48 @@ class UIManager:
|
||||
canvas.itemconfig(canvas_window, width=canvas_width)
|
||||
|
||||
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)
|
||||
canvas.bind("<Configure>", configure_canvas_width)
|
||||
|
||||
# Bind mouse wheel events to canvas and edit window
|
||||
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
|
||||
canvas.bind("<Button-4>", on_mousewheel_linux_up) # 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
|
||||
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
|
||||
if len(values) == 10:
|
||||
# Old format: date, dep, anx, slp, app, bup, hydro, gaba, prop, note
|
||||
@@ -427,6 +496,9 @@ class UIManager:
|
||||
edit_win.update_idletasks()
|
||||
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
|
||||
edit_win.focus_set()
|
||||
edit_win.grab_set()
|
||||
@@ -968,18 +1040,42 @@ class UIManager:
|
||||
"""Recursively bind mouse wheel events to all widgets in the tree."""
|
||||
|
||||
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
|
||||
widget.bind("<MouseWheel>", on_mousewheel)
|
||||
widget.bind("<Button-4>", lambda e: canvas.yview_scroll(-1, "units"))
|
||||
widget.bind("<Button-5>", lambda e: canvas.yview_scroll(1, "units"))
|
||||
try:
|
||||
widget.bind("<MouseWheel>", on_mousewheel)
|
||||
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
|
||||
for child in widget.winfo_children():
|
||||
# Skip certain widgets that have their own scrolling behavior
|
||||
if not isinstance(child, tk.Text | tk.Listbox | tk.Canvas):
|
||||
self._bind_mousewheel_to_widget_tree(child, canvas)
|
||||
try:
|
||||
for child in widget.winfo_children():
|
||||
# Skip widgets that have their own scrolling behavior or are problematic
|
||||
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(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user