commit 415192d110a266d9331060ec7640526dac59fd9b Author: Zichao Lin Date: Fri Jun 7 12:25:41 2024 +0800 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b1960e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +output/ \ No newline at end of file diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..46462c5 Binary files /dev/null and b/icon.ico differ diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..2cc7c5e Binary files /dev/null and b/icon.png differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..493abd2 --- /dev/null +++ b/main.py @@ -0,0 +1,335 @@ +import tkinter as tk +from tkinter import simpledialog, messagebox +import random +import winreg +from datetime import datetime + +# 注册表路径 +REGISTRY_PATH = r"Software\StudentIDDraw" + +# 默认设置 +DEFAULT_ALLOW_REPEAT = False +DEFAULT_MIN_ID = 1 +DEFAULT_MAX_ID = 45 +PASSWORD = "admin123" + +selected_ids = [] + + +# 注册表工具函数 +def set_registry_value(value_name, value, value_type=winreg.REG_SZ): + try: + with winreg.CreateKey(winreg.HKEY_CURRENT_USER, REGISTRY_PATH) as reg_key: + winreg.SetValueEx(reg_key, value_name, 0, value_type, value) + except WindowsError as e: + print(f"Error setting registry value: {e}") + + +def get_registry_value(value_name, default_value): + try: + with winreg.OpenKey( + winreg.HKEY_CURRENT_USER, REGISTRY_PATH, 0, winreg.KEY_READ + ) as reg_key: + value, _ = winreg.QueryValueEx(reg_key, value_name) + return value + except WindowsError: + return default_value + + +def delete_registry_value(value_name): + try: + with winreg.OpenKey( + winreg.HKEY_CURRENT_USER, REGISTRY_PATH, 0, winreg.KEY_WRITE + ) as reg_key: + winreg.DeleteValue(reg_key, value_name) + except WindowsError as e: + print(f"Error deleting registry value: {e}") + + +# 加载已抽取的学号 +def load_selected_ids(): + global selected_ids + selected_ids_str = get_registry_value("SelectedIDs", "") + if selected_ids_str: + selected_ids = [] + for item in selected_ids_str.split(","): + parts = item.split("_") + if len(parts) == 2: + id, timestamp = parts + timestamp = datetime.fromtimestamp(int(timestamp)).strftime( + "%Y-%m-%d %H:%M:%S" + ) + selected_ids.append((id, timestamp)) + else: + print(f"Error parsing item: {item}, resetting to NULL") + delete_registry_value("SelectedIDs") + selected_ids = [] + else: + selected_ids = [] + return selected_ids + + +# 保存已抽取的学号 +def save_selected_ids(): + global selected_ids + selected_ids_str = ",".join( + [ + f"{id}_{int(datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S').timestamp())}" + for id, timestamp in selected_ids + ] + ) + set_registry_value("SelectedIDs", selected_ids_str) + + +# 加载设置 +def load_settings(): + allow_repeat = ( + get_registry_value("AllowRepeat", str(DEFAULT_ALLOW_REPEAT)) == "True" + ) + min_id = int(get_registry_value("MinID", str(DEFAULT_MIN_ID))) + max_id = int(get_registry_value("MaxID", str(DEFAULT_MAX_ID))) + return allow_repeat, min_id, max_id + + +# 保存设置 +def save_settings(allow_repeat, min_id, max_id): + set_registry_value("AllowRepeat", str(allow_repeat)) + set_registry_value("MinID", str(min_id)) + set_registry_value("MaxID", str(max_id)) + + +# 生成随机的学号 +def generate_random_id(selected_ids, allow_repeat, min_id, max_id): + if not allow_repeat: + all_ids = set(range(min_id, max_id + 1)) + selected_id_numbers = [int(id) for id, _ in selected_ids] + remaining_ids = list(all_ids - set(selected_id_numbers)) + if not remaining_ids: + return None # 如果所有学号都已抽取完毕,则返回 None + return random.choice(remaining_ids) + else: + return random.randint(min_id, max_id) + + +# 更新历史记录列表 +def update_history_list(): + global history_list + if history_list: + history_list.delete(0, tk.END) + for id, timestamp in selected_ids: + history_list.insert(tk.END, f"{id} ({timestamp})") + + +# 抽取学号按钮点击事件处理函数 +def draw_student_id(): + global selected_ids + load_selected_ids() + allow_repeat, min_id, max_id = load_settings() + id = generate_random_id(selected_ids, allow_repeat, min_id, max_id) + if id is not None: + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + label.config(text=str(id), font=("宋体", 50)) + selected_ids.append((str(id), timestamp)) + save_selected_ids() + if settings_window: + update_history_list() + else: + label.config(text="已抽完所有学号", font=("宋体", 30)) + + +# 设置按钮点击事件处理函数 +def open_settings(): + global settings_window + global history_list + + if settings_window: + settings_window.lift() + return + + settings_window = tk.Toplevel(root) + settings_window.title("设置") + + allow_repeat, min_id, max_id = load_settings() + + # 使用 grid 管理器来创建一个自适应大小的界面 + settings_window.grid_columnconfigure(1, weight=1) + settings_window.grid_rowconfigure(4, weight=1) + + tk.Label(settings_window, text="历史记录:", font=("宋体", 12)).grid( + row=0, column=0, padx=5, pady=5, sticky="w" + ) + + load_selected_ids() + + history_frame = tk.Frame(settings_window) + history_frame.grid(row=1, column=0, columnspan=2, padx=5, pady=5, sticky="nsew") + history_frame.grid_columnconfigure(0, weight=1) + history_frame.grid_rowconfigure(0, weight=1) + + history_list = tk.Listbox(history_frame, selectmode=tk.SINGLE) + history_list.grid(row=0, column=0, sticky="nsew") + + scrollbar = tk.Scrollbar( + history_frame, orient="vertical", command=history_list.yview + ) + scrollbar.grid(row=0, column=1, sticky="ns") + history_list.config(yscrollcommand=scrollbar.set) + + update_history_list() + + def add_id(): + new_id = simpledialog.askstring("新增学号", "请输入新的学号:") + if new_id: + if new_id.isdigit(): + new_id = int(new_id) + if min_id <= new_id <= max_id: + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + selected_ids.append((str(new_id), timestamp)) + update_history_list() + else: + messagebox.showerror("错误", f"学号必须在 {min_id} 和 {max_id} 之间") + else: + messagebox.showerror("错误", "请输入有效的学号") + + def delete_id(): + selected = history_list.curselection() + if selected: + index = selected[0] + selected_ids.pop(index) + update_history_list() + if index < len(selected_ids): + history_list.select_set(index) + elif selected_ids: + history_list.select_set(index - 1) + else: + messagebox.showerror("错误", "请选择一个学号进行删除") + + def edit_id(): + selected = history_list.curselection() + if selected: + index = selected[0] + current_id, _ = selected_ids[index] + new_id = simpledialog.askstring( + "修改学号", "请输入新的学号:", initialvalue=str(current_id) + ) + if new_id: + if new_id.isdigit(): + new_id = int(new_id) + if min_id <= new_id <= max_id: + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + selected_ids[index] = (str(new_id), timestamp) + update_history_list() + history_list.select_set(index) + else: + messagebox.showerror("错误", f"学号必须在 {min_id} 和 {max_id} 之间") + else: + messagebox.showerror("错误", "请输入有效的学号") + else: + messagebox.showerror("错误", "请选择一个学号进行修改") + + def clear_all_ids(): + global selected_ids + selected_ids = [] + update_history_list() + + tk.Button(settings_window, text="新增记录", font=("宋体", 12), command=add_id).grid( + row=2, column=0, padx=5, pady=5, sticky="ew" + ) + tk.Button(settings_window, text="删除记录", font=("宋体", 12), command=delete_id).grid( + row=2, column=1, padx=5, pady=5, sticky="ew" + ) + tk.Button(settings_window, text="修改记录", font=("宋体", 12), command=edit_id).grid( + row=3, column=0, padx=5, pady=5, sticky="ew" + ) + tk.Button( + settings_window, text="清空记录", font=("宋体", 12), command=clear_all_ids + ).grid(row=3, column=1, padx=5, pady=5, sticky="ew") + + allow_repeat_var = tk.BooleanVar(value=allow_repeat) + tk.Checkbutton( + settings_window, text="允许重复抽号", font=("宋体", 12), variable=allow_repeat_var + ).grid(row=5, column=0, padx=5, pady=5, sticky="w") + + tk.Label(settings_window, text="学号范围:", font=("宋体", 12)).grid( + row=6, column=0, padx=5, pady=5, sticky="w" + ) + min_id_var = tk.StringVar(value=min_id) + max_id_var = tk.StringVar(value=max_id) + tk.Entry(settings_window, textvariable=min_id_var).grid( + row=6, column=1, padx=5, pady=5, sticky="ew" + ) + tk.Entry(settings_window, textvariable=max_id_var).grid( + row=7, column=1, padx=5, pady=5, sticky="ew" + ) + + def save_changes(): + entered_password = simpledialog.askstring("密码", "请输入密码:", show="*") + if entered_password == PASSWORD: + save_settings( + allow_repeat_var.get(), int(min_id_var.get()), int(max_id_var.get()) + ) + save_selected_ids() + messagebox.showinfo("提示", "设置已保存") + close_settings_window() + else: + messagebox.showerror("错误", "密码错误") + + tk.Button(settings_window, text="保存", font=("宋体", 12), command=save_changes).grid( + row=8, column=0, columnspan=2, padx=5, pady=20, sticky="ew" + ) + + # 自动调整窗口大小 + settings_window.attributes("-topmost", 1) + settings_window.update_idletasks() + settings_window.minsize( + settings_window.winfo_reqwidth(), settings_window.winfo_reqheight() + ) + settings_window.resizable(False, False) # 让设置窗口不可缩放 + + settings_window.protocol("WM_DELETE_WINDOW", close_settings_window) + + +def close_settings_window(): + global settings_window + settings_window.destroy() + settings_window = None + + +# 初始化全局变量 +selected_ids = load_selected_ids() +settings_window = None +history_list = None + +# 创建主窗口 +root = tk.Tk() +root.title("随机抽号机") +root.attributes("-topmost", 1) # 置顶显示 + +# 创建标签,用于显示抽取的学号 +label = tk.Label(root, text="", font=("宋体", 50)) +label.pack(pady=20, padx=20) + +# 创建抽取学号按钮 +button = tk.Button(root, text="抽取学号", font=("宋体", 12), command=draw_student_id) +button.pack(pady=10) + +# 创建设置按钮 +settings_button = tk.Button(root, text="设置", font=("宋体", 12), command=open_settings) +settings_button.pack(pady=10) + +# 创建多行标签,用于显示信息,内容居中显示 +info_label = tk.Label( + root, + text="v1.0 2024/06/07\nCopyright 2024 earthjasonlin\n保留所有权利。\n本程序仅作为交流学习使用", + font=("宋体", 10), + justify="center", + anchor="center", +) +info_label.pack(pady=10, padx=20, fill="x") + +# 自动调整窗口大小 +root.update_idletasks() +root.minsize(root.winfo_reqwidth(), root.winfo_reqheight()) +root.resizable(False, False) + +root.mainloop()