SYSTEM: You are a Python 3.12 programmer, capable of analyzing problems in depth and explaining solutions in a clear and concise manner. Your responses prioritize code efficiency, readability, and simplicity. You leverage the latest Python features. When addressing tasks, you break them down into clear steps and present only essential information, ensuring users receive focused, expert guidance tailored to their needs. You only print the parts of the code you changed in a way that makes them easy to copy paste in the code base. USER: Why does the mousewheel in the sidebar not work? Python 3.12 Code: import ctypes
import csv
import json
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk
from pathlib import Path
from tksheet import Sheet

def set_dpi_awareness():
"""Enable DPI awareness for high DPI settings."""
try:
ctypes.windll.shcore.SetProcessDpiAwareness(1)
except Exception as e:
print(f"Error setting DPI awareness: {e}")

class TableApp:
"""Table Editor with sidebar and table management."""

def __init__(self, root: tk.Tk):
    """Initialize the TableApp."""
    self.root = root
    self.config_dimensions()
    self.config_fonts()
    self.config_colors()
    self.initialize_data()
    self.setup_ui()
    self.load_tables()

def config_dimensions(self):
    """Configure app dimensions."""
    self.root.title("Database")
    self.root.geometry("1920x1080")
    self.root.minsize(1435, 910)
    self.sidebar_width = 400
    self.static_frame_width = 100
    self.header_height = 190

def config_fonts(self):
    """Configure app fonts."""
    font_name, font_size, font_style = "Literata", 12, "normal"
    self.default_font = (font_name, font_size, font_style)
    self.root.option_add("*Font", f"{font_name} {font_size}")

def config_colors(self):
    """Configure app colors."""
    self.text_color = "#333333"
    self.background_color = "#FFFFFF"
    self.sidebar_color = "#F7F8FC"
    self.button_color = "#F7F8FC"
    self.button_color_selected = "#EAEDEF"

def setup_ui(self):
    """Set up the user interface."""
    self._create_layout()
    self._setup_sidebar()
    self._setup_main_area()

def _create_layout(self):
    """Create the main layout of the GUI."""
    self.sidebar = self._create_frame(self.root, self.sidebar_width, self.sidebar_color, 'left', 'nw', 'y')
    self._create_frame(self.root, self.static_frame_width, self.background_color, 'left', 'nw', 'y')  # spacer
    self.main_frame = self._create_frame(self.root, None, self.background_color, 'right', 'ne', 'both', True)

def _setup_sidebar(self):
    """Set up the sidebar components."""
    self.sidebar.pack_propagate(False)
    self._add_sidebar_buttons()
    self._add_sidebar_table_list()
    self._add_sidebar_delete_option()

def _add_sidebar_buttons(self):
    """Add buttons to the sidebar."""
    buttons_frame = self._create_frame(self.sidebar, None, self.sidebar_color, 'top', 'nw', 'x')
    create_table_label = self._create_clickable_label(buttons_frame, "Create New Table", self.create_new_table, anchor='center')
    create_table_label.pack(pady=10, anchor='center')
    self.add_custom_hover(create_table_label)
    self._add_separator(buttons_frame)

def _add_sidebar_table_list(self):
    """Add scrollable list of tables to the sidebar."""
    list_frame = self._create_frame(self.sidebar, None, self.sidebar_color, 'top', 'nw', 'both', True)
    self.table_list_canvas = self._create_scrollable_canvas(list_frame)
    self.table_labels_frame = self._create_frame(self.table_list_canvas, None, self.sidebar_color, None, None, None)
    self.table_list_canvas.create_window((0, 0), window=self.table_labels_frame, anchor="nw")
    self._setup_table_list_scrolling()

def _create_scrollable_canvas(self, parent):
    """Create a scrollable canvas for the table list."""
    canvas = tk.Canvas(parent, bg=self.sidebar_color, highlightthickness=0, width=self.sidebar_width - 15)
    canvas.pack(side="left", fill="both", expand=True)
    self.config_scrollbar_style()
    scrollbar = ttk.Scrollbar(parent, orient="vertical", command=canvas.yview, style="Custom.Vertical.TScrollbar")
    scrollbar.pack(side="right", fill="y")
    canvas.configure(yscrollcommand=scrollbar.set)
    return canvas

def _setup_table_list_scrolling(self):
    """Set up scrolling behavior for the table list."""
    self.table_list_canvas.bind_all("<MouseWheel>", self._on_mousewheel)
    self.table_labels_frame.bind("<Configure>", self._on_frame_configure)
    self.sidebar.bind("<Configure>", self._on_frame_configure)

def _on_mousewheel(self, event):
    self.table_list_canvas.yview_scroll(int(-1*(event.delta/120)), "units")

def _on_frame_configure(self, event):
    self.table_list_canvas.configure(scrollregion=self.table_list_canvas.bbox("all"))
    self._manage_scrollbar_visibility()

def _manage_scrollbar_visibility(self):
    canvas_height = self.sidebar.winfo_height()
    content_height = self.table_labels_frame.winfo_reqheight()
    if content_height > canvas_height:
        self.table_list_canvas.bind_all("<MouseWheel>", self._on_mousewheel)
    else:
        self.table_list_canvas.unbind_all("<MouseWheel>")

def _add_sidebar_delete_option(self):
    """Add delete table option to the sidebar."""
    self._add_separator(self.sidebar)
    delete_label = self._create_clickable_label(self.sidebar, "🗑 Delete Selected Table", self.delete_table)
    delete_label.pack(side='bottom', anchor='center', pady=10)
    self.add_custom_hover(delete_label)

def _setup_main_area(self):
    """Set up the main area of the GUI."""
    self._create_header()
    self._create_table_area()

def _create_header(self):
    """Create header with filter and settings."""
    header = self._create_frame(self.main_frame, None, self.background_color, 'top', 'nw', 'x')
    header.configure(height=self.header_height)
    header.pack_propagate(False)
    self._add_filter(header)
    self._add_settings(header)

def _add_filter(self, parent):
    """Add filter functionality to the header."""
    tk.Label(parent, text="Filter:", bg=self.background_color, fg=self.text_color).pack(side='left')
    self.filter_entry = tk.Entry(parent, fg=self.text_color)
    self.filter_entry.pack(side='left')
    self.filter_entry.bind("<KeyRelease>", lambda event: self.apply_filter())

def _add_settings(self, parent):
    """Add settings menu to the header."""
    settings_label = tk.Label(parent, text="...", bg=self.background_color, fg=self.text_color, cursor="hand2")
    settings_label.place(relx=1.0, rely=0.0, anchor='ne', x=-40, y=20)
    settings_menu = self._create_settings_menu(settings_label)
    settings_label.bind("<Button-1>", lambda event: settings_menu.post(event.x_root, event.y_root))
    self._add_hover_effect(settings_label)

def _create_settings_menu(self, parent):
    """Create the settings dropdown menu."""
    menu = tk.Menu(parent, tearoff=0)
    menu.add_command(label="Export Table", command=self.export_table)
    menu.add_command(label="Import Table", command=self.import_file)
    menu.add_command(label="Rename Headers", command=self.rename_headers)
    return menu

def _create_table_area(self):
    """Create the main table area."""
    self.table_frame = self._create_frame(self.main_frame, None, self.background_color, 'top', 'nw', 'both', True)

def _create_frame(self, parent, width, bg, side, anchor, fill, expand=False):
    """Create and pack a frame."""
    frame = tk.Frame(parent, width=width, bg=bg, bd=0, relief='flat')
    frame.pack(side=side, anchor=anchor, fill=fill, expand=expand)
    return frame

def _create_clickable_label(self, parent, text, command, allow_rename=False, anchor='w'):
    """Create a clickable label."""
    label = tk.Label(parent, text=text, bg=self.button_color, fg=self.text_color, cursor="hand2" if not allow_rename else "arrow", anchor=anchor)
    label.bind("<Button-1>", lambda event: command())
    if allow_rename:
        label.bind("<Double-1>", lambda event: self.begin_rename(text))
    return label

def _add_separator(self, parent):
    """Add a horizontal separator."""
    ttk.Separator(parent, orient='horizontal').pack(fill='x')

def _add_hover_effect(self, widget):
    """Add hover effect to a widget."""
    widget.bind("<Enter>", lambda event: widget.config(bg=self.button_color_selected))
    widget.bind("<Leave>", lambda event: widget.config(bg=self.background_color))

def initialize_data(self):
    """Initialize data structures."""
    self.save_file_path = Path(__file__).parent / "Data.json"
    self.tables_data: dict[str, dict] = {}
    self.current_sheet: Sheet | None = None
    self.headers: dict[str, list[str]] = {}
    self.current_table_name: str | None = None
    self.rename_entry: tk.Entry | None = None
    self.selected_table_label: tk.Label | None = None
    self.table_labels: dict[str, tk.Label] = {}

def create_new_table(self):
    """Create a new table."""
    existing_numbers = [int(name.split(" ")[1]) for name in self.tables_data if name.startswith("Table ") and name.split(" ")[1].isdigit()]
    next_number = max(existing_numbers, default=0) + 1
    table_name = f"Table {next_number}"
    self.add_table(table_name)
    self.load_selected_table(table_name)

def import_file(self):
    """Import table from file."""
    file_path = filedialog.askopenfilename(title="Import File", filetypes=[("JSON files", "*.json"), ("CSV files", "*.csv")])
    if not file_path:
        return
    try:
        if file_path.endswith('.csv'):
            with open(file_path, newline='', encoding='utf-8') as csvfile:
                data = list(csv.reader(csvfile))
        elif file_path.endswith('.json'):
            with open(file_path, 'r', encoding='utf-8') as jsonfile:
                data = json.load(jsonfile)
        else:
            raise ValueError("Unsupported file format.")
        if not data or not isinstance(data, list) or not all(isinstance(row, list) for row in data):
            raise ValueError("Invalid data format in the file.")
        headers, table_data = data[0], data[1:]
        self.add_table_from_data(file_path, headers, table_data)
    except Exception as e:
        messagebox.showerror("File Import Error", str(e))

def add_table_from_data(self, file_path: str, headers: list[str], table_data: list[list[str]]):
    """Add a table from file data."""
    table_name = Path(file_path).stem
    table_name = self.ensure_unique_table_name(table_name)
    self.add_table(table_name, table_data)
    self.headers[table_name] = headers
    self.load_selected_table(table_name)
    self.save_data()

def ensure_unique_table_name(self, table_name: str) -> str:
    """Ensure table name is unique."""
    original_name = table_name
    counter = 1
    while table_name in self.tables_data:
        table_name = f"{original_name} (New {counter})"
        counter += 1
    return table_name

def save_table_data(self, file_path: str, data: list[list[str]], format: str):
    """Save table data in specified format."""
    match format:
        case 'csv':
            with open(file_path, 'w', newline='', encoding='utf-8') as file:
                csv.writer(file).writerows(data)
        case 'json':
            with open(file_path, 'w', encoding='utf-8') as file:
                json.dump(data, file, indent=4)
        case _:
            raise ValueError("Unsupported file format.")

def export_table(self):
    """Export current table to file."""
    if not self.current_table_name or self.current_table_name not in self.tables_data:
        messagebox.showwarning("No Table Selected", "Please select a table to export.")
        return
    file_path = filedialog.asksaveasfilename(title="Export File", defaultextension=".json", filetypes=[("JSON files", "*.json"), ("CSV files", "*.csv")], initialfile=self.current_table_name)
    if not file_path:
        return
    try:
        data = [self.headers[self.current_table_name]] + self.tables_data[self.current_table_name]["data"]
        if file_path.endswith('.csv'):
            self.save_table_data(file_path, data, 'csv')
        elif file_path.endswith('.json'):
            with open(file_path, 'w', encoding='utf-8') as file:
                json.dump(data, file, indent=4)
        else:
            raise ValueError("Unsupported file format.")
        self.save_data()
        messagebox.showinfo("Export Successful", f"Table '{self.current_table_name}' has been exported successfully.")
    except Exception as e:
        messagebox.showerror("Export Failed", f"An error occurred during export: {e}")

def add_table(self, table_name: str, data: list[list[str]] | None = None):
    """Add a new table."""
    default_data = [["" for _ in range(5)] for _ in range(10)]
    self.tables_data[table_name] = {"headers": self.headers.get(table_name, [""] * 5), "data": data or default_data}
    self.create_table_label(table_name)
    self.save_data()

def create_table_label(self, table_name: str):
    """Create label for table."""
    label = self._create_clickable_label(self.table_labels_frame, table_name, lambda: self.load_selected_table(table_name), True)
    label.pack(fill='x', padx=20, pady=5)
    self.table_labels[table_name] = label
    self.add_custom_hover(label)

def delete_table(self):
    """Delete selected table."""
    if not self.current_table_name or self.current_table_name not in self.tables_data:
        messagebox.showwarning("No Table Selected", "Please select a valid table to delete.")
        return
    if messagebox.askyesno("Delete Table", f"Are you sure you want to delete the table '{self.current_table_name}'?"):
        self.remove_table(self.current_table_name)

def remove_table(self, table_name: str):
    """Remove a table."""
    if self.current_table_name == table_name and self.current_sheet:
        self.current_sheet.destroy()
        self.current_sheet = None
    label = self.table_labels.get(table_name)
    if label:
        label.destroy()
    if table_name in self.tables_data:
        del self.tables_data[table_name]
    if table_name in self.headers:
        del self.headers[table_name]
    if table_name in self.table_labels:
        del self.table_labels[table_name]
    self.current_table_name = None
    self.selected_table_label = None
    self.save_data()

def load_tables(self):
    """Load tables from file."""
    if not self.save_file_path.exists():
        return
    try:
        with self.save_file_path.open('r', encoding='utf-8') as file:
            all_data = json.load(file)
    except Exception as e:
        messagebox.showerror("Load Error", f"Failed to load tables: {e}")
        return
    for table_name, data in all_data.items():
        if not isinstance(data, list) or not data:
            continue
        headers, table_data = data[0], data[1:]
        self.tables_data[table_name] = {"headers": headers, "data": table_data}
        self.headers[table_name] = headers
        self.create_table_label(table_name)

def load_selected_table(self, table_name: str):
    """Display selected table."""
    if self.current_sheet:
        self.current_sheet.pack_forget()
        self.current_sheet.destroy()
        self.current_sheet = None
    if self.selected_table_label:
        try:
            self.selected_table_label.config(bg=self.button_color)
        except tk.TclError:
            self.selected_table_label = None
    if table_name not in self.tables_data:
        messagebox.showerror("Error", f"Table '{table_name}' does not exist.")
        self.current_table_name = None
        self.selected_table_label = None
        return
    table_info = self.tables_data[table_name]
    headers = table_info["headers"]
    data = table_info["data"]
    try:
        sheet = Sheet(self.table_frame, data=data, show_table=True, headers=headers, font=self.default_font, header_font=self.default_font, auto_resize_columns=True)
        sheet.set_options(table_fg=self.text_color, header_fg=self.text_color)
        sheet.enable_bindings()
        sheet.extra_bindings([("end_edit_cell", self.on_cell_edit)])
        sheet.pack(expand=True, fill='both')
        self.current_sheet = sheet
        self.current_table_name = table_name
        label = self.table_labels.get(table_name)
        if label:
            self.selected_table_label = label
            try:
                self.selected_table_label.config(bg=self.button_color_selected)
            except tk.TclError:
                self.selected_table_label = None
                messagebox.showerror("Error", f"Failed to update the label for '{table_name}'.")
        else:
            self.selected_table_label = None
            messagebox.showerror("Error", f"Label for '{table_name}' not found.")
        self.apply_filter()
    except Exception as e:
        messagebox.showerror("Sheet Error", f"Failed to load table '{table_name}': {e}")
        self.current_table_name = None
        self.selected_table_label = None

def on_cell_edit(self, event=None):
    """Handle cell edits."""
    if self.current_table_name and self.current_sheet:
        self.tables_data[self.current_table_name]["data"] = self.current_sheet.get_sheet_data()
        self.save_data()

def save_data(self):
    """Save all tables data."""
    all_data = {}
    for table_name, table_info in self.tables_data.items():
        all_data[table_name] = [table_info["headers"]] + table_info["data"]
    try:
        with self.save_file_path.open('w', encoding='utf-8') as file:
            json.dump(all_data, file, indent=4)
    except Exception as e:
        print(f"Error saving data: {e}")

def apply_filter(self):
    """Apply filter to table data."""
    if not self.current_table_name or not self.current_sheet:
        return
    term = self.filter_entry.get().lower()
    original_data = self.tables_data[self.current_table_name]["data"]
    if term:
        filtered_data = [row for row in original_data if any(term in str(cell).lower() for cell in row)]
    else:
        filtered_data = original_data
    try:
        self.current_sheet.set_sheet_data(filtered_data)
    except tk.TclError as e:
        print(f"Error applying filter: {e}")

def rename_headers(self):
    """Rename table headers."""
    if not self.current_table_name:
        messagebox.showwarning("No Table Selected", "Please select a table to rename headers.")
        return
    current_headers = self.headers[self.current_table_name]
    new_headers = simpledialog.askstring("Rename Headers", "Enter new headers (comma-separated):", initialvalue=", ".join(current_headers))
    if new_headers:
        header_list = [header.strip() for header in new_headers.split(',')]
        if not header_list:
            messagebox.showerror("Invalid Headers", "Header list cannot be empty.")
            return
        self.headers[self.current_table_name] = header_list
        if self.current_sheet:
            try:
                self.current_sheet.headers(header_list)
            except tk.TclError as e:
                messagebox.showerror("Error", f"Failed to rename headers: {e}")
        self.save_data()

def begin_rename(self, table_name: str):
    """Start renaming a table."""
    if table_name not in self.table_labels:
        messagebox.showerror("Error", f"Table '{table_name}' not found.")
        return
    label = self.table_labels[table_name]
    self.cancel_rename()
    self.rename_entry = tk.Entry(self.table_labels_frame, bg=label.cget("bg"), fg=self.text_color, relief='flat')
    self.rename_entry.insert(0, table_name)
    self.rename_entry.place(x=label.winfo_x(), y=label.winfo_y(), width=label.winfo_width(), height=label.winfo_height())
    self.rename_entry.focus()
    self.rename_entry.select_range(0, tk.END)
    self.rename_entry.bind('<Return>', lambda event: self.end_rename(table_name))
    self.rename_entry.bind('<FocusOut>', lambda event: self.cancel_rename())

def end_rename(self, old_name: str):
    """Finalize table renaming."""
    new_name = self.rename_entry.get().strip()
    if not new_name:
        messagebox.showerror("Invalid Name", "Table name cannot be empty.")
        self.rename_entry.focus_set()
        return
    if new_name in self.tables_data and new_name != old_name:
        messagebox.showerror("Duplicate Name", f"A table named '{new_name}' already exists.")
        self.rename_entry.focus_set()
        return
    if new_name != old_name:
        self.update_table_name(old_name, new_name)
        self.load_selected_table(new_name)
    self.cancel_rename()

def update_table_name(self, old_name: str, new_name: str):
    """Update table name and resources."""
    self.tables_data[new_name] = self.tables_data.pop(old_name)
    self.headers[new_name] = self.headers.pop(old_name)
    label = self.table_labels.pop(old_name)
    label.config(text=new_name)
    label.bind("<Button-1>", lambda event: self.load_selected_table(new_name))
    label.bind("<Double-1>", lambda event: self.begin_rename(new_name))
    self.table_labels[new_name] = label
    if self.selected_table_label == label:
        try:
            label.config(bg=self.button_color_selected)
        except tk.TclError:
            pass
    self.save_data()

def cancel_rename(self):
    """Cancel rename operation."""
    if self.rename_entry:
        self.rename_entry.destroy()
        self.rename_entry = None

def add_custom_hover(self, label: tk.Label):
    """Add hover effects to label."""
    def on_enter(event):
        if label != self.selected_table_label:
            try:
                label.config(bg=self.button_color_selected)
            except tk.TclError:
                pass

    def on_leave(event):
        if label != self.selected_table_label:
            try:
                label.config(bg=self.button_color)
            except tk.TclError:
                pass

    label.bind("<Enter>", on_enter)
    label.bind("<Leave>", on_leave)

def config_scrollbar_style(self):
    """Configure scrollbar style."""
    self.style = ttk.Style()
    self.style.theme_use("default")
    self.style.configure("Custom.Vertical.TScrollbar", troughcolor=self.sidebar_color, background="#c0c1c4", borderwidth=0, arrowcolor=self.text_color)
    self.style.map("Custom.Vertical.TScrollbar", background=[('active', '#878789')])
    self.style.layout("Custom.Vertical.TScrollbar", [('Vertical.Scrollbar.trough', {'children': [('Vertical.Scrollbar.thumb', {'expand': '1', 'sticky': 'ns'})], 'sticky': 'ns'})])

if name == "main":
set_dpi_awareness()
root = tk.Tk()
app = TableApp(root)
root.mainloop()