使用Python实现单词记忆软件

前言

该代码实现了一个基于PyQt5的单词记忆软件,支持高考、四级、六级和考研四个级别的词库。程序提供四种学习模式:拆分模式(将单词拆分为片段重组)、填空模式(选择正确字母填空)、输入模式(手动输入单词)和测试模式(评估单词记忆效果)。软件界面包含单词释义显示、交互练习区域和反馈功能,支持单词级别切换、结果统计和保存功能。采用随机算法打乱单词顺序,确保学习效果,具有错误提示和自动跳转下一题功能,适合不同英语水平的学习者使用。

目前存在的问题和优化思路,目前还没实现:

  • 拆分模式再次点击已经被选择的单词片段可以取消锁定,但是要按单词拼写的倒序取消(原本是没锁定的,但是那样会导致一个字符可以重复点击,导致单词拼接不正确,而且还没法判断正误)。
  • 模式之间切换会导致窗口卡死,这个还没找到是什么原因。
  • 测试模式可以结合其他三种模式来进行选择。
  • 当保存的时候点击那个词书就会保存什么,比如我是测试的"高考",但是在保存的时候点击了"考研",保存名字默认是"考研"。
  • 单词太少了,完全是deepseek生成的,自己目前还没看到错误的,也可以是因为本人英语不好所以还没发现。

拆分模式

  1. 显示单词的释义
  2. 将单词拆分成若干片段并打乱顺序显示
  3. 用户按正确顺序点击片段拼出完整单词
  4. 系统检查是否正确,提供反馈
