python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python单词记忆软件

基于Python实现简易的单词记忆软件

作者:封奚泽优

这篇文章主要为大家详细介绍了如何基于Python实现一个简易的单词记忆软件,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前言

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

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

拆分模式

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 = ""

填空模式

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)  # 保存按钮引用

输入模式

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

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

测试模式

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)  # 显示结果界面

完整代码

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)

以上就是基于Python实现简易的单词记忆软件的详细内容,更多关于Python单词记忆软件的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文