2.2.0
This commit is contained in:
815
main.py
815
main.py
@@ -1,5 +1,5 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from tkinter import ttk, messagebox, filedialog
|
||||
import yaml
|
||||
import colorama
|
||||
import threading
|
||||
@@ -7,36 +7,42 @@ import random
|
||||
import time
|
||||
import sys
|
||||
import csv
|
||||
import json
|
||||
import functools
|
||||
from PIL import Image
|
||||
Image.CUBIC = Image.BICUBIC
|
||||
#Image.CUBIC = Resampling.BICUBIC
|
||||
import ttkbootstrap as tb
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
marking_buttons = list()
|
||||
version='v2.1'
|
||||
config = None
|
||||
current_member = dict()
|
||||
member_sum = 0
|
||||
stdtime = 0.1
|
||||
random_stop = 0
|
||||
LICENSE = None
|
||||
member = None
|
||||
is_paused = 1
|
||||
is_tab_shown = 0
|
||||
default_tab_layout = None
|
||||
is_first = 1
|
||||
db = None
|
||||
marking_colormark = dict() # 标记颜色序号
|
||||
is_dark = None
|
||||
mk_fg = []
|
||||
mk_bg = []
|
||||
btnbg = None
|
||||
style = None
|
||||
btnfg = None
|
||||
ttkthemename = None
|
||||
about_text = f"""CLASSAUX - 幸运选手α
|
||||
带轻量级数据库和随机功能的教学管理辅助程序 版本 {version}
|
||||
class ClassAuxApp:
|
||||
def __init__(self):
|
||||
self.version = 'v2.7.0 Dev'
|
||||
self.config = None
|
||||
self.current_member = {"pause": None, "show": "", "genuine": ""}
|
||||
self.member_sum = 0
|
||||
self.stdtime = 0.1
|
||||
self.random_stop = 0
|
||||
self.LICENSE = None
|
||||
self.member = None
|
||||
self.is_paused = 1
|
||||
self.is_tab_shown = 1
|
||||
self.default_tab_layout = None
|
||||
self.is_first = 1
|
||||
self.db = None
|
||||
self.marking_colormark = dict()
|
||||
self.is_dark = None
|
||||
self.mk_fg = []
|
||||
self.mk_bg = []
|
||||
self.btnbg = None
|
||||
self.style = None
|
||||
self.btnfg = None
|
||||
self.ttkthemename = None
|
||||
self.marking_buttons = []
|
||||
self.omember = None
|
||||
|
||||
self.about_text = f"""CLASSAUX - 抽取软件 改进型
|
||||
带轻量级数据库和随机功能的教学管理辅助程序 版本 {self.version}
|
||||
版权所有 (C) 2025 Wang Zhiyu
|
||||
本程序为共产版权的自由软件, 在自由软件联盟发布的GNU通用公共许可协议的约束下,
|
||||
你可以对其进行再发布及修改。协议版本为第三版。
|
||||
@@ -50,6 +56,7 @@ Colorama - Cross-platform colored terminal text
|
||||
Tkinter - Python interface to Tcl/Tk
|
||||
Pillow - Python Imaging Library
|
||||
PyYaml - YAML parser and emitter for Python
|
||||
TTkBootstrap - Bootstrap-themed widgets for Tkinter
|
||||
Sarasa Gothic (更纱黑体)
|
||||
--------------------------------------------------------------------------------
|
||||
开源软件是一项立足于协作精神的事业,
|
||||
@@ -58,330 +65,452 @@ Sarasa Gothic (更纱黑体)
|
||||
开放源代码/报告程序缺陷: https://github.com/david-ajax/classaux
|
||||
--------------------------------------------------------------------------------
|
||||
"""
|
||||
current_member["pause"] = None
|
||||
current_member["show"] = ""
|
||||
|
||||
|
||||
def init_theme():
|
||||
global ttkthemename
|
||||
global mk_bg
|
||||
global mk_fg
|
||||
global style
|
||||
global btnfg
|
||||
global btnbg
|
||||
global sbtnfg
|
||||
global sbtnbg
|
||||
if not is_dark:
|
||||
mk_bg = ["#FFFFFF","#009900","#ff6666","#0088ff"]
|
||||
mk_fg = ["#000000","#FFFFFF","#FFFFFF","#FFFFFF"]
|
||||
ttkthemename = "cosmo"
|
||||
btnbg = [('pressed', '#2097ff'), ('active', '#9bcbff')]
|
||||
btnfg = [('pressed', 'white'), ('active', '#36393b')]
|
||||
sbtnbg = 'white'
|
||||
sbtnfg = '#36393b'
|
||||
else:
|
||||
mk_fg = ["#FFFFFF","#00ff00","#ff6666","#9999ff"]
|
||||
mk_bg = ["#202020","#005500","#550000","#000055"]
|
||||
ttkthemename = "darkly"
|
||||
btnbg = [('pressed', '#242424'), ('active', '#242424')]
|
||||
btnfg = [('pressed', '#FFFFFF'), ('active', '#dddddd')]
|
||||
sbtnbg = "#202020"
|
||||
sbtnfg = 'white'
|
||||
|
||||
def matrix_gen(format):
|
||||
ttmem = list()
|
||||
tmem = list()
|
||||
mem = list(config["member"])
|
||||
random.shuffle(mem)
|
||||
print(list(enumerate(mem)))
|
||||
for i, ele in enumerate(mem):
|
||||
tmem.append(ele["name"])
|
||||
if i % 8 == 0:
|
||||
ttmem.append(tmem)
|
||||
tmem = list()
|
||||
ttmem.reverse()
|
||||
omember = None
|
||||
def random_gen():
|
||||
global config
|
||||
global current_member
|
||||
global random_stop
|
||||
global member
|
||||
member = config['member']
|
||||
while not random_stop:
|
||||
#print("重置列表")
|
||||
random.shuffle(member)
|
||||
#print(member)
|
||||
for i in member:
|
||||
if random_stop:
|
||||
break
|
||||
#print(i)
|
||||
if i['weight'] == 0:
|
||||
pass
|
||||
else:
|
||||
for k in range(0, i['weight']):
|
||||
current_member["genuine"] = i['name']
|
||||
time.sleep(stdtime)
|
||||
|
||||
def interface():
|
||||
global btnfg
|
||||
global btnbg
|
||||
global style
|
||||
global ttkthemename
|
||||
global sbtnbg
|
||||
global sbtnfg
|
||||
root = tb.Window(themename=ttkthemename)
|
||||
#root = tk.Tk()
|
||||
root.iconphoto(False, tk.PhotoImage(file='logo.png'))
|
||||
style = tb.Style()
|
||||
style.configure("Marking.TButton", background=sbtnbg, foreground=sbtnfg)
|
||||
style.map("Marking.TButton",
|
||||
background=btnbg,
|
||||
foreground=btnfg)
|
||||
style.configure("TabToggle.TButton", background=sbtnbg, foreground=sbtnfg)
|
||||
style.map("TabToggle.TButton",
|
||||
background=btnbg,
|
||||
foreground=btnfg)
|
||||
root.title(f"幸运选手α {version}")
|
||||
root.geometry("800x600")
|
||||
notebook = ttk.Notebook(root)
|
||||
notebook.pack(padx=10, pady=10)
|
||||
tab_electing = tk.Frame(notebook, width=800, height=600)
|
||||
tab_marking = tk.Frame(notebook, width=800, height=600)
|
||||
tab_about = tk.Frame(notebook, width=800, height=600)
|
||||
tab_bat = tk.Frame(notebook, width=800, height=600)
|
||||
tab_edit = tk.Frame(notebook, width=800, height=600)
|
||||
tab_filter = tk.Frame(notebook, width=800, height=600)
|
||||
tab_migration = tk.Frame(notebook, width=800, height=600)
|
||||
tab_cfg = tk.Frame(notebook, width=800, height=600)
|
||||
notebook.add(tab_electing, text='单次抽签')
|
||||
notebook.add(tab_marking, text='标记视图')
|
||||
notebook.add(tab_bat, text='批量视图')
|
||||
notebook.add(tab_edit, text='编辑数据库')
|
||||
notebook.add(tab_filter, text='配置筛选器')
|
||||
notebook.add(tab_cfg, text='设置')
|
||||
notebook.add(tab_migration, text='转换兼容配置')
|
||||
notebook.add(tab_about, text='关于')
|
||||
marking_colormode = tk.StringVar()
|
||||
bat_formationmode = tk.StringVar()
|
||||
bat_attrmode = tk.StringVar()
|
||||
chosen_attr = tk.StringVar()
|
||||
def update_data():
|
||||
global is_paused
|
||||
if not is_paused:
|
||||
wdgt[tab_electing][0].config(text=config['member'][random.randint(0, member_sum - 1)]["name"])
|
||||
else:
|
||||
wdgt[tab_electing][0].config(text=current_member["show"])
|
||||
wdgt[tab_electing][0].after(int(1000 * stdtime * 0.75), update_data)
|
||||
|
||||
def on_closing():
|
||||
root.destroy()
|
||||
global random_stop
|
||||
random_stop = 1
|
||||
|
||||
self.init_console()
|
||||
self.load_config()
|
||||
self.init_theme()
|
||||
|
||||
def init_console(self):
|
||||
"""初始化控制台输出"""
|
||||
print("确保此终端支持 UTF-8 字符输出!")
|
||||
print(f"抽取程序 {self.version}")
|
||||
print("开放源代码: https://github.com/david-ajax/classaux")
|
||||
|
||||
def load_config(self):
|
||||
"""加载配置文件"""
|
||||
try:
|
||||
print("读取 YAML 配置文件与 GPL 协议 ", end="")
|
||||
with open("COPYING", encoding='utf-8') as license_file:
|
||||
self.LICENSE = license_file.read()
|
||||
|
||||
with open("config.yaml", encoding='utf-8') as config_file:
|
||||
self.config = yaml.safe_load(config_file)
|
||||
self.omember = list(self.config['member'])
|
||||
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
|
||||
# 加载数据库
|
||||
db_file = self.config['info'].get('db', 'db.csv')
|
||||
print(f"读取数据库 {db_file} ", end="")
|
||||
self.load_database(db_file)
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
|
||||
print(f"配置文件: {self.config['info']['name']}")
|
||||
self.member_sum = len(self.config['member'])
|
||||
print(f"成员人数: {self.member_sum}")
|
||||
print(f"随机刻间隔时间: {self.stdtime}s")
|
||||
|
||||
except Exception as e:
|
||||
print(colorama.Fore.RED + f"失败: {e}" + colorama.Style.RESET_ALL)
|
||||
sys.exit(1)
|
||||
|
||||
def toggle(): # 仅用于单次抽取模式
|
||||
global is_paused
|
||||
if not is_paused:
|
||||
current_member["show"] = current_member["genuine"]
|
||||
is_paused = 1
|
||||
wdgt[tab_electing][1].config(text="开始")
|
||||
def load_database(self, db_file):
|
||||
"""加载数据库文件"""
|
||||
try:
|
||||
with open(db_file, encoding='utf-8-sig') as db_file:
|
||||
self.db = list(csv.reader(db_file, delimiter=',', quotechar='"'))
|
||||
# 过滤注释行
|
||||
self.db = [row for row in self.db if row[0] != 'NOTE']
|
||||
except FileNotFoundError:
|
||||
print(colorama.Fore.YELLOW + "数据库文件不存在,创建空数据库" + colorama.Style.RESET_ALL)
|
||||
self.db = []
|
||||
|
||||
def init_theme(self):
|
||||
"""初始化主题设置"""
|
||||
self.is_dark = self.config.get("darkmode", False)
|
||||
|
||||
if not self.is_dark:
|
||||
self.mk_bg = ["#FFFFFF", "#009900", "#ff6666", "#0088ff", "#FFA500"]
|
||||
self.mk_fg = ["#000000", "#FFFFFF", "#FFFFFF", "#FFFFFF", "#000000"]
|
||||
self.ttkthemename = "cosmo"
|
||||
self.btnbg = [('pressed', '#2097ff'), ('active', '#9bcbff')]
|
||||
self.btnfg = [('pressed', 'white'), ('active', '#36393b')]
|
||||
self.sbtnbg = 'white'
|
||||
self.sbtnfg = '#36393b'
|
||||
else:
|
||||
wdgt[tab_electing][1].config(text="暂停")
|
||||
is_paused = 0
|
||||
|
||||
def toggle_menu():
|
||||
global is_tab_shown
|
||||
global default_tab_layout
|
||||
if not is_tab_shown:
|
||||
style.layout('TNotebook.Tab', default_tab_layout)
|
||||
is_tab_shown = 1
|
||||
self.mk_fg = ["#FFFFFF", "#00ff00", "#ff6666", "#9999ff", "#FFA500"]
|
||||
self.mk_bg = ["#202020", "#005500", "#550000", "#000055", "#333300"]
|
||||
self.ttkthemename = "darkly"
|
||||
self.btnbg = [('pressed', '#242424'), ('active', '#242424')]
|
||||
self.btnfg = [('pressed', '#FFFFFF'), ('active', '#dddddd')]
|
||||
self.sbtnbg = "#202020"
|
||||
self.sbtnfg = 'white'
|
||||
|
||||
def random_gen(self):
|
||||
"""随机生成器线程函数"""
|
||||
self.member = self.config['member']
|
||||
while not self.random_stop:
|
||||
random.shuffle(self.member)
|
||||
for i in self.member:
|
||||
if self.random_stop:
|
||||
break
|
||||
if i['weight'] > 0:
|
||||
for k in range(i['weight']):
|
||||
self.current_member["genuine"] = i['name']
|
||||
time.sleep(self.stdtime)
|
||||
|
||||
def matrix_gen(self, format_type="linear"):
|
||||
"""生成矩阵/列表视图"""
|
||||
members = list(self.config["member"])
|
||||
random.shuffle(members)
|
||||
|
||||
if format_type == "linear":
|
||||
return "\n".join([f"{i+1}. {member['name']}" for i, member in enumerate(members)])
|
||||
elif format_type == "ascii_table":
|
||||
# 简单的ASCII表格
|
||||
table = "序号 | 姓名\n" + "-" * 20 + "\n"
|
||||
for i, member in enumerate(members):
|
||||
table += f"{i+1:3} | {member['name']}\n"
|
||||
return table
|
||||
elif format_type == "csv":
|
||||
return "序号,姓名\n" + "\n".join([f"{i+1},{member['name']}" for i, member in enumerate(members)])
|
||||
elif format_type == "markdown":
|
||||
return "| 序号 | 姓名 |\n|-----|------|\n" + "\n".join([f"| {i+1} | {member['name']} |" for i, member in enumerate(members)])
|
||||
else:
|
||||
style.layout('TNotebook.Tab', [])
|
||||
is_tab_shown = 0
|
||||
return "\n".join([member['name'] for member in members])
|
||||
|
||||
def export_to_file(self, content, file_type="txt"):
|
||||
"""导出内容到文件"""
|
||||
try:
|
||||
filename = filedialog.asksaveasfilename(
|
||||
defaultextension=f".{file_type}",
|
||||
filetypes=[(f"{file_type.upper()} files", f"*.{file_type}")]
|
||||
)
|
||||
if filename:
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
messagebox.showinfo("成功", f"文件已导出到: {filename}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("错误", f"导出失败: {e}")
|
||||
|
||||
def copy_to_clipboard(self, content):
|
||||
"""复制内容到剪贴板"""
|
||||
try:
|
||||
self.root.clipboard_clear()
|
||||
self.root.clipboard_append(content)
|
||||
messagebox.showinfo("成功", "内容已复制到剪贴板")
|
||||
except Exception as e:
|
||||
messagebox.showerror("错误", f"复制失败: {e}")
|
||||
|
||||
def marking_change_color(self, button):
|
||||
"""标记视图中的颜色切换"""
|
||||
if id(button) not in self.marking_colormark:
|
||||
self.marking_colormark[id(button)] = 0
|
||||
|
||||
current_color = self.marking_colormark[id(button)]
|
||||
next_color = (current_color + 1) % len(self.mk_bg)
|
||||
self.marking_colormark[id(button)] = next_color
|
||||
|
||||
# 创建新的样式
|
||||
style_name = f"MarkingX{id(button)}.TButton"
|
||||
self.style.configure(style_name,
|
||||
background=self.mk_bg[next_color],
|
||||
foreground=self.mk_fg[next_color])
|
||||
self.style.map(style_name,
|
||||
background=[('pressed', self.mk_bg[next_color]),
|
||||
('active', self.mk_bg[next_color])],
|
||||
foreground=[('pressed', self.mk_fg[next_color]),
|
||||
('active', self.mk_fg[next_color])])
|
||||
button.config(style=style_name)
|
||||
|
||||
def marking_clear(self):
|
||||
"""清空所有标记"""
|
||||
self.marking_colormark.clear()
|
||||
for button in self.marking_buttons:
|
||||
self.marking_change_color(button)
|
||||
|
||||
def toggle(self):
|
||||
"""切换抽取状态"""
|
||||
if not self.is_paused:
|
||||
self.current_member["show"] = self.current_member["genuine"]
|
||||
self.is_paused = 1
|
||||
self.electing_button.config(text="开始")
|
||||
else:
|
||||
self.electing_button.config(text="暂停")
|
||||
self.is_paused = 0
|
||||
|
||||
def toggle_menu(self):
|
||||
"""切换选项卡显示"""
|
||||
if not self.is_tab_shown:
|
||||
self.style.layout('TNotebook.Tab', self.default_tab_layout)
|
||||
self.is_tab_shown = 1
|
||||
else:
|
||||
self.style.layout('TNotebook.Tab', [])
|
||||
self.is_tab_shown = 0
|
||||
|
||||
def toggle_dark(self):
|
||||
"""切换暗色模式"""
|
||||
self.is_dark = not self.is_dark
|
||||
self.config["darkmode"] = self.is_dark
|
||||
self.init_theme()
|
||||
self.style.theme_use(self.ttkthemename)
|
||||
self.marking_clear()
|
||||
self.is_tab_shown = not self.is_tab_shown
|
||||
self.toggle_menu()
|
||||
|
||||
# 保存主题设置
|
||||
self.save_config()
|
||||
|
||||
def save_config(self):
|
||||
"""保存配置到文件"""
|
||||
try:
|
||||
with open("config.yaml", 'w', encoding='utf-8') as f:
|
||||
yaml.dump(self.config, f, allow_unicode=True, default_flow_style=False)
|
||||
except Exception as e:
|
||||
print(f"保存配置失败: {e}")
|
||||
|
||||
def update_data(self):
|
||||
"""更新显示数据"""
|
||||
if not self.is_paused:
|
||||
self.electing_label.config(text=random.choice(self.config['member'])["name"])
|
||||
else:
|
||||
self.electing_label.config(text=self.current_member["show"])
|
||||
self.electing_label.after(int(1000 * self.stdtime * 0.75), self.update_data)
|
||||
|
||||
def create_interface(self):
|
||||
"""创建主界面"""
|
||||
self.root = tb.Window(themename=self.ttkthemename)
|
||||
self.root.title(f"抽取程序 {self.version}")
|
||||
self.root.geometry("900x700")
|
||||
|
||||
# 设置图标
|
||||
try:
|
||||
self.root.iconphoto(False, tk.PhotoImage(file='logo.png'))
|
||||
except:
|
||||
pass
|
||||
|
||||
# 创建样式
|
||||
self.style = tb.Style()
|
||||
self.setup_styles()
|
||||
|
||||
def toggle_dark():
|
||||
global style
|
||||
global is_dark
|
||||
global ttkthemename
|
||||
global btnbg
|
||||
global btnfg
|
||||
global sbtnbg
|
||||
global sbtnfg
|
||||
global is_tab_shown
|
||||
is_dark = not is_dark
|
||||
init_theme()
|
||||
style.theme_use(ttkthemename)
|
||||
style.configure("Marking.TButton", background=sbtnbg, foreground=sbtnfg)
|
||||
style.map("Marking.TButton",
|
||||
background=btnbg,
|
||||
foreground=btnfg)
|
||||
style.configure("TabToggle.TButton", background=sbtnbg, foreground=sbtnfg)
|
||||
style.map("TabToggle.TButton",
|
||||
background=btnbg,
|
||||
foreground=btnfg)
|
||||
marking_clear()
|
||||
is_tab_shown = not is_tab_shown
|
||||
toggle_menu()
|
||||
def marking_clear():
|
||||
global style
|
||||
global marking_buttons
|
||||
marking_colormark.clear()
|
||||
for i in marking_buttons:
|
||||
marking_change_color(i)
|
||||
wdgt = {
|
||||
tab_electing: [
|
||||
ttk.Label(tab_electing, text="待抽取", font=("Sarasa UI SC", 70, 'bold')),
|
||||
ttk.Button(tab_electing, text="开始", command=toggle),
|
||||
ttk.Button(tab_electing, text="选项卡", command=toggle_menu,style="TabToggle.TButton"),
|
||||
ttk.Button(tab_electing, text="暗色调", command=toggle_dark,style="TabToggle.TButton"),
|
||||
],
|
||||
tab_about: [
|
||||
tk.Text(tab_about, wrap=tk.WORD,font=("Sarasa UI SC", 10, '')),
|
||||
#ttk.Label(tab_about, text=about_text)
|
||||
],
|
||||
tab_edit: [tk.Text(tab_about, wrap=tk.WORD,font=("Sarasa UI Mono SC", 10, '')),
|
||||
],
|
||||
tab_marking: [
|
||||
ttk.Button(tab_marking, text="清空",command=marking_clear),
|
||||
ttk.Checkbutton(tab_marking, text="只读模式", onvalue=1, offvalue=0,cursor="arrow",state="normal"),
|
||||
ttk.Combobox(tab_marking, textvariable=marking_colormode, values=("双值模式", "三值模式", "五值模式"))
|
||||
],
|
||||
tab_bat: [
|
||||
tk.Text(tab_bat),
|
||||
ttk.Button(tab_bat, text="生成新随机", command=matrix_gen),
|
||||
ttk.Button(tab_bat, text="复制到剪贴板",style="TabToggle.TButton"),
|
||||
ttk.Button(tab_bat, text="导出至文件 (CSV/TXT)",style="TabToggle.TButton"),
|
||||
ttk.Combobox(tab_bat, textvariable=bat_formationmode, values=("选择格式...", "线性列表", "ASCII 表格", "CSV (逗号分隔)", "Markdown 表格")),
|
||||
ttk.Combobox(tab_bat, textvariable=bat_attrmode, values=("选择随机项...", "姓名", "性别", "居住"))
|
||||
],
|
||||
tab_filter: [
|
||||
ttk.Combobox(tab_filter,textvariable=chosen_attr, values=["选择筛选项...","示例1","示例2"]),
|
||||
ttk.Label(tab_filter, text="属性: 无"),
|
||||
ttk.Label(tab_filter, text="类型: 无"),
|
||||
ttk.Label(tab_filter, text="注意: 更改是实时的")
|
||||
],
|
||||
tab_migration: [
|
||||
ttk.Combobox(tab_filter,textvariable=chosen_attr, values=["选择兼容的配置文件格式...","示例1","示例2"]),
|
||||
ttk.Label(tab_filter, text="支持的文件格式: TXT 姓名列表(回车分隔), 标准 CSV 文件"),
|
||||
],
|
||||
tab_cfg: [
|
||||
ttk.Label(tab_cfg, text="外观",font=("Sarasa UI SC", 14, 'bold')),
|
||||
ttk.Label(tab_cfg, text="功能",font=("Sarasa UI SC", 14, 'bold')),
|
||||
ttk.Label(tab_cfg, text="调试",font=("Sarasa UI SC", 14, 'bold')),
|
||||
ttk.Combobox(tab_cfg, values=["选择主题", "cosmo (默认)", "flatly", "darkly"]),
|
||||
ttk.Combobox(tab_cfg, values=["选择字体", "更纱黑体 (默认)", "系统默认字体"]),
|
||||
]
|
||||
}
|
||||
# 创建笔记本(选项卡)
|
||||
self.create_notebook()
|
||||
|
||||
wdgt[tab_electing][0].place(relx=0.5, rely=0.35, anchor='center')
|
||||
wdgt[tab_electing][1].place(relx=0.5, rely=0.8, relwidth=0.25, relheight=0.15, anchor='center')
|
||||
wdgt[tab_electing][2].place(relx=0.01, rely=0.99, relwidth=0.12, relheight=0.08, anchor='sw')
|
||||
wdgt[tab_electing][3].place(relx=0.99, rely=0.99, relwidth=0.12, relheight=0.08, anchor='se')
|
||||
if self.default_tab_layout == None:
|
||||
self.default_tab_layout = self.style.layout('TNotebook.Tab')
|
||||
|
||||
wdgt[tab_about][0].insert(tk.END, about_text,"center")
|
||||
wdgt[tab_about][0].insert(tk.END, LICENSE)
|
||||
wdgt[tab_about][0].grid(row=1, column=0, sticky=tk.N)
|
||||
wdgt[tab_about][0].configure(state="disabled")
|
||||
self.toggle_menu()
|
||||
|
||||
wdgt[tab_bat][4].current(0)
|
||||
wdgt[tab_bat][1].place(relx=0.5, rely=0.845, relwidth=0.25, relheight=0.13, anchor='n')
|
||||
wdgt[tab_bat][2].place(relx=0.99, rely=0.99, relwidth=0.3, relheight=0.08, anchor='se')
|
||||
wdgt[tab_bat][3].place(relx=0.99, rely=0.91, relwidth=0.3, relheight=0.08, anchor='se')
|
||||
wdgt[tab_bat][4].place(relx=0.01, rely=0.91, relwidth=0.3, relheight=0.08, anchor='sw')
|
||||
wdgt[tab_bat][5].place(relx=0.01, rely=0.99, relwidth=0.3, relheight=0.08, anchor='sw')
|
||||
wdgt[tab_bat][0].place(relx=0.03, rely=0.03, relwidth=0.94, relheight=0.79, anchor='nw')
|
||||
# 初始化各个选项卡
|
||||
self.create_electing_tab()
|
||||
self.create_marking_tab()
|
||||
self.create_batch_tab()
|
||||
self.create_about_tab()
|
||||
self.create_edit_tab()
|
||||
self.create_config_tab()
|
||||
|
||||
# 设置关闭事件
|
||||
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
|
||||
# 启动数据更新
|
||||
self.update_data()
|
||||
self.root.mainloop()
|
||||
|
||||
def setup_styles(self):
|
||||
"""设置样式"""
|
||||
self.style.configure("Marking.TButton", background=self.sbtnbg, foreground=self.sbtnfg)
|
||||
self.style.map("Marking.TButton", background=self.btnbg, foreground=self.btnfg)
|
||||
self.style.configure("TabToggle.TButton", background=self.sbtnbg, foreground=self.sbtnfg)
|
||||
self.style.map("TabToggle.TButton", background=self.btnbg, foreground=self.btnfg)
|
||||
|
||||
def create_notebook(self):
|
||||
"""创建选项卡容器"""
|
||||
self.notebook = ttk.Notebook(self.root)
|
||||
self.notebook.pack(fill='both', expand=True, padx=10, pady=10)
|
||||
|
||||
# 创建各个选项卡框架
|
||||
self.tab_electing = tk.Frame(self.notebook)
|
||||
self.tab_marking = tk.Frame(self.notebook)
|
||||
self.tab_batch = tk.Frame(self.notebook)
|
||||
self.tab_edit = tk.Frame(self.notebook)
|
||||
self.tab_about = tk.Frame(self.notebook)
|
||||
self.tab_config = tk.Frame(self.notebook)
|
||||
|
||||
# 添加选项卡
|
||||
self.notebook.add(self.tab_electing, text='单次抽签')
|
||||
self.notebook.add(self.tab_marking, text='标记视图')
|
||||
self.notebook.add(self.tab_batch, text='批量视图')
|
||||
self.notebook.add(self.tab_edit, text='编辑数据库')
|
||||
self.notebook.add(self.tab_config, text='设置')
|
||||
self.notebook.add(self.tab_about, text='关于')
|
||||
|
||||
wdgt[tab_marking][0].place(relx=0.5, rely=1, relwidth=0.13, relheight=0.08, anchor='s')
|
||||
wdgt[tab_marking][1].place(relx=1, rely=1, relwidth=0.13, relheight=0.08, anchor='se')
|
||||
wdgt[tab_marking][2].place(relx=0, rely=1, relwidth=0.15, relheight=0.08, anchor='sw')
|
||||
wdgt[tab_marking][2].current(0)
|
||||
def marking_change_color(l):
|
||||
global style
|
||||
global marking_colormark
|
||||
global mk_bg
|
||||
global mk_fg
|
||||
if id(l) not in marking_colormark.keys():
|
||||
marking_colormark[id(l)] = 0
|
||||
style = tb.Style()
|
||||
style.configure(f"MarkingX{id(l)}.TButton", background=mk_bg[marking_colormark[id(l)]], foreground=mk_fg[marking_colormark[id(l)]])
|
||||
style.map(f"MarkingX{id(l)}.TButton",
|
||||
background=[('pressed', mk_bg[marking_colormark[id(l)]]), ('active', mk_bg[marking_colormark[id(l)]])],
|
||||
foreground=[('pressed', mk_fg[marking_colormark[id(l)]]), ('active', mk_fg[marking_colormark[id(l)]])])
|
||||
marking_colormark[id(l)] += 1
|
||||
marking_colormark[id(l)]%=len(mk_fg)
|
||||
# 应用样式
|
||||
l.config(style=f"MarkingX{id(l)}.TButton")
|
||||
global omember
|
||||
tmember = list(omember)
|
||||
for i in range((8 - len(member) % 8 )% 8):
|
||||
tmember.append({"name":"占位符"})
|
||||
for i, j in enumerate(tmember):
|
||||
if len(j["name"]) == 2:
|
||||
j["name"] = " " + j["name"] + " "
|
||||
# 创建按钮并赋值给 l
|
||||
l = ttk.Button(tab_marking, text=j["name"], style="Marking.TButton")
|
||||
marking_buttons.append(l)
|
||||
# 使用 partial 将 l 作为参数传递给回调函数
|
||||
marking_change_color(l)
|
||||
l.config(command=functools.partial(marking_change_color, l))
|
||||
l.grid(column=i % 8, row=i // 8, padx=5, pady=5)
|
||||
wdgt[tab_filter][0].current(0)
|
||||
wdgt[tab_filter][0].grid(column=0,row=0)
|
||||
wdgt[tab_filter][1].grid(column=0,row=1,sticky=tk.W,padx=5,pady=5)
|
||||
wdgt[tab_filter][2].grid(column=0,row=2,sticky=tk.W,padx=5,pady=5)
|
||||
wdgt[tab_filter][3].place(relx=0.01, rely=1, relwidth=1, relheight=0.08, anchor='sw')
|
||||
wdgt[tab_filter][0].grid(column=0,row=0,sticky=tk.W,padx=5,pady=5)
|
||||
wdgt[tab_filter][1].grid(column=0,row=1,sticky=tk.W,padx=5,pady=5)
|
||||
|
||||
wdgt[tab_cfg][0].grid(column=0, row=0, padx=5,pady=5,sticky=tk.W)
|
||||
wdgt[tab_cfg][1].grid(column=0, row=3, padx=5,pady=5,sticky=tk.W)
|
||||
wdgt[tab_cfg][2].grid(column=0, row=4, padx=5,pady=5,sticky=tk.W)
|
||||
wdgt[tab_cfg][3].grid(column=0, row=1, padx=5,pady=5,sticky=tk.W)
|
||||
wdgt[tab_cfg][4].grid(column=0, row=2, padx=5,pady=5,sticky=tk.W)
|
||||
|
||||
global is_first
|
||||
if is_first:
|
||||
global default_tab_layout
|
||||
default_tab_layout = style.layout('TNotebook.Tab')
|
||||
style.layout('TNotebook.Tab', [])
|
||||
is_first = 0
|
||||
root.protocol("WM_DELETE_WINDOW", on_closing)
|
||||
update_data()
|
||||
root.mainloop()
|
||||
def create_electing_tab(self):
|
||||
"""创建单次抽签选项卡"""
|
||||
# 主显示标签
|
||||
self.electing_label = ttk.Label(self.tab_electing, text="待抽取",
|
||||
font=("Sarasa UI SC", 70, 'bold'))
|
||||
self.electing_label.place(relx=0.5, rely=0.35, anchor='center')
|
||||
|
||||
# 控制按钮
|
||||
self.electing_button = ttk.Button(self.tab_electing, text="开始",
|
||||
command=self.toggle)
|
||||
self.electing_button.place(relx=0.5, rely=0.8, relwidth=0.25,
|
||||
relheight=0.15, anchor='center')
|
||||
|
||||
# 辅助按钮
|
||||
ttk.Button(self.tab_electing, text="选项卡", command=self.toggle_menu,
|
||||
style="TabToggle.TButton").place(relx=0.01, rely=0.99,
|
||||
relwidth=0.12, relheight=0.08, anchor='sw')
|
||||
|
||||
ttk.Button(self.tab_electing, text="暗色调", command=self.toggle_dark,
|
||||
style="TabToggle.TButton").place(relx=0.99, rely=0.99,
|
||||
relwidth=0.12, relheight=0.08, anchor='se')
|
||||
|
||||
def create_marking_tab(self):
|
||||
"""创建标记视图选项卡"""
|
||||
# 控制按钮
|
||||
ttk.Button(self.tab_marking, text="清空", command=self.marking_clear
|
||||
).place(relx=0.5, rely=0.99, relwidth=0.13,
|
||||
relheight=0.08, anchor='s')
|
||||
|
||||
# 标记按钮网格
|
||||
self.create_marking_grid()
|
||||
|
||||
def create_marking_grid(self):
|
||||
"""创建标记网格"""
|
||||
members = list(self.omember)
|
||||
# 补全到8的倍数
|
||||
for i in range((8 - len(members) % 8) % 8):
|
||||
members.append({"name": "占位符"})
|
||||
|
||||
for i, member in enumerate(members):
|
||||
# 创建标记按钮
|
||||
btn_text = f" {member['name']} " if len(member["name"]) == 2 else member["name"]
|
||||
button = ttk.Button(self.tab_marking, text=btn_text,
|
||||
style="Marking.TButton")
|
||||
|
||||
# 绑定点击事件
|
||||
button.config(command=functools.partial(self.marking_change_color, button))
|
||||
button.grid(column=i % 8, row=i // 8, padx=5, pady=5, sticky='nsew')
|
||||
|
||||
# 配置网格权重
|
||||
self.tab_marking.grid_columnconfigure(i % 8, weight=1)
|
||||
self.tab_marking.grid_rowconfigure(i // 8, weight=1)
|
||||
|
||||
self.marking_buttons.append(button)
|
||||
self.marking_change_color(button) # 初始化颜色
|
||||
|
||||
def create_batch_tab(self):
|
||||
"""创建批量视图选项卡"""
|
||||
# 结果显示文本框
|
||||
self.batch_text = tk.Text(self.tab_batch, wrap=tk.WORD, font=("Sarasa UI SC", 10))
|
||||
self.batch_text.place(relx=0.03, rely=0.03, relwidth=0.94, relheight=0.79)
|
||||
|
||||
# 格式选择
|
||||
self.format_var = tk.StringVar(value="linear")
|
||||
format_combo = ttk.Combobox(self.tab_batch, textvariable=self.format_var,
|
||||
values=("linear", "ascii_table", "csv", "markdown"))
|
||||
format_combo.place(relx=0.01, rely=0.91, relwidth=0.3, relheight=0.08, anchor='sw')
|
||||
format_combo.set("linear")
|
||||
|
||||
# 生成按钮
|
||||
ttk.Button(self.tab_batch, text="生成新随机",
|
||||
command=self.generate_batch).place(relx=0.5, rely=0.845,
|
||||
relwidth=0.25, relheight=0.13, anchor='n')
|
||||
|
||||
# 操作按钮
|
||||
ttk.Button(self.tab_batch, text="复制到剪贴板",
|
||||
command=lambda: self.copy_to_clipboard(self.batch_text.get(1.0, tk.END)),
|
||||
style="TabToggle.TButton").place(relx=0.99, rely=0.99,
|
||||
relwidth=0.3, relheight=0.08, anchor='se')
|
||||
|
||||
ttk.Button(self.tab_batch, text="导出至文件",
|
||||
command=lambda: self.export_to_file(self.batch_text.get(1.0, tk.END), "txt"),
|
||||
style="TabToggle.TButton").place(relx=0.99, rely=0.91,
|
||||
relwidth=0.3, relheight=0.08, anchor='se')
|
||||
|
||||
# 初始生成内容
|
||||
self.generate_batch()
|
||||
|
||||
def generate_batch(self):
|
||||
"""生成批量视图内容"""
|
||||
content = self.matrix_gen(self.format_var.get())
|
||||
self.batch_text.delete(1.0, tk.END)
|
||||
self.batch_text.insert(1.0, content)
|
||||
|
||||
def create_edit_tab(self):
|
||||
"""创建编辑数据库选项卡"""
|
||||
# 简单的编辑界面
|
||||
label = ttk.Label(self.tab_edit, text="数据库编辑功能开发中...",
|
||||
font=("Sarasa UI SC", 16))
|
||||
label.pack(expand=True)
|
||||
|
||||
# 显示当前数据库信息
|
||||
info_text = f"当前数据库记录数: {len(self.db)}"
|
||||
ttk.Label(self.tab_edit, text=info_text).pack(pady=10)
|
||||
|
||||
def create_config_tab(self):
|
||||
"""创建设置选项卡"""
|
||||
# 主题设置
|
||||
ttk.Label(self.tab_config, text="外观设置",
|
||||
font=("Sarasa UI SC", 14, 'bold')).grid(row=0, column=0,
|
||||
sticky='w', padx=5, pady=5)
|
||||
|
||||
self.theme_var = tk.StringVar(value=self.ttkthemename)
|
||||
theme_combo = ttk.Combobox(self.tab_config, textvariable=self.theme_var,
|
||||
values=["cosmo", "flatly", "darkly", "litera", "minty"])
|
||||
theme_combo.grid(row=1, column=0, sticky='w', padx=5, pady=5)
|
||||
theme_combo.bind('<<ComboboxSelected>>', self.change_theme)
|
||||
|
||||
# 其他设置
|
||||
ttk.Label(self.tab_config, text="其他设置",
|
||||
font=("Sarasa UI SC", 14, 'bold')).grid(row=2, column=0,
|
||||
sticky='w', padx=5, pady=5)
|
||||
|
||||
self.speed_var = tk.DoubleVar(value=self.stdtime)
|
||||
speed_scale = ttk.Scale(self.tab_config, from_=0.05, to=0.5,
|
||||
variable=self.speed_var, orient='horizontal')
|
||||
speed_scale.grid(row=3, column=0, sticky='we', padx=5, pady=5)
|
||||
speed_scale.bind('<ButtonRelease-1>', self.change_speed)
|
||||
|
||||
ttk.Label(self.tab_config, text=f"速度: {self.stdtime}s").grid(row=4, column=0, sticky='w', padx=5)
|
||||
|
||||
def change_theme(self, event):
|
||||
"""更改主题"""
|
||||
self.ttkthemename = self.theme_var.get()
|
||||
self.style.theme_use(self.ttkthemename)
|
||||
|
||||
def change_speed(self, event):
|
||||
"""更改速度"""
|
||||
self.stdtime = self.speed_var.get()
|
||||
# 更新显示
|
||||
for widget in self.tab_config.grid_slaves():
|
||||
if isinstance(widget, ttk.Label) and widget.cget('text').startswith("速度:"):
|
||||
widget.config(text=f"速度: {self.stdtime}s")
|
||||
|
||||
def create_about_tab(self):
|
||||
"""创建关于选项卡"""
|
||||
about_text = tk.Text(self.tab_about, wrap=tk.WORD,
|
||||
font=("Sarasa UI SC", 10))
|
||||
about_text.pack(fill='both', expand=True, padx=10, pady=10)
|
||||
|
||||
about_text.insert(tk.END, self.about_text)
|
||||
about_text.insert(tk.END, "\n\n" + "="*50 + "\n")
|
||||
about_text.insert(tk.END, "GNU GENERAL PUBLIC LICENSE\n")
|
||||
about_text.insert(tk.END, "="*50 + "\n")
|
||||
about_text.insert(tk.END, self.LICENSE[:2000] + "...") # 只显示部分许可证内容
|
||||
|
||||
about_text.configure(state="disabled")
|
||||
|
||||
def on_closing(self):
|
||||
"""程序关闭处理"""
|
||||
self.random_stop = 1
|
||||
self.root.destroy()
|
||||
|
||||
def run(self):
|
||||
"""运行程序"""
|
||||
print("启动随机生成器守护线程 ", end="")
|
||||
random_thr = threading.Thread(target=self.random_gen)
|
||||
random_thr.daemon = True
|
||||
random_thr.start()
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
|
||||
print("初始化 GUI ", end="")
|
||||
print(colorama.Fore.YELLOW + "正运行" + colorama.Style.RESET_ALL)
|
||||
|
||||
self.create_interface()
|
||||
print(colorama.Fore.GREEN + "结束" + colorama.Style.RESET_ALL)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("确保此终端支持 UTF-8 字符输出!")
|
||||
print(f"幸运选手α {version}")
|
||||
print("开放源代码: https://github.com/david-ajax/classaux")
|
||||
print("读取 YAML 配置文件与 GPL 协议 ", end="")
|
||||
with open("COPYING", encoding='utf_8') as license_file:
|
||||
LICENSE = license_file.read()
|
||||
with open("config.yaml", encoding='utf_8') as config_file:
|
||||
config = yaml.safe_load(config_file.read())
|
||||
print(config['member'])
|
||||
omember = list(config['member'])
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
#print(config)
|
||||
print(f"读取数据库 {config['info']['db']} ", end="")
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
with open("db.csv", encoding='utf_8-sig') as db_file:
|
||||
db = list(csv.reader(db_file, delimiter=',', quotechar='"'))
|
||||
for i in db:
|
||||
if i[0] == 'NOTE':
|
||||
db.remove(i)
|
||||
# print(db)
|
||||
print(f"配置文件: {config['info']['name']}")
|
||||
member_sum = len(config['member'])
|
||||
print(f"成员人数: {len(config['member'])}")
|
||||
print(f"随机刻间隔时间: {stdtime}s")
|
||||
print("启动随机生成器守护线程 ", end="")
|
||||
random_thr = threading.Thread(target=random_gen)
|
||||
random_thr.start()
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
print("初始化主题资源 ", end="")
|
||||
is_dark = config["darkmode"]
|
||||
init_theme()
|
||||
print(colorama.Fore.GREEN + "成功" + colorama.Style.RESET_ALL)
|
||||
print("初始化 GUI ", end="")
|
||||
print(colorama.Fore.YELLOW + "正运行" + colorama.Style.RESET_ALL)
|
||||
interface()
|
||||
print(colorama.Fore.GREEN + "结束" + colorama.Style.RESET_ALL)
|
||||
app = ClassAuxApp()
|
||||
app.run()
|
||||
|
Reference in New Issue
Block a user