152 lines
4.9 KiB
Python
152 lines
4.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""UI控件模块 - StatusBar、ProgressReporter、可折叠框架等"""
|
|
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
|
|
from .theme import THEMES, get_theme_mode
|
|
|
|
|
|
class StatusBar(tk.Frame):
|
|
"""状态栏,显示当前系统状态和进度"""
|
|
|
|
def __init__(self, master, **kwargs):
|
|
super().__init__(master, **kwargs)
|
|
self.configure(height=25, relief=tk.SUNKEN, borderwidth=1)
|
|
|
|
self.status_label = tk.Label(self, text="就绪", anchor=tk.W, padx=5)
|
|
self.status_label.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
|
|
|
self.progress = ttk.Progressbar(self, orient=tk.HORIZONTAL, length=200, mode='determinate')
|
|
self.progress.pack(side=tk.RIGHT, padx=5, pady=2)
|
|
|
|
self.progress.pack_forget()
|
|
|
|
def set_status(self, text, progress=None):
|
|
"""设置状态栏文本和进度"""
|
|
self.status_label.config(text=text)
|
|
|
|
if progress is not None and 0 <= progress <= 100:
|
|
self.progress.pack(side=tk.RIGHT, padx=5, pady=2)
|
|
self.progress.config(value=progress)
|
|
else:
|
|
self.progress.pack_forget()
|
|
|
|
def set_running(self, is_running=True):
|
|
"""设置运行状态"""
|
|
theme = THEMES[get_theme_mode()]
|
|
if is_running:
|
|
self.status_label.config(text="处理中...", foreground=theme["info"])
|
|
self.progress.pack(side=tk.RIGHT, padx=5, pady=2)
|
|
self.progress.config(mode='indeterminate')
|
|
self.progress.start()
|
|
else:
|
|
self.status_label.config(text="就绪", foreground=theme["fg"])
|
|
self.progress.stop()
|
|
self.progress.pack_forget()
|
|
|
|
|
|
class ProgressReporter:
|
|
def __init__(self, status_bar: StatusBar):
|
|
self.status_bar = status_bar
|
|
|
|
def set(self, text: str, percent: int = None):
|
|
try:
|
|
if percent is not None:
|
|
self.status_bar.set_status(text, percent)
|
|
else:
|
|
self.status_bar.set_status(text)
|
|
except Exception:
|
|
pass
|
|
|
|
def running(self):
|
|
try:
|
|
self.status_bar.set_running(True)
|
|
except Exception:
|
|
pass
|
|
|
|
def done(self):
|
|
try:
|
|
self.status_bar.set_running(False)
|
|
self.status_bar.set_status("就绪")
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
class ToolTip:
|
|
"""给组件添加悬停提示"""
|
|
def __init__(self, widget, text):
|
|
self.widget = widget
|
|
self.text = text
|
|
self.tip_window = None
|
|
self.widget.bind("<Enter>", self.show_tip)
|
|
self.widget.bind("<Leave>", self.hide_tip)
|
|
|
|
def show_tip(self, event=None):
|
|
if self.tip_window or not self.text:
|
|
return
|
|
x, y, _cx, cy = self.widget.bbox("insert")
|
|
x = x + self.widget.winfo_rootx() + 27
|
|
y = y + cy + self.widget.winfo_rooty() + 27
|
|
self.tip_window = tw = tk.Toplevel(self.widget)
|
|
tw.wm_overrideredirect(1)
|
|
tw.wm_geometry("+%d+%d" % (x, y))
|
|
label = tk.Label(tw, text=self.text, justify=tk.LEFT,
|
|
background="#ffffe0", relief=tk.SOLID, borderwidth=1,
|
|
font=("tahoma", "8", "normal"), padx=4, pady=2)
|
|
label.pack(ipadx=1)
|
|
|
|
def hide_tip(self, event=None):
|
|
tw = self.tip_window
|
|
self.tip_window = None
|
|
if tw:
|
|
tw.destroy()
|
|
|
|
|
|
def create_collapsible_frame(parent, title, initial_state=True):
|
|
"""创建可折叠的面板"""
|
|
frame = tk.Frame(parent)
|
|
frame.pack(fill=tk.X, pady=5)
|
|
|
|
title_frame = tk.Frame(frame)
|
|
title_frame.pack(fill=tk.X)
|
|
|
|
state_var = tk.BooleanVar(value=initial_state)
|
|
indicator = "▼" if initial_state else "►"
|
|
state_label = tk.Label(title_frame, text=indicator, font=("Arial", 10, "bold"))
|
|
state_label.pack(side=tk.LEFT, padx=5)
|
|
|
|
title_label = tk.Label(title_frame, text=title, font=("Arial", 11, "bold"))
|
|
title_label.pack(side=tk.LEFT, padx=5)
|
|
|
|
content_frame = tk.Frame(frame)
|
|
if initial_state:
|
|
content_frame.pack(fill=tk.X, padx=20, pady=5)
|
|
|
|
def toggle_collapse(event=None):
|
|
current_state = state_var.get()
|
|
new_state = not current_state
|
|
state_var.set(new_state)
|
|
state_label.config(text="▼" if new_state else "►")
|
|
if new_state:
|
|
content_frame.pack(fill=tk.X, padx=20, pady=5)
|
|
else:
|
|
content_frame.pack_forget()
|
|
|
|
title_frame.bind("<Button-1>", toggle_collapse)
|
|
state_label.bind("<Button-1>", toggle_collapse)
|
|
title_label.bind("<Button-1>", toggle_collapse)
|
|
|
|
return content_frame, state_var
|
|
|
|
|
|
def center_window(window):
|
|
"""使窗口居中显示"""
|
|
window.update_idletasks()
|
|
width = window.winfo_width()
|
|
height = window.winfo_height()
|
|
x = (window.winfo_screenwidth() // 2) - (width // 2)
|
|
y = (window.winfo_screenheight() // 2) - (height // 2)
|
|
window.geometry('{}x{}+{}+{}'.format(width, height, x, y))
|