python 复制代码
def setup_mode1(self, word, meaning):
    """设置拆分模式"""
    self.mode1_meaning.setText(meaning)
    self.mode1_answer.clear()
    self.mode1_feedback.clear()

    # 清理旧按钮
    while self.mode1_chunks_layout.count():
        item = self.mode1_chunks_layout.takeAt(0)
        if item.widget():
            item.widget().deleteLater()

    # 安全拆分单词
    if len(word) < 2:
        chunks = [word]
    else:
        n = min(3, max(2, len(word) // 2))
        split_points = sorted(random.sample(range(1, len(word)), n - 1))
        chunks = []
        start = 0
        for point in split_points:
            chunks.append(word[start:point])
            start = point
        chunks.append(word[start:])

    # 打乱顺序
    random.shuffle(chunks)

    # 创建新按钮
    self.chunk_buttons = []
    self.selected_chunks = []  # 存储字典:{"chunk": 片段, "button": 按钮, "position": 位置}
    for chunk in chunks:
        btn = QPushButton(chunk)
        btn.setStyleSheet("...")
        btn.clicked.connect(lambda _, c=chunk, b=btn: self.toggle_chunk(c, b))
        self.mode1_chunks_layout.addWidget(btn)
        self.chunk_buttons.append(btn)

    self.correct_word = word
    self.user_answer = ""

填空模式

  1. 显示单词的释义
  2. 显示带有空缺的单词(部分字母被下划线替代)
  3. 提供4个选项(1个正确,3个干扰项)
  4. 用户选择正确选项填补空缺
  5. 系统检查是否正确,提供反馈
python 复制代码
def setup_mode2(self, word, meaning):
    """设置填空模式"""
    self.mode2_meaning.setText(meaning)
    self.mode2_feedback.clear()

    # 清理旧选项
    while self.mode2_options_layout.count():
        item = self.mode2_options_layout.takeAt(0)
        widget = item.widget()
        if widget is not None:
            widget.deleteLater()
        del item

    # 创建填空
    if len(word) <= 3:
        blank_pos = len(word) // 2
        blank_len = len(word) - blank_pos
        correct_part = word[blank_pos:]
    else:
        blank_len = min(3, max(2, len(word) // 3))
        blank_pos = random.randint(1, len(word) - blank_len - 1)
        correct_part = word[blank_pos:blank_pos + blank_len]

    blank_word = word[:blank_pos] + "_" * blank_len + word[blank_pos + blank_len:]
    self.mode2_blank.setText(blank_word)

    # 生成选项
    options = [correct_part]
    chars = list(set(word) - set(correct_part))

    while len(options) < 4:
        if chars:
            option = ''.join(random.sample(chars, min(len(chars), blank_len)))
        else:
            option = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=blank_len))

        if option != correct_part and option not in options:
            options.append(option)

    random.shuffle(options)

    # 创建选项按钮
    self.option_buttons = []  # 保存按钮引用防止被垃圾回收
    for option in options:
        btn = QPushButton(option)
        btn.setStyleSheet("...")
        btn.clicked.connect(lambda _, o=option, cp=correct_part, w=word: self.check_fill_answer(o, cp, w))
        self.mode2_options_layout.addWidget(btn)
        self.option_buttons.append(btn)  # 保存按钮引用

输入模式

这个当时最大的问题就是那个错误信息和文本信息没有清空,导致再次输入还可以看到提示信息,那岂不是可以照着输入。

  1. 显示单词的释义
  2. 用户输入框中输入对应单词
  3. 系统检查是否正确,提供反馈
  4. 可回车提交答案
python 复制代码
def setup_mode3(self, meaning):
    """设置输入模式"""
    self.mode3_meaning.setText(meaning)
    self.mode3_input.clear()
    self.mode3_feedback.clear()
    self.mode3_input.setFocus()
    self.input_error_shown = False

def check_input_mode(self):
    """检查输入模式答案"""
    user_input = self.mode3_input.text().strip().lower()
    correct = self.current_words[self.current_index]["word"].lower()

    if user_input == correct:
        self.mode3_feedback.setText("✓ 正确!")
        self.mode3_feedback.setStyleSheet("color: #28a745;")
        QTimer.singleShot(1000, self.next_word)
    else:
        self.mode3_feedback.setText(f"✗ 错误!正确答案是: {correct}")
        self.mode3_feedback.setStyleSheet("color: #dc3545;")
        self.input_error_shown = True

测试模式

  1. 点击"开始测试"按钮
  2. 系统随机选择词库中的单词
  3. 显示单词释义,用户输入对应单词
  4. 记录错误次数
  5. 测试完成后显示统计结果(正确率、错误最多的单词等)
  6. 可保存测试结果到文件
python 复制代码
def start_test(self):
    """开始测试"""
    self.test_mode = True
    self.test_results = {}
    self.current_test_words = self.current_words.copy()
    random.shuffle(self.current_test_words)
    self.test_index = 0

    for word_data in self.current_test_words:
        word = word_data["word"]
        self.test_results[word] = {"errors": 0, "meaning": word_data["meaning"]}

    self.start_test_btn.setEnabled(False)
    self.end_test_btn.setEnabled(True)
    self.test_input.setEnabled(True)
    self.test_input.clear()
    self.test_feedback.clear()

    self.show_next_test_word()

def check_test_answer(self):
    """检查测试答案"""
    if not self.test_mode:
        return

    user_input = self.test_input.text().strip().lower()
    current_word_data = self.current_test_words[self.test_index]
    correct_word = current_word_data["word"].lower()

    if user_input == correct_word:
        self.test_feedback.setText("✓ 正确!")
        self.test_feedback.setStyleSheet("color: #28a745;")
        self.test_index += 1
        QTimer.singleShot(1000, self.show_next_test_word)
    else:
        self.test_feedback.setText(f"✗ 错误!正确答案是: {correct_word}")
        self.test_feedback.setStyleSheet("color: #dc3545;")
        self.test_results[correct_word]["errors"] += 1
        self.test_input_error_shown = True
        QTimer.singleShot(1000, self.clear_test_input)

def end_test(self):
    """结束测试并显示结果"""
    self.test_mode = False
    self.start_test_btn.setEnabled(True)
    self.end_test_btn.setEnabled(False)
    self.test_input.setEnabled(False)
    self.test_input.clear()
    self.test_feedback.clear()

    # 按错误次数排序,错误多的排在前面
    sorted_results = sorted(self.test_results.items(),
                            key=lambda x: x[1]["errors"],
                            reverse=True)

    result_text = f"测试完成 - {self.current_level}词库\n\n"
    result_text += "单词\t\t错误次数\t\t释义\n"
    result_text += "-" * 60 + "\n"

    for word, data in sorted_results:
        result_text += f"{word.ljust(15)}\t{data['errors']}\t\t{data['meaning']}\n"

    # 添加统计信息
    total_words = len(self.test_results)
    correct_words = sum(1 for word in self.test_results.values() if word["errors"] == 0)
    accuracy = correct_words / total_words * 100 if total_words > 0 else 0
    most_mistakes = sorted_results[0] if sorted_results else ("", {"errors": 0, "meaning": ""})

    result_text += "\n统计信息:\n"
    result_text += f"总单词数: {total_words}\n"
    result_text += f"正确掌握的单词: {correct_words}\n"
    result_text += f"准确率: {accuracy:.1f}%\n"
    result_text += f"错误最多的单词: {most_mistakes[0]} (错误 {most_mistakes[1]['errors']} 次)\n"

    self.test_results_text.setText(result_text)
    self.results_stack.setCurrentIndex(1)  # 显示结果界面

完整代码

python 复制代码
import sys
import random
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QPushButton, QStackedWidget,
                             QRadioButton, QButtonGroup, QLineEdit, QMessageBox,
                             QFileDialog, QTextEdit)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont


class WordPracticeApp(QMainWindow):
    def __init__(self):
        super().__init__()
        try:
            self.setup_ui()
            self.load_word_database()
            self.setup_connections()
            self.shuffle_words()
            self.show_word()

            # 初始化测试模式相关变量
            self.test_mode = False
            self.test_results = {}
            self.current_test_words = []
            self.input_error_shown = False  # 标记是否显示了输入错误
        except Exception as e:
            self.show_error_message(f"初始化失败: {str(e)}")
            raise

    def center_window(self):
        """将窗口居中显示"""
        frame = self.frameGeometry()
        screen = QApplication.primaryScreen().availableGeometry()
        frame.moveCenter(screen.center())
        self.move(frame.topLeft())

    def setup_ui(self):
        """初始化用户界面"""
        try:
            # 设置主窗口
            self.setWindowTitle("单词记忆软件")
            self.setGeometry(100, 100, 900, 650)
            self.center_window()

            # 设置全局字体
            font = QFont()
            font.setPointSize(12)
            QApplication.setFont(font)

            # 主窗口布局
            self.central_widget = QWidget()
            self.setCentralWidget(self.central_widget)
            self.main_layout = QVBoxLayout(self.central_widget)
            self.main_layout.setContentsMargins(20, 20, 20, 20)
            self.main_layout.setSpacing(15)

            # 初始化UI组件
            self.setup_top_bar()
            self.setup_mode_selector()
            self.setup_stacked_widget()
            self.setup_bottom_controls()
            self.setup_test_results_widget()

            # 初始化状态
            self.current_level = "高考"
            self.current_mode = 0
            self.current_index = 0
        except Exception as e:
            self.show_error_message(f"UI初始化失败: {str(e)}")
            raise

    def load_word_database(self):
        """加载单词数据库"""
        self.word_db = {
            "考研": [
                {"word": "abandon", "meaning": "放弃,遗弃"},
                {"word": "abstract", "meaning": "抽象的,摘要"},
                {"word": "academic", "meaning": "学术的,学院的"},
                {"word": "access", "meaning": "进入,使用权"},
                {"word": "accompany", "meaning": "陪伴,伴随"},
                {"word": "accomplish", "meaning": "完成,实现"},
                {"word": "accurate", "meaning": "精确的,准确的"},
                {"word": "accuse", "meaning": "指责,控告"},
                {"word": "achieve", "meaning": "达到,完成"},
                {"word": "acknowledge", "meaning": "承认,答谢"},
                {"word": "acquire", "meaning": "获得,学到"},
                {"word": "adapt", "meaning": "适应,改编"},
                {"word": "adequate", "meaning": "足够的,适当的"},
                {"word": "adjust", "meaning": "调整,使适应"},
                {"word": "administration", "meaning": "管理,行政部门"},
                {"word": "admit", "meaning": "承认,准许进入"},
                {"word": "adopt", "meaning": "采用,收养"},
                {"word": "advance", "meaning": "前进,进展"},
                {"word": "advantage", "meaning": "优势,有利条件"},
                {"word": "advertise", "meaning": "做广告,宣传"},
                {"word": "affect", "meaning": "影响,感动"},
                {"word": "afford", "meaning": "负担得起,提供"},
                {"word": "agency", "meaning": "代理,机构"},
                {"word": "aggressive", "meaning": "侵略的,有进取心的"},
                {"word": "alarm", "meaning": "警报,惊慌"},
                {"word": "alert", "meaning": "警觉的,警惕的"},
                {"word": "alliance", "meaning": "联盟,联合"},
                {"word": "allow", "meaning": "允许,承认"},
                {"word": "alter", "meaning": "改变,修改"},
                {"word": "amaze", "meaning": "使吃惊"},
                {"word": "ambition", "meaning": "雄心,抱负"},
                {"word": "amount", "meaning": "数量,总额"},
                {"word": "amuse", "meaning": "使发笑,使愉快"},
                {"word": "analyze", "meaning": "分析,分解"},
                {"word": "announce", "meaning": "宣布,通告"},
                {"word": "annoy", "meaning": "使恼怒,打扰"},
                {"word": "anticipate", "meaning": "预期,期望"},
                {"word": "anxiety", "meaning": "焦虑,渴望"},
                {"word": "apologize", "meaning": "道歉,辩白"},
                {"word": "apparent", "meaning": "显然的,表面上的"},
                {"word": "appeal", "meaning": "呼吁,上诉"},
                {"word": "appear", "meaning": "出现,似乎"},
                {"word": "appliance", "meaning": "用具,器具"},
                {"word": "apply", "meaning": "申请,应用"},
                {"word": "appoint", "meaning": "任命,指定"},
                {"word": "appreciate", "meaning": "欣赏,感激"},
                {"word": "approach", "meaning": "接近,方法"},
                {"word": "approve", "meaning": "批准,赞成"},
                {"word": "argue", "meaning": "争论,辩论"}
            ],
            "高考": [
                {"word": "book", "meaning": "书,预订"},
                {"word": "apple", "meaning": "苹果"},
                {"word": "computer", "meaning": "计算机"},
                {"word": "school", "meaning": "学校"},
                {"word": "teacher", "meaning": "老师"},
                {"word": "student", "meaning": "学生"},
                {"word": "classroom", "meaning": "教室"},
                {"word": "homework", "meaning": "家庭作业"},
                {"word": "examination", "meaning": "考试"},
                {"word": "dictionary", "meaning": "字典"},
                {"word": "library", "meaning": "图书馆"},
                {"word": "knowledge", "meaning": "知识"},
                {"word": "education", "meaning": "教育"},
                {"word": "university", "meaning": "大学"},
                {"word": "college", "meaning": "学院"},
                {"word": "subject", "meaning": "科目,主题"},
                {"word": "mathematics", "meaning": "数学"},
                {"word": "physics", "meaning": "物理"},
                {"word": "chemistry", "meaning": "化学"},
                {"word": "biology", "meaning": "生物"},
                {"word": "geography", "meaning": "地理"},
                {"word": "history", "meaning": "历史"},
                {"word": "language", "meaning": "语言"},
                {"word": "literature", "meaning": "文学"},
                {"word": "philosophy", "meaning": "哲学"},
                {"word": "economy", "meaning": "经济"},
                {"word": "politics", "meaning": "政治"},
                {"word": "culture", "meaning": "文化"},
                {"word": "society", "meaning": "社会"},
                {"word": "development", "meaning": "发展"},
                {"word": "technology", "meaning": "技术"},
                {"word": "science", "meaning": "科学"},
                {"word": "research", "meaning": "研究"},
                {"word": "experiment", "meaning": "实验"},
                {"word": "discovery", "meaning": "发现"},
                {"word": "invention", "meaning": "发明"},
                {"word": "information", "meaning": "信息"},
                {"word": "communication", "meaning": "交流,通讯"},
                {"word": "internet", "meaning": "互联网"},
                {"word": "software", "meaning": "软件"},
                {"word": "hardware", "meaning": "硬件"},
                {"word": "program", "meaning": "程序,节目"},
                {"word": "system", "meaning": "系统"},
                {"word": "database", "meaning": "数据库"},
                {"word": "network", "meaning": "网络"},
                {"word": "security", "meaning": "安全"},
                {"word": "password", "meaning": "密码"},
                {"word": "account", "meaning": "账户"},
                {"word": "application", "meaning": "应用,申请"}
            ],
            "四级": [
                {"word": "examination", "meaning": "考试,检查"},
                {"word": "frequent", "meaning": "频繁的"},
                {"word": "generation", "meaning": "一代,产生"},
                {"word": "global", "meaning": "全球的"},
                {"word": "graduate", "meaning": "毕业,毕业生"},
                {"word": "habit", "meaning": "习惯"},
                {"word": "handle", "meaning": "处理,把手"},
                {"word": "harm", "meaning": "伤害,损害"},
                {"word": "huge", "meaning": "巨大的"},
                {"word": "human", "meaning": "人类,人的"},
                {"word": "hurry", "meaning": "匆忙"},
                {"word": "ideal", "meaning": "理想的,理想"},
                {"word": "identify", "meaning": "识别,鉴定"},
                {"word": "ignore", "meaning": "忽视,不理睬"},
                {"word": "illustrate", "meaning": "说明,阐明"},
                {"word": "image", "meaning": "形象,图像"},
                {"word": "imagine", "meaning": "想象"},
                {"word": "immediate", "meaning": "立即的,直接的"},
                {"word": "impact", "meaning": "影响,冲击"},
                {"word": "implement", "meaning": "实施,工具"},
                {"word": "imply", "meaning": "暗示,意味"},
                {"word": "import", "meaning": "进口,输入"},
                {"word": "impress", "meaning": "给...留下印象"},
                {"word": "improve", "meaning": "改进,提高"},
                {"word": "include", "meaning": "包括,包含"},
                {"word": "income", "meaning": "收入,收益"},
                {"word": "increase", "meaning": "增加,增长"},
                {"word": "indeed", "meaning": "确实,的确"},
                {"word": "indicate", "meaning": "表明,指出"},
                {"word": "individual", "meaning": "个人的,个体"},
                {"word": "industry", "meaning": "工业,产业"},
                {"word": "influence", "meaning": "影响"},
                {"word": "inform", "meaning": "通知,告知"},
                {"word": "initial", "meaning": "最初的,开始的"},
                {"word": "injure", "meaning": "伤害,损害"},
                {"word": "inner", "meaning": "内部的,内心的"},
                {"word": "innocent", "meaning": "无辜的,天真的"},
                {"word": "inquire", "meaning": "询问,调查"},
                {"word": "insert", "meaning": "插入,嵌入"},
                {"word": "insist", "meaning": "坚持,坚决要求"},
                {"word": "inspect", "meaning": "检查,视察"},
                {"word": "inspire", "meaning": "鼓舞,激励"},
                {"word": "install", "meaning": "安装,安置"},
                {"word": "instance", "meaning": "例子,实例"},
                {"word": "instant", "meaning": "立即的,即时的"},
                {"word": "instead", "meaning": "代替,反而"},
                {"word": "institute", "meaning": "学会,研究所"},
                {"word": "instruct", "meaning": "指导,命令"},
                {"word": "instrument", "meaning": "仪器,工具"}
            ],
            "六级": [
                {"word": "phenomenon", "meaning": "现象"},
                {"word": "quintessential", "meaning": "精髓的"},
                {"word": "resilience", "meaning": "恢复力"},
                {"word": "scrutinize", "meaning": "仔细检查"},
                {"word": "spontaneous", "meaning": "自发的"},
                {"word": "subsequent", "meaning": "随后的"},
                {"word": "substantial", "meaning": "大量的,实质的"},
                {"word": "subtle", "meaning": "微妙的,精细的"},
                {"word": "sufficient", "meaning": "足够的"},
                {"word": "superficial", "meaning": "表面的,肤浅的"},
                {"word": "supplement", "meaning": "补充,增刊"},
                {"word": "suppress", "meaning": "压制,抑制"},
                {"word": "surpass", "meaning": "超越,胜过"},
                {"word": "suspend", "meaning": "暂停,悬挂"},
                {"word": "sustain", "meaning": "维持,支撑"},
                {"word": "symposium", "meaning": "研讨会"},
                {"word": "synthesis", "meaning": "合成,综合"},
                {"word": "tangible", "meaning": "有形的,实际的"},
                {"word": "tedious", "meaning": "冗长乏味的"},
                {"word": "temperament", "meaning": "气质,性情"},
                {"word": "temporary", "meaning": "暂时的"},
                {"word": "tentative", "meaning": "试探性的"},
                {"word": "terminate", "meaning": "终止,结束"},
                {"word": "terrific", "meaning": "极好的,可怕的"},
                {"word": "testify", "meaning": "证明,作证"},
                {"word": "therapy", "meaning": "治疗,疗法"},
                {"word": "threshold", "meaning": "门槛,开端"},
                {"word": "thrive", "meaning": "繁荣,兴旺"},
                {"word": "tolerant", "meaning": "宽容的"},
                {"word": "tragedy", "meaning": "悲剧,惨案"},
                {"word": "transaction", "meaning": "交易"},
                {"word": "transcend", "meaning": "超越"},
                {"word": "transient", "meaning": "短暂的"},
                {"word": "transition", "meaning": "过渡,转变"},
                {"word": "transparent", "meaning": "透明的"},
                {"word": "trivial", "meaning": "琐碎的"},
                {"word": "turbulent", "meaning": "动荡的"},
                {"word": "ultimate", "meaning": "最终的"},
                {"word": "unanimous", "meaning": "全体一致的"},
                {"word": "underestimate", "meaning": "低估"},
                {"word": "underlying", "meaning": "潜在的"},
                {"word": "undertake", "meaning": "承担,从事"},
                {"word": "unfold", "meaning": "展开,显露"},
                {"word": "unify", "meaning": "统一"},
                {"word": "unique", "meaning": "独特的"},
                {"word": "universal", "meaning": "普遍的"},
                {"word": "update", "meaning": "更新"},
                {"word": "upgrade", "meaning": "升级"},
                {"word": "uphold", "meaning": "支持,维护"},
                {"word": "utilize", "meaning": "利用"}
            ]
        }
        self.current_words = self.word_db[self.current_level]

    def shuffle_words(self):
        """打乱当前词库的单词顺序"""
        random.shuffle(self.current_words)
        self.current_index = 0

    def setup_connections(self):
        """设置信号槽连接"""
        for level, btn in self.level_buttons.items():
            btn.clicked.connect(lambda checked, l=level: self.change_level(l))

        for i in range(self.mode_group.buttons().__len__()):
            self.mode_group.button(i).toggled.connect(
                lambda checked, idx=i: self.change_mode(idx) if checked else None)

        self.prev_btn.clicked.connect(self.prev_word)
        self.next_btn.clicked.connect(self.next_word)
        self.check_btn.clicked.connect(self.check_answer)
        self.mode3_input.returnPressed.connect(self.check_input_mode)
        self.mode3_input.textChanged.connect(self.on_input_text_changed)

        # 测试模式按钮连接
        self.start_test_btn.clicked.connect(self.start_test)
        self.end_test_btn.clicked.connect(self.end_test)
        self.save_results_btn.clicked.connect(self.save_test_results)

    def on_input_text_changed(self):
        """处理输入框文本变化事件"""
        if self.input_error_shown:
            self.mode3_input.clear()
            self.mode3_feedback.clear()
            self.input_error_shown = False
        else:
            # 正常处理文本变化
            pass

    def setup_top_bar(self):
        """设置顶部选择栏"""
        self.top_bar = QHBoxLayout()
        self.level_buttons = {}
        for level in ["高考", "四级", "六级", "考研"]:
            btn = QPushButton(level)
            btn.setStyleSheet("""
                QPushButton {
                    padding: 8px 15px;
                    font-weight: bold;
                    border-radius: 5px;
                    background-color: #f0f0f0;
                }
                QPushButton:hover {
                    background-color: #e0e0e0;
                }
                QPushButton:pressed {
                    background-color: #d0d0d0;
                }
            """)
            self.level_buttons[level] = btn
            self.top_bar.addWidget(btn)
        self.main_layout.addLayout(self.top_bar)

    def setup_mode_selector(self):
        """设置模式选择器"""
        self.mode_group = QButtonGroup()
        self.mode_layout = QHBoxLayout()
        for i, mode in enumerate(["拆分模式", "填空模式", "输入模式", "测试模式"]):
            rb = QRadioButton(mode)
            rb.setStyleSheet("""
                QRadioButton {
                    spacing: 5px;
                    font-weight: bold;
                }
                QRadioButton::indicator {
                    width: 16px;
                    height: 16px;
                }
            """)
            self.mode_group.addButton(rb, i)
            self.mode_layout.addWidget(rb)
            if i == 0:
                rb.setChecked(True)
        self.main_layout.addLayout(self.mode_layout)

    def setup_stacked_widget(self):
        """设置堆叠窗口"""
        self.stacked_widget = QStackedWidget()

        self.mode1_widget = self.create_mode1_widget()
        self.stacked_widget.addWidget(self.mode1_widget)

        self.mode2_widget = self.create_mode2_widget()
        self.stacked_widget.addWidget(self.mode2_widget)

        self.mode3_widget = self.create_mode3_widget()
        self.stacked_widget.addWidget(self.mode3_widget)

        self.mode4_widget = self.create_test_mode_widget()
        self.stacked_widget.addWidget(self.mode4_widget)

        self.main_layout.addWidget(self.stacked_widget)

    def create_mode1_widget(self):
        """创建拆分模式组件"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(20)

        self.mode1_meaning = QLabel()
        self.mode1_meaning.setAlignment(Qt.AlignCenter)
        self.mode1_meaning.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                color: #333;
                padding: 10px;
                background-color: #f9f9f9;
                border-radius: 8px;
                border: 1px solid #ddd;
            }
        """)
        layout.addWidget(self.mode1_meaning)

        self.mode1_chunks_container = QWidget()
        self.mode1_chunks_layout = QHBoxLayout(self.mode1_chunks_container)
        self.mode1_chunks_layout.setSpacing(10)
        layout.addWidget(self.mode1_chunks_container)

        self.mode1_answer = QLabel()
        self.mode1_answer.setAlignment(Qt.AlignCenter)
        self.mode1_answer.setStyleSheet("""
            QLabel {
                font-size: 28px;
                font-weight: bold;
                min-height: 50px;
                border: 2px dashed #aaa;
                border-radius: 8px;
                padding: 10px;
            }
        """)
        layout.addWidget(self.mode1_answer)

        self.mode1_feedback = QLabel()
        self.mode1_feedback.setAlignment(Qt.AlignCenter)
        self.mode1_feedback.setStyleSheet("""
            QLabel {
                font-size: 16px;
                min-height: 30px;
            }
        """)
        layout.addWidget(self.mode1_feedback)

        return widget

    def create_mode2_widget(self):
        """创建填空模式组件"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(20)

        self.mode2_meaning = QLabel()
        self.mode2_meaning.setAlignment(Qt.AlignCenter)
        self.mode2_meaning.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                color: #333;
                padding: 10px;
                background-color: #f9f9f9;
                border-radius: 8px;
                border: 1px solid #ddd;
            }
        """)
        layout.addWidget(self.mode2_meaning)

        self.mode2_blank = QLabel()
        self.mode2_blank.setAlignment(Qt.AlignCenter)
        self.mode2_blank.setStyleSheet("""
            QLabel {
                font-size: 28px;
                font-weight: bold;
                min-height: 50px;
                padding: 10px;
            }
        """)
        layout.addWidget(self.mode2_blank)

        self.mode2_options_container = QWidget()
        self.mode2_options_layout = QHBoxLayout(self.mode2_options_container)
        self.mode2_options_layout.setSpacing(15)
        layout.addWidget(self.mode2_options_container)

        self.mode2_feedback = QLabel()
        self.mode2_feedback.setAlignment(Qt.AlignCenter)
        self.mode2_feedback.setStyleSheet("""
            QLabel {
                font-size: 16px;
                min-height: 30px;
            }
        """)
        layout.addWidget(self.mode2_feedback)

        return widget

    def create_mode3_widget(self):
        """创建输入模式组件"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(20)

        self.mode3_meaning = QLabel()
        self.mode3_meaning.setAlignment(Qt.AlignCenter)
        self.mode3_meaning.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                color: #333;
                padding: 10px;
                background-color: #f9f9f9;
                border-radius: 8px;
                border: 1px solid #ddd;
            }
        """)
        layout.addWidget(self.mode3_meaning)

        self.mode3_input = QLineEdit()
        self.mode3_input.setStyleSheet("""
            QLineEdit {
                font-size: 24px;
                padding: 10px;
                border: 2px solid #ccc;
                border-radius: 8px;
            }
            QLineEdit:focus {
                border: 2px solid #6a9eda;
            }
        """)
        self.mode3_input.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.mode3_input)

        self.mode3_feedback = QLabel()
        self.mode3_feedback.setAlignment(Qt.AlignCenter)
        self.mode3_feedback.setStyleSheet("""
            QLabel {
                font-size: 16px;
                min-height: 30px;
            }
        """)
        layout.addWidget(self.mode3_feedback)

        return widget

    def create_test_mode_widget(self):
        """创建测试模式组件"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(20)

        # 测试模式控制按钮
        self.test_controls = QHBoxLayout()

        self.start_test_btn = QPushButton("开始测试")
        self.start_test_btn.setStyleSheet("""
            QPushButton {
                padding: 8px 20px;
                font-weight: bold;
                border-radius: 5px;
                background-color: #4CAF50;
                color: white;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
        """)

        self.end_test_btn = QPushButton("结束测试")
        self.end_test_btn.setStyleSheet("""
            QPushButton {
                padding: 8px 20px;
                font-weight: bold;
                border-radius: 5px;
                background-color: #f44336;
                color: white;
            }
            QPushButton:hover {
                background-color: #d32f2f;
            }
            QPushButton:pressed {
                background-color: #b71c1c;
            }
        """)
        self.end_test_btn.setEnabled(False)

        self.test_controls.addWidget(self.start_test_btn)
        self.test_controls.addWidget(self.end_test_btn)
        layout.addLayout(self.test_controls)

        # 测试模式显示区域
        self.test_info_label = QLabel("准备开始测试...")
        self.test_info_label.setAlignment(Qt.AlignCenter)
        self.test_info_label.setStyleSheet("""
            QLabel {
                font-size: 18px;
                font-weight: bold;
                color: #333;
                padding: 10px;
                background-color: #f9f9f9;
                border-radius: 8px;
                border: 1px solid #ddd;
            }
        """)
        layout.addWidget(self.test_info_label)

        # 测试模式输入区域
        self.test_input = QLineEdit()
        self.test_input.setStyleSheet("""
            QLineEdit {
                font-size: 24px;
                padding: 10px;
                border: 2px solid #ccc;
                border-radius: 8px;
            }
            QLineEdit:focus {
                border: 2px solid #6a9eda;
            }
        """)
        self.test_input.setAlignment(Qt.AlignCenter)
        self.test_input.setEnabled(False)
        self.test_input.returnPressed.connect(self.check_test_answer)
        layout.addWidget(self.test_input)

        # 测试反馈
        self.test_feedback = QLabel()
        self.test_feedback.setAlignment(Qt.AlignCenter)
        self.test_feedback.setStyleSheet("""
            QLabel {
                font-size: 16px;
                min-height: 30px;
            }
        """)
        layout.addWidget(self.test_feedback)

        return widget

    def setup_test_results_widget(self):
        """设置测试结果组件"""
        try:
            # 创建结果部件(如果不存在)
            if not hasattr(self, 'test_results_widget'):
                self.test_results_widget = QWidget()
                self.test_results_layout = QVBoxLayout(self.test_results_widget)
                self.test_results_layout.setContentsMargins(20, 20, 20, 20)

                self.test_results_title = QLabel("测试结果")
                self.test_results_title.setAlignment(Qt.AlignCenter)
                self.test_results_title.setStyleSheet("""
                    QLabel {
                        font-size: 20px;
                        font-weight: bold;
                        color: #333;
                        padding: 10px;
                    }
                """)
                self.test_results_layout.addWidget(self.test_results_title)

                self.test_results_text = QTextEdit()
                self.test_results_text.setReadOnly(True)
                self.test_results_text.setStyleSheet("""
                    QTextEdit {
                        font-size: 14px;
                        border: 1px solid #ddd;
                        border-radius: 5px;
                        padding: 10px;
                    }
                """)
                self.test_results_layout.addWidget(self.test_results_text)

                self.save_results_btn = QPushButton("保存结果")
                self.save_results_btn.setStyleSheet("""
                    QPushButton {
                        padding: 8px 20px;
                        font-weight: bold;
                        border-radius: 5px;
                        background-color: #2196F3;
                        color: white;
                    }
                    QPushButton:hover {
                        background-color: #0b7dda;
                    }
                    QPushButton:pressed {
                        background-color: #0a68b4;
                    }
                """)
                self.test_results_layout.addWidget(self.save_results_btn)

                # 返回按钮
                self.return_btn = QPushButton("返回主界面")
                self.return_btn.setStyleSheet("""
                    QPushButton {
                        padding: 8px 20px;
                        font-weight: bold;
                        border-radius: 5px;
                        background-color: #6c757d;
                        color: white;
                    }
                    QPushButton:hover {
                        background-color: #5a6268;
                    }
                    QPushButton:pressed {
                        background-color: #484e53;
                    }
                """)
                self.return_btn.clicked.connect(self.return_to_main)
                self.test_results_layout.addWidget(self.return_btn)

            # 初始隐藏结果窗口
            self.test_results_widget.hide()
        except Exception as e:
            self.show_error_message(f"测试结果部件初始化失败: {str(e)}")
            raise

    def setup_bottom_controls(self):
        """设置底部控制按钮"""
        self.bottom_layout = QHBoxLayout()
        self.bottom_layout.setSpacing(20)

        self.prev_btn = QPushButton("上一个")
        self.next_btn = QPushButton("下一个")
        self.check_btn = QPushButton("检查")

        for btn in [self.prev_btn, self.next_btn, self.check_btn]:
            btn.setStyleSheet("""
                QPushButton {
                    padding: 8px 20px;
                    font-weight: bold;
                    border-radius: 5px;
                    background-color: #4CAF50;
                    color: white;
                }
                QPushButton:hover {
                    background-color: #45a049;
                }
                QPushButton:pressed {
                    background-color: #3d8b40;
                }
                QPushButton:disabled {
                    background-color: #cccccc;
                }
            """)
            btn.setMinimumWidth(100)

        self.bottom_layout.addStretch()
        self.bottom_layout.addWidget(self.prev_btn)
        self.bottom_layout.addWidget(self.next_btn)
        self.bottom_layout.addWidget(self.check_btn)
        self.bottom_layout.addStretch()

        self.main_layout.addLayout(self.bottom_layout)

    def change_level(self, level):
        """切换词库级别"""
        try:
            self.current_level = level
            self.current_words = self.word_db[level]
            self.shuffle_words()
            self.show_word()
            self.clear_feedback()
        except Exception as e:
            self.show_error_message(f"切换级别失败: {str(e)}")

    def change_mode(self, mode):
        """切换练习模式"""
        try:
            self.current_mode = mode
            self.stacked_widget.setCurrentIndex(mode)

            if mode == 3:
                self.test_mode = False
                self.test_info_label.setText("准备开始测试...")
                self.test_input.setEnabled(False)
                self.test_feedback.clear()
            else:
                if self.test_mode:
                    self.end_test()
                self.show_word()
                self.clear_feedback()
        except Exception as e:
            self.show_error_message(f"切换模式失败: {str(e)}")

    def clear_feedback(self):
        """清除所有反馈信息"""
        if hasattr(self, 'mode1_feedback'):
            self.mode1_feedback.clear()
        if hasattr(self, 'mode2_feedback'):
            self.mode2_feedback.clear()
        if hasattr(self, 'mode3_feedback'):
            self.mode3_feedback.clear()
            self.input_error_shown = False
        if hasattr(self, 'test_feedback'):
            self.test_feedback.clear()

    def show_word(self):
        """显示当前单词"""
        try:
            if not self.current_words or self.current_index >= len(self.current_words):
                return

            word_data = self.current_words[self.current_index]
            word = word_data["word"]
            meaning = word_data["meaning"]

            if self.current_mode == 0:
                self.setup_mode1(word, meaning)
            elif self.current_mode == 1:
                self.setup_mode2(word, meaning)
            elif self.current_mode == 2:
                self.setup_mode3(meaning)
        except Exception as e:
            self.show_error_message(f"显示单词失败: {str(e)}")

    def setup_mode1(self, word, meaning):
        """设置拆分模式"""
        self.mode1_meaning.setText(meaning)
        self.mode1_answer.clear()
        self.mode1_feedback.clear()

        # 清理旧按钮
        while self.mode1_chunks_layout.count():
            item = self.mode1_chunks_layout.takeAt(0)
            if item.widget():
                item.widget().deleteLater()

        # 安全拆分单词
        if len(word) < 2:
            chunks = [word]
        else:
            n = min(3, max(2, len(word) // 2))
            split_points = sorted(random.sample(range(1, len(word)), n - 1))
            chunks = []
            start = 0
            for point in split_points:
                chunks.append(word[start:point])
                start = point
            chunks.append(word[start:])

        # 打乱顺序
        random.shuffle(chunks)

        # 创建新按钮
        self.chunk_buttons = []
        self.selected_chunks = []  # 存储字典:{"chunk": 片段, "button": 按钮, "position": 位置}
        for chunk in chunks:
            btn = QPushButton(chunk)
            btn.setStyleSheet("""
                QPushButton {
                    font-size: 18px;
                    padding: 10px 15px;
                    background-color: #e7f3fe;
                    border: 1px solid #b8daff;
                    border-radius: 5px;
                }
                QPushButton:hover {
                    background-color: #d0e3fc;
                }
                QPushButton:pressed {
                    background-color: #b8daff;
                }
                QPushButton:disabled {
                    background-color: #f8f9fa;
                    color: #6c757d;
                    border: 1px solid #dee2e6;
                }
            """)
            btn.clicked.connect(lambda _, c=chunk, b=btn: self.toggle_chunk(c, b))
            self.mode1_chunks_layout.addWidget(btn)
            self.chunk_buttons.append(btn)

        self.correct_word = word
        self.user_answer = ""

    def toggle_chunk(self, chunk, button):
        """切换单词块的选择状态"""
        try:
            if button.isEnabled():
                # 选择片段
                self.user_answer += chunk
                self.mode1_answer.setText(self.user_answer)
                button.setEnabled(False)
                # 记录片段信息
                self.selected_chunks.append({
                    "chunk": chunk,
                    "button": button,
                    "position": len(self.user_answer) - len(chunk)
                })
                self.mode1_feedback.clear()

                # 检查是否完成
                if len(self.user_answer) == len(self.correct_word):
                    if self.user_answer == self.correct_word:
                        self.mode1_answer.setStyleSheet("color: #28a745;")
                        self.mode1_feedback.setText("✓ 正确!")
                        self.mode1_feedback.setStyleSheet("color: #28a745;")
                        QTimer.singleShot(1000, self.next_word)
                    else:
                        self.mode1_answer.setStyleSheet("color: #dc3545;")
                        self.mode1_feedback.setText(f"✗ 错误!正确答案是: {self.correct_word}")
                        self.mode1_feedback.setStyleSheet("color: #dc3545;")
                        QTimer.singleShot(1000, self.reset_mode1)
            else:
                # 取消选择片段
                for i, selected in enumerate(self.selected_chunks):
                    if selected["button"] == button:
                        # 从答案中移除该片段
                        pos = selected["position"]
                        chunk_len = len(selected["chunk"])
                        self.user_answer = self.user_answer[:pos] + self.user_answer[pos + chunk_len:]
                        self.mode1_answer.setText(self.user_answer)
                        button.setEnabled(True)
                        # 更新其他片段的位置
                        for other in self.selected_chunks[i + 1:]:
                            other["position"] -= chunk_len
                        # 从列表中移除
                        self.selected_chunks.pop(i)
                        break
        except Exception as e:
            self.show_error_message(f"切换单词块状态失败: {str(e)}")

    def reset_mode1(self):
        """重置拆分模式"""
        try:
            # 重新启用所有已选择的块按钮
            for selected in self.selected_chunks:
                selected["button"].setEnabled(True)

            # 清空已选择块列表
            self.selected_chunks = []

            # 清空答案和反馈
            self.mode1_answer.clear()
            self.mode1_feedback.clear()
            self.user_answer = ""
        except Exception as e:
            self.show_error_message(f"重置拆分模式失败: {str(e)}")

    def setup_mode2(self, word, meaning):
        """设置填空模式"""
        try:
            self.mode2_meaning.setText(meaning)
            self.mode2_feedback.clear()

            # 清理旧选项
            while self.mode2_options_layout.count():
                item = self.mode2_options_layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.deleteLater()
                del item

            # 创建填空
            if len(word) <= 3:
                blank_pos = len(word) // 2
                blank_len = len(word) - blank_pos
                correct_part = word[blank_pos:]
            else:
                blank_len = min(3, max(2, len(word) // 3))
                blank_pos = random.randint(1, len(word) - blank_len - 1)
                correct_part = word[blank_pos:blank_pos + blank_len]

                blank_word = word[:blank_pos] + "_" * blank_len + word[blank_pos + blank_len:]
                self.mode2_blank.setText(blank_word)

                # 生成选项
                options = [correct_part]
                chars = list(set(word) - set(correct_part))

            while len(options) < 4:
                if chars:
                    option = ''.join(random.sample(chars, min(len(chars), blank_len)))
                else:
                    option = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=blank_len))

                if option != correct_part and option not in options:
                    options.append(option)

            random.shuffle(options)

            # 创建选项按钮
            self.option_buttons = []  # 保存按钮引用防止被垃圾回收
            for option in options:
                btn = QPushButton(option)
                btn.setStyleSheet("""
                    QPushButton {
                        font-size: 18px;
                        padding: 10px 15px;
                        background-color: #e7f3fe;
                        border: 1px solid #b8daff;
                        border-radius: 5px;
                    }
                    QPushButton:hover {
                        background-color: #d0e3fc;
                    }
                    QPushButton:pressed {
                        background-color: #b8daff;
                    }
                """)
                btn.clicked.connect(lambda _, o=option, cp=correct_part, w=word: self.check_fill_answer(o, cp, w))
                self.mode2_options_layout.addWidget(btn)
                self.option_buttons.append(btn)  # 保存按钮引用
        except Exception as e:
            self.show_error_message(f"设置填空模式失败: {str(e)}")

    def check_fill_answer(self, selected, correct, full_word):
        """检查填空答案"""
        try:
            if selected == correct:
                # 显示完整单词
                self.mode2_blank.setText(full_word)
                self.mode2_feedback.setText("✓ 正确!")
                self.mode2_feedback.setStyleSheet("color: #28a745;")
                QTimer.singleShot(1000, self.next_word)
            else:
                self.mode2_feedback.setText(f"✗ 错误!正确答案是: {correct}")
                self.mode2_feedback.setStyleSheet("color: #dc3545;")
        except Exception as e:
            self.show_error_message(f"检查填空答案失败: {str(e)}")

    def setup_mode3(self, meaning):
        """设置输入模式"""
        try:
            self.mode3_meaning.setText(meaning)
            self.mode3_input.clear()
            self.mode3_feedback.clear()
            self.mode3_input.setFocus()
            self.input_error_shown = False
        except Exception as e:
            self.show_error_message(f"设置输入模式失败: {str(e)}")

    def check_input_mode(self):
        """检查输入模式答案"""
        try:
            user_input = self.mode3_input.text().strip().lower()
            correct = self.current_words[self.current_index]["word"].lower()

            if user_input == correct:
                self.mode3_feedback.setText("✓ 正确!")
                self.mode3_feedback.setStyleSheet("color: #28a745;")
                QTimer.singleShot(1000, self.next_word)
            else:
                self.mode3_feedback.setText(f"✗ 错误!正确答案是: {correct}")
                self.mode3_feedback.setStyleSheet("color: #dc3545;")
                self.input_error_shown = True
        except Exception as e:
            self.show_error_message(f"检查输入答案失败: {str(e)}")

    def check_answer(self):
        """检查答案"""
        try:
            if self.current_mode == 2:
                self.check_input_mode()
        except Exception as e:
            self.show_error_message(f"检查答案失败: {str(e)}")

    def prev_word(self):
        """上一个单词"""
        try:
            if self.current_index > 0:
                self.current_index -= 1
                self.show_word()
                self.clear_feedback()
        except Exception as e:
            self.show_error_message(f"切换上一个单词失败: {str(e)}")

    def next_word(self):
        """下一个单词"""
        try:
            if self.current_index < len(self.current_words) - 1:
                self.current_index += 1
                self.show_word()
                self.clear_feedback()
            else:
                if self.current_mode == 0:
                    self.mode1_feedback.setText("🎉 已完成当前词库所有单词!")
                    self.mode1_feedback.setStyleSheet("color: #17a2b8;")
                elif self.current_mode == 1:
                    self.mode2_feedback.setText("🎉 已完成当前词库所有单词!")
                    self.mode2_feedback.setStyleSheet("color: #17a2b8;")
                elif self.current_mode == 2:
                    self.mode3_feedback.setText("🎉 已完成当前词库所有单词!")
                    self.mode3_feedback.setStyleSheet("color: #17a2b8;")

                self.shuffle_words()
                QTimer.singleShot(2000, self.show_word)
        except Exception as e:
            self.show_error_message(f"切换下一个单词失败: {str(e)}")

    def start_test(self):
        """开始测试"""
        try:
            self.test_mode = True
            self.test_results = {}
            self.current_test_words = self.current_words.copy()
            random.shuffle(self.current_test_words)
            self.test_index = 0

            for word_data in self.current_test_words:
                word = word_data["word"]
                self.test_results[word] = {"errors": 0, "meaning": word_data["meaning"]}

            self.start_test_btn.setEnabled(False)
            self.end_test_btn.setEnabled(True)
            self.test_input.setEnabled(True)
            self.test_input.clear()
            self.test_feedback.clear()

            self.show_next_test_word()
        except Exception as e:
            self.show_error_message(f"开始测试失败: {str(e)}")

    def show_next_test_word(self):
        """显示下一个测试单词"""
        if self.test_index < len(self.current_test_words):
            word_data = self.current_test_words[self.test_index]
            self.test_info_label.setText(
                f"测试中 ({self.test_index + 1}/{len(self.current_test_words)}): {word_data['meaning']}")
            self.test_input.clear()
            self.test_feedback.clear()
            self.test_input.setFocus()
        else:
            self.end_test()

    def check_test_answer(self):
        """检查测试答案"""
        try:
            if not self.test_mode:
                return

            user_input = self.test_input.text().strip().lower()
            current_word_data = self.current_test_words[self.test_index]
            correct_word = current_word_data["word"].lower()

            if user_input == correct_word:
                self.test_feedback.setText("✓ 正确!")
                self.test_feedback.setStyleSheet("color: #28a745;")
                self.test_index += 1
                QTimer.singleShot(1000, self.show_next_test_word)
            else:
                self.test_feedback.setText(f"✗ 错误!正确答案是: {correct_word}")
                self.test_feedback.setStyleSheet("color: #dc3545;")
                self.test_results[correct_word]["errors"] += 1
                self.test_input_error_shown = True  # 标记错误已显示
                # 设置定时器,1秒后清除错误信息
                QTimer.singleShot(1000, self.clear_test_input)
        except Exception as e:
            self.show_error_message(f"检查测试答案失败: {str(e)}")

    def clear_test_input(self):
        """清除测试输入框和错误信息"""
        if hasattr(self, 'test_input_error_shown') and self.test_input_error_shown:
            self.test_input.clear()
            self.test_feedback.clear()
            self.test_input_error_shown = False
            self.test_input.setFocus()

    def setup_test_mode_widget(self):
        """创建测试模式组件"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(20, 20, 20, 20)
        layout.setSpacing(20)

        # 测试模式控制按钮
        self.test_controls = QHBoxLayout()

        self.start_test_btn = QPushButton("开始测试")
        self.start_test_btn.setStyleSheet("""
            QPushButton {
                padding: 8px 20px;
                font-weight: bold;
                border-radius: 5px;
                background-color: #4CAF50;
                color: white;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
        """)

        self.end_test_btn = QPushButton("结束测试")
        self.end_test_btn.setStyleSheet("""
            QPushButton {
                padding: 8px 20px;
                font-weight: bold;
                border-radius: 5px;
                background-color: #f44336;
                color: white;
            }
            QPushButton:hover {
                background-color: #d32f2f;
            }
            QPushButton:pressed {
                background-color: #b71c1c;
            }
        """)
        self.end_test_btn.setEnabled(False)

        self.test_controls.addWidget(self.start_test_btn)
        self.test_controls.addWidget(self.end_test_btn)
        layout.addLayout(self.test_controls)

        # 测试模式显示区域
        self.test_info_label = QLabel("准备开始测试...")
        self.test_info_label.setAlignment(Qt.AlignCenter)
        self.test_info_label.setStyleSheet("""
            QLabel {
                font-size: 18px;
                font-weight: bold;
                color: #333;
                padding: 10px;
                background-color: #f9f9f9;
                border-radius: 8px;
                border: 1px solid #ddd;
            }
        """)
        layout.addWidget(self.test_info_label)

        # 测试模式输入区域
        self.test_input = QLineEdit()
        self.test_input.setStyleSheet("""
            QLineEdit {
                font-size: 24px;
                padding: 10px;
                border: 2px solid #ccc;
                border-radius: 8px;
            }
            QLineEdit:focus {
                border: 2px solid #6a9eda;
            }
        """)
        self.test_input.setAlignment(Qt.AlignCenter)
        self.test_input.setEnabled(False)
        self.test_input.returnPressed.connect(self.check_test_answer)
        # 添加文本变化信号连接
        self.test_input.textChanged.connect(self.on_test_input_text_changed)
        layout.addWidget(self.test_input)

        # 测试反馈
        self.test_feedback = QLabel()
        self.test_feedback.setAlignment(Qt.AlignCenter)
        self.test_feedback.setStyleSheet("""
            QLabel {
                font-size: 16px;
                min-height: 30px;
            }
        """)
        layout.addWidget(self.test_feedback)

        # 初始化错误显示标记
        self.test_input_error_shown = False
        # 初始化测试模式状态
        self.test_mode = False
        self.test_input_error_shown = False

        return widget

    def on_test_input_text_changed(self):
        """处理测试输入框文本变化事件"""
        if hasattr(self, 'test_input_error_shown') and self.test_input_error_shown:
            self.test_input.clear()
            self.test_feedback.clear()
            self.test_input_error_shown = False

    def end_test(self):
        """结束测试并显示结果"""
        try:
            self.test_mode = False
            self.start_test_btn.setEnabled(True)
            self.end_test_btn.setEnabled(False)
            self.test_input.setEnabled(False)
            self.test_input.clear()  # 清空输入框
            self.test_feedback.clear()  # 清空反馈

            # 按错误次数排序,错误多的排在前面
            sorted_results = sorted(self.test_results.items(),
                                    key=lambda x: x[1]["errors"],
                                    reverse=True)

            result_text = f"测试完成 - {self.current_level}词库\n\n"
            result_text += "单词\t\t错误次数\t\t释义\n"
            result_text += "-" * 60 + "\n"

            for word, data in sorted_results:
                result_text += f"{word.ljust(15)}\t{data['errors']}\t\t{data['meaning']}\n"

            # 添加统计信息
            total_words = len(self.test_results)
            correct_words = sum(1 for word in self.test_results.values() if word["errors"] == 0)
            accuracy = correct_words / total_words * 100 if total_words > 0 else 0
            most_mistakes = sorted_results[0] if sorted_results else ("", {"errors": 0, "meaning": ""})

            result_text += "\n统计信息:\n"
            result_text += f"总单词数: {total_words}\n"
            result_text += f"正确掌握的单词: {correct_words}\n"
            result_text += f"准确率: {accuracy:.1f}%\n"
            result_text += f"错误最多的单词: {most_mistakes[0]} (错误 {most_mistakes[1]['errors']} 次)\n"

            self.test_results_text.setText(result_text)

            # 使用堆叠窗口而不是替换中央部件
            if not hasattr(self, 'results_stack'):
                self.results_stack = QStackedWidget()
                self.results_stack.addWidget(self.central_widget)
                self.results_stack.addWidget(self.test_results_widget)
                self.setCentralWidget(self.results_stack)

            self.results_stack.setCurrentIndex(1)  # 显示结果界面

        except Exception as e:
            self.show_error_message(f"结束测试失败: {str(e)}")

    def save_test_results(self):
        """保存测试结果到文件"""
        try:
            options = QFileDialog.Options()
            file_name, _ = QFileDialog.getSaveFileName(self, "保存测试结果",
                                                       f"{self.current_level}_测试结果.txt",
                                                       "Text Files (*.txt)",
                                                       options=options)
            if file_name:
                with open(file_name, 'w', encoding='utf-8') as f:
                    f.write(self.test_results_text.toPlainText())
                QMessageBox.information(self, "保存成功", "测试结果已成功保存!")
        except Exception as e:
            self.show_error_message(f"保存测试结果失败: {str(e)}")

    def return_to_main(self):
        """从结果界面返回到主界面"""
        try:
            if hasattr(self, 'results_stack'):
                self.results_stack.setCurrentIndex(0)  # 显示主界面

            # 重置测试模式状态
            self.test_mode = False
            self.start_test_btn.setEnabled(True)
            self.end_test_btn.setEnabled(False)
            self.test_input.setEnabled(False)
            self.test_info_label.setText("准备开始测试...")
            self.test_feedback.clear()

        except Exception as e:
            self.show_error_message(f"返回主界面失败: {str(e)}")

    def show_error_message(self, message):
        """显示错误信息"""
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Critical)
        msg.setText("发生错误")
        msg.setInformativeText(message)
        msg.setWindowTitle("错误")
        msg.exec_()


if __name__ == "__main__":
    try:
        app = QApplication(sys.argv)
        app.setStyle('Fusion')

        # 增加堆栈大小以防止溢出
        import ctypes

        ctypes.cdll.msvcrt._resetstkoflw()

        window = WordPracticeApp()
        window.show()

        ret = app.exec_()
        sys.exit(ret)
    except SystemExit:
        pass
    except Exception as e:
        print(f"致命错误: {e}")
        import traceback

        traceback.print_exc()
        sys.exit(1)
相关推荐
Maybe_ch22 分钟前
.NET-键控服务依赖注入
开发语言·c#·.net
超浪的晨29 分钟前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
终焉暴龙王32 分钟前
CTFHub web进阶 php Bypass disable_function通关攻略
开发语言·安全·web安全·php
AntBlack37 分钟前
从小不学好 ,影刀 + ddddocr 实现图片验证码认证自动化
后端·python·计算机视觉
凪卄12131 小时前
图像预处理 二
人工智能·python·深度学习·计算机视觉·pycharm
巫婆理发2221 小时前
强化学习(第三课第三周)
python·机器学习·深度神经网络
seasonsyy1 小时前
1.安装anaconda详细步骤(含安装截图)
python·深度学习·环境配置
Edingbrugh.南空1 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
半新半旧1 小时前
python 整合使用 Redis
redis·python·bootstrap
Blossom.1182 小时前
基于深度学习的图像分类:使用Capsule Networks实现高效分类
人工智能·python·深度学习·神经网络·机器学习·分类·数据挖掘