389 lines
15 KiB
Python
389 lines
15 KiB
Python
import tkinter as tk
|
|
from tkinter import ttk, messagebox, filedialog
|
|
import json
|
|
import random
|
|
from datetime import datetime
|
|
import os
|
|
|
|
class ModernUIApp:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.root.title("托福单词默写系统")
|
|
self.root.geometry("1000x700")
|
|
self.root.configure(bg='#f0f0f0')
|
|
|
|
# 设置现代化样式
|
|
self.setup_styles()
|
|
|
|
# 创建主界面
|
|
self.create_main_interface()
|
|
|
|
# 托福单词库(简化版)
|
|
self.toefl_words = [
|
|
"abandon", "ability", "abnormal", "abolish", "abrupt",
|
|
"absorb", "abstract", "abundant", "access", "accident",
|
|
"accommodate", "accompany", "accomplish", "account", "accurate",
|
|
"achieve", "acknowledge", "acquire", "adapt", "adequate",
|
|
"adjust", "administer", "admire", "admit", "adopt",
|
|
"advance", "advantage", "adventure", "advertise", "advise",
|
|
"affect", "afford", "aggressive", "agree", "aid",
|
|
"aim", "alert", "alien", "alike", "alive",
|
|
"allocate", "allow", "ally", "alone", "alter",
|
|
"alternative", "amateur", "amaze", "ambition", "amount",
|
|
"ample", "analyze", "anchor", "ancient", "angle"
|
|
]
|
|
|
|
self.selected_words = []
|
|
self.current_word_index = 0
|
|
self.mistakes = []
|
|
|
|
def setup_styles(self):
|
|
# 配置样式
|
|
style = ttk.Style()
|
|
style.theme_use('clam')
|
|
|
|
# 自定义按钮样式
|
|
style.configure('Modern.TButton',
|
|
padding=10,
|
|
font=('Arial', 12, 'bold'),
|
|
foreground='#ffffff',
|
|
background='#4a90e2',
|
|
borderwidth=0)
|
|
|
|
style.map('Modern.TButton',
|
|
background=[('active', '#357abd')])
|
|
|
|
# 自定义标签样式
|
|
style.configure('Title.TLabel',
|
|
font=('Arial', 16, 'bold'),
|
|
foreground='#2c3e50',
|
|
background='#f0f0f0')
|
|
|
|
style.configure('Subtitle.TLabel',
|
|
font=('Arial', 12),
|
|
foreground='#7f8c8d',
|
|
background='#f0f0f0')
|
|
|
|
def create_main_interface(self):
|
|
# 创建主框架
|
|
main_frame = tk.Frame(self.root, bg='#f0f0f0')
|
|
main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
|
|
|
|
# 标题区域
|
|
title_frame = tk.Frame(main_frame, bg='#f0f0f0')
|
|
title_frame.pack(fill=tk.X, pady=(0, 20))
|
|
|
|
title_label = ttk.Label(title_frame, text="托福单词默写系统", style='Title.TLabel')
|
|
title_label.pack(side=tk.LEFT)
|
|
|
|
# 模式选择区域
|
|
mode_frame = tk.Frame(main_frame, bg='#f0f0f0')
|
|
mode_frame.pack(fill=tk.X, pady=(0, 20))
|
|
|
|
ttk.Label(mode_frame, text="选择使用模式:", style='Subtitle.TLabel').pack(side=tk.LEFT)
|
|
|
|
self.teacher_btn = ttk.Button(mode_frame, text="老师端",
|
|
style='Modern.TButton',
|
|
command=self.show_teacher_interface)
|
|
self.teacher_btn.pack(side=tk.LEFT, padx=(20, 10))
|
|
|
|
self.student_btn = ttk.Button(mode_frame, text="学生端",
|
|
style='Modern.TButton',
|
|
command=self.show_student_interface)
|
|
self.student_btn.pack(side=tk.LEFT, padx=10)
|
|
|
|
# 内容区域
|
|
self.content_frame = tk.Frame(main_frame, bg='#ffffff', relief=tk.RAISED, bd=1)
|
|
self.content_frame.pack(fill=tk.BOTH, expand=True)
|
|
|
|
# 显示欢迎界面
|
|
self.show_welcome_interface()
|
|
|
|
def show_welcome_interface(self):
|
|
self.clear_content_frame()
|
|
|
|
welcome_frame = tk.Frame(self.content_frame, bg='#ffffff')
|
|
welcome_frame.pack(expand=True)
|
|
|
|
ttk.Label(welcome_frame, text="欢迎使用托福单词默写系统",
|
|
font=('Arial', 18, 'bold'),
|
|
foreground='#2c3e50',
|
|
background='#ffffff').pack(pady=20)
|
|
|
|
ttk.Label(welcome_frame, text="请选择您要使用的模式:老师端 或 学生端",
|
|
font=('Arial', 12),
|
|
foreground='#7f8c8d',
|
|
background='#ffffff').pack(pady=10)
|
|
|
|
def show_teacher_interface(self):
|
|
self.clear_content_frame()
|
|
|
|
# 创建笔记本控件用于选项卡
|
|
notebook = ttk.Notebook(self.content_frame)
|
|
notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
|
|
# 单词选择页面
|
|
word_select_frame = tk.Frame(notebook, bg='#ffffff')
|
|
notebook.add(word_select_frame, text="单词选择")
|
|
self.create_word_selection_interface(word_select_frame)
|
|
|
|
# 默写控制页面
|
|
dictation_frame = tk.Frame(notebook, bg='#ffffff')
|
|
notebook.add(dictation_frame, text="开始默写")
|
|
self.create_dictation_interface(dictation_frame)
|
|
|
|
def create_word_selection_interface(self, parent):
|
|
# 标题
|
|
ttk.Label(parent, text="选择托福单词",
|
|
font=('Arial', 14, 'bold'),
|
|
background='#ffffff').pack(pady=10)
|
|
|
|
# 搜索框
|
|
search_frame = tk.Frame(parent, bg='#ffffff')
|
|
search_frame.pack(fill=tk.X, padx=20, pady=10)
|
|
|
|
ttk.Label(search_frame, text="搜索:", background='#ffffff').pack(side=tk.LEFT)
|
|
self.search_var = tk.StringVar()
|
|
search_entry = ttk.Entry(search_frame, textvariable=self.search_var, width=30)
|
|
search_entry.pack(side=tk.LEFT, padx=10)
|
|
search_entry.bind('<KeyRelease>', self.filter_words)
|
|
|
|
# 单词列表框架
|
|
list_frame = tk.Frame(parent, bg='#ffffff')
|
|
list_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
|
|
|
|
# 创建Treeview显示单词
|
|
columns = ('单词', '状态')
|
|
self.word_tree = ttk.Treeview(list_frame, columns=columns, show='headings', height=15)
|
|
|
|
# 设置列标题
|
|
self.word_tree.heading('单词', text='单词')
|
|
self.word_tree.heading('状态', text='状态')
|
|
self.word_tree.column('单词', width=200)
|
|
self.word_tree.column('状态', width=100)
|
|
|
|
# 滚动条
|
|
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.word_tree.yview)
|
|
self.word_tree.configure(yscrollcommand=scrollbar.set)
|
|
|
|
self.word_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
|
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
|
|
|
# 填充单词数据
|
|
self.populate_word_list()
|
|
|
|
# 按钮区域
|
|
button_frame = tk.Frame(parent, bg='#ffffff')
|
|
button_frame.pack(fill=tk.X, padx=20, pady=10)
|
|
|
|
ttk.Button(button_frame, text="全选",
|
|
style='Modern.TButton',
|
|
command=self.select_all_words).pack(side=tk.LEFT, padx=5)
|
|
|
|
ttk.Button(button_frame, text="取消全选",
|
|
style='Modern.TButton',
|
|
command=self.deselect_all_words).pack(side=tk.LEFT, padx=5)
|
|
|
|
ttk.Button(button_frame, text="随机选择20个",
|
|
style='Modern.TButton',
|
|
command=self.random_select_words).pack(side=tk.LEFT, padx=5)
|
|
|
|
ttk.Button(button_frame, text="导出配置文件",
|
|
style='Modern.TButton',
|
|
command=self.export_config).pack(side=tk.RIGHT, padx=5)
|
|
|
|
# 统计信息
|
|
self.stats_label = ttk.Label(button_frame, text="已选择: 0 个单词",
|
|
background='#ffffff')
|
|
self.stats_label.pack(side=tk.RIGHT, padx=20)
|
|
|
|
def populate_word_list(self):
|
|
self.word_tree.delete(*self.word_tree.get_children())
|
|
for word in self.toefl_words:
|
|
status = "✓ 已选择" if word in self.selected_words else "○ 未选择"
|
|
self.word_tree.insert('', tk.END, values=(word, status))
|
|
|
|
def filter_words(self, event=None):
|
|
# 简化的过滤功能
|
|
search_term = self.search_var.get().lower()
|
|
if search_term:
|
|
filtered_words = [word for word in self.toefl_words if search_term in word.lower()]
|
|
else:
|
|
filtered_words = self.toefl_words
|
|
|
|
self.word_tree.delete(*self.word_tree.get_children())
|
|
for word in filtered_words:
|
|
status = "✓ 已选择" if word in self.selected_words else "○ 未选择"
|
|
self.word_tree.insert('', tk.END, values=(word, status))
|
|
|
|
def select_all_words(self):
|
|
self.selected_words = self.toefl_words.copy()
|
|
self.populate_word_list()
|
|
self.update_stats()
|
|
|
|
def deselect_all_words(self):
|
|
self.selected_words = []
|
|
self.populate_word_list()
|
|
self.update_stats()
|
|
|
|
def random_select_words(self):
|
|
self.selected_words = random.sample(self.toefl_words, min(20, len(self.toefl_words)))
|
|
self.populate_word_list()
|
|
self.update_stats()
|
|
|
|
def update_stats(self):
|
|
self.stats_label.config(text=f"已选择: {len(self.selected_words)} 个单词")
|
|
|
|
def export_config(self):
|
|
if not self.selected_words:
|
|
messagebox.showwarning("警告", "请先选择单词!")
|
|
return
|
|
|
|
filename = filedialog.asksaveasfilename(
|
|
defaultextension=".json",
|
|
filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
|
|
title="保存配置文件"
|
|
)
|
|
|
|
if filename:
|
|
config = {
|
|
"words": self.selected_words,
|
|
"created_time": datetime.now().isoformat(),
|
|
"version": "1.0"
|
|
}
|
|
|
|
try:
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|
json.dump(config, f, ensure_ascii=False, indent=2)
|
|
messagebox.showinfo("成功", f"配置文件已保存到:\n{filename}")
|
|
except Exception as e:
|
|
messagebox.showerror("错误", f"保存失败: {str(e)}")
|
|
|
|
def show_student_interface(self):
|
|
self.clear_content_frame()
|
|
|
|
# 标题
|
|
ttk.Label(self.content_frame, text="学生端 - 导入配置",
|
|
font=('Arial', 14, 'bold'),
|
|
background='#ffffff').pack(pady=20)
|
|
|
|
# 导入区域
|
|
import_frame = tk.Frame(self.content_frame, bg='#ffffff')
|
|
import_frame.pack(fill=tk.BOTH, expand=True, padx=50, pady=20)
|
|
|
|
ttk.Label(import_frame, text="请导入老师端生成的配置文件",
|
|
font=('Arial', 12),
|
|
background='#ffffff').pack(pady=10)
|
|
|
|
ttk.Button(import_frame, text="选择配置文件",
|
|
style='Modern.TButton',
|
|
command=self.import_config).pack(pady=20)
|
|
|
|
# 显示导入的单词信息
|
|
self.word_info_label = ttk.Label(import_frame,
|
|
text="尚未导入配置文件",
|
|
font=('Arial', 10),
|
|
background='#ffffff')
|
|
self.word_info_label.pack(pady=10)
|
|
|
|
def import_config(self):
|
|
filename = filedialog.askopenfilename(
|
|
filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
|
|
title="选择配置文件"
|
|
)
|
|
|
|
if filename:
|
|
try:
|
|
with open(filename, 'r', encoding='utf-8') as f:
|
|
config = json.load(f)
|
|
|
|
self.selected_words = config.get('words', [])
|
|
created_time = config.get('created_time', '未知')
|
|
|
|
self.word_info_label.config(
|
|
text=f"已导入 {len(self.selected_words)} 个单词\n创建时间: {created_time}"
|
|
)
|
|
|
|
messagebox.showinfo("成功", f"成功导入 {len(self.selected_words)} 个单词!")
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("错误", f"导入失败: {str(e)}")
|
|
|
|
def create_dictation_interface(self, parent):
|
|
# 标题
|
|
ttk.Label(parent, text="开始默写",
|
|
font=('Arial', 14, 'bold'),
|
|
background='#ffffff').pack(pady=10)
|
|
|
|
# 控制按钮
|
|
control_frame = tk.Frame(parent, bg='#ffffff')
|
|
control_frame.pack(fill=tk.X, padx=20, pady=10)
|
|
|
|
ttk.Button(control_frame, text="开始默写",
|
|
style='Modern.TButton',
|
|
command=self.start_dictation).pack(side=tk.LEFT, padx=5)
|
|
|
|
ttk.Button(control_frame, text="暂停",
|
|
style='Modern.TButton',
|
|
command=self.pause_dictation).pack(side=tk.LEFT, padx=5)
|
|
|
|
ttk.Button(control_frame, text="结束",
|
|
style='Modern.TButton',
|
|
command=self.end_dictation).pack(side=tk.LEFT, padx=5)
|
|
|
|
# 默写显示区域
|
|
dictation_frame = tk.Frame(parent, bg='#ffffff')
|
|
dictation_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
|
|
|
|
# 当前单词显示
|
|
self.current_word_label = ttk.Label(dictation_frame,
|
|
text="点击'开始默写'开始",
|
|
font=('Arial', 24, 'bold'),
|
|
background='#ffffff')
|
|
self.current_word_label.pack(expand=True)
|
|
|
|
# 进度信息
|
|
self.progress_label = ttk.Label(dictation_frame,
|
|
text="进度: 0/0",
|
|
font=('Arial', 12),
|
|
background='#ffffff')
|
|
self.progress_label.pack(pady=10)
|
|
|
|
def start_dictation(self):
|
|
if not self.selected_words:
|
|
messagebox.showwarning("警告", "请先在'单词选择'页面选择单词!")
|
|
return
|
|
|
|
self.current_word_index = 0
|
|
self.mistakes = []
|
|
self.show_next_word()
|
|
|
|
def show_next_word(self):
|
|
if self.current_word_index < len(self.selected_words):
|
|
word = self.selected_words[self.current_word_index]
|
|
self.current_word_label.config(text=word)
|
|
self.progress_label.config(
|
|
text=f"进度: {self.current_word_index + 1}/{len(self.selected_words)}"
|
|
)
|
|
else:
|
|
self.end_dictation()
|
|
|
|
def pause_dictation(self):
|
|
messagebox.showinfo("暂停", "默写已暂停")
|
|
|
|
def end_dictation(self):
|
|
self.current_word_label.config(text="默写结束")
|
|
self.progress_label.config(text=f"完成: {len(self.selected_words)}/{len(self.selected_words)}")
|
|
messagebox.showinfo("完成", f"默写完成!共 {len(self.selected_words)} 个单词")
|
|
|
|
def clear_content_frame(self):
|
|
for widget in self.content_frame.winfo_children():
|
|
widget.destroy()
|
|
|
|
def main():
|
|
root = tk.Tk()
|
|
app = ModernUIApp(root)
|
|
root.mainloop()
|
|
|
|
if __name__ == "__main__":
|
|
main() |