SXXXXXXX_PyMsc/pymsc/utils/gui_helpers.py

119 lines
3.4 KiB
Python

# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk
from typing import Any
class ScrollableFrame(ttk.Frame):
"""
A reusable frame with vertical and horizontal scrollbars.
Configured to expand and fill the entire available space.
"""
def __init__(self, parent: tk.Widget, controller: Any, **kwargs):
super().__init__(parent, **kwargs)
self.controller = controller
# Container for canvas and scrollbars
self.main_container = ttk.Frame(self)
self.main_container.pack(fill=tk.BOTH, expand=True)
# Create Canvas
self.canvas = tk.Canvas(self.main_container, highlightthickness=0)
# Create Scrollbars
self.v_scroll = ttk.Scrollbar(
self.main_container,
orient=tk.VERTICAL,
command=self.canvas.yview
)
self.h_scroll = ttk.Scrollbar(
self,
orient=tk.HORIZONTAL,
command=self.canvas.xview
)
# Content frame inside the canvas
self.scrollable_content = ttk.Frame(self.canvas)
# Bindings for dynamic resize
self.scrollable_content.bind(
"<Configure>",
lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
)
# Create window inside canvas
self.canvas_window = self.canvas.create_window(
(0, 0),
window=self.scrollable_content,
anchor="nw"
)
# Ensure content frame matches canvas width for better layout
self.canvas.bind("<Configure>", self._on_canvas_configure)
self.canvas.configure(
yscrollcommand=self.v_scroll.set,
xscrollcommand=self.h_scroll.set
)
# Layout management
self.v_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.h_scroll.pack(side=tk.BOTTOM, fill=tk.X)
def _on_canvas_configure(self, event):
"""Adjusts the internal window width to match the canvas."""
self.canvas.itemconfig(self.canvas_window, width=event.width)
def add_title_to_frame(
frame: tk.Widget,
text: str,
side: str = 'left',
thickness: int = 20,
bg_color: str = 'lightgrey',
font_color: str = 'black'
):
"""
Adds a vertical or horizontal title bar to an existing frame.
"""
def draw_text(event):
canvas.delete("all")
if side in ['left', 'right']:
x_pos = thickness // 2
y_pos = event.height // 2
angle = 90 if side == 'left' else 270
anchor = 'center'
else:
x_pos = event.width // 2
y_pos = thickness // 2
angle = 0
anchor = 'center'
canvas.create_text(
x_pos,
y_pos,
text=text,
angle=angle,
anchor=anchor,
fill=font_color,
font=('Helvetica', thickness // 2, 'bold')
)
if side in ['left', 'right']:
cw, ch = thickness, 10
pack_side = side
fill_type = 'y'
else:
cw, ch = 10, thickness
pack_side = 'top' if side == 'top' else 'bottom'
fill_type = 'x'
canvas = tk.Canvas(
frame,
width=cw,
height=ch,
bg=bg_color,
bd=0,
highlightthickness=0
)
canvas.pack(side=pack_side, fill=fill_type)
canvas.bind("<Configure>", draw_text)