最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Python實現(xiàn)一個簡單的題庫與在線考試系統(tǒng)

 更新時間:2025年06月10日 16:24:40   作者:創(chuàng)客白澤  
在當(dāng)今信息化教育時代,在線學(xué)習(xí)與考試系統(tǒng)已成為教育技術(shù)領(lǐng)域的重要組成部分,本文就來介紹一下如何使用Python和PyQt5框架開發(fā)一個名為白澤題庫系統(tǒng)的智能刷題軟件吧

概述

在當(dāng)今信息化教育時代,在線學(xué)習(xí)與考試系統(tǒng)已成為教育技術(shù)領(lǐng)域的重要組成部分。本文將詳細介紹一款名為"白澤題庫系統(tǒng)"的智能刷題軟件的設(shè)計與實現(xiàn),該系統(tǒng)基于Python的PyQt5框架開發(fā),集題庫管理、隨機組卷、智能刷題、錯題集和學(xué)習(xí)統(tǒng)計等功能于一體。

白澤是中國古代神話中的神獸,以博學(xué)多識著稱,本系統(tǒng)取其"智慧"之意,旨在為用戶提供一個高效、智能的刷題學(xué)習(xí)平臺。系統(tǒng)采用模塊化設(shè)計,具有良好的擴展性和用戶體驗,特別適合各類考試備考使用。

功能特點

白澤題庫系統(tǒng)具備以下核心功能模塊:

功能模塊描述技術(shù)實現(xiàn)
題庫管理支持創(chuàng)建、編輯、導(dǎo)入/導(dǎo)出題庫JSON/Excel文件處理
隨機組卷按題型比例隨機生成試卷隨機算法、計時功能
題海刷題順序/逆序/隨機刷題模式用戶答案記錄
錯題集自動收集錯題,支持復(fù)習(xí)數(shù)據(jù)結(jié)構(gòu)存儲
學(xué)習(xí)統(tǒng)計可視化錯題分布與趨勢Matplotlib圖表

系統(tǒng)采用MVC架構(gòu)設(shè)計,主要技術(shù)棧包括:

  • 前端:PyQt5 + Qt Designer
  • 數(shù)據(jù)處理:JSON + openpyxl
  • 圖表展示:Matplotlib
  • 核心邏輯:Python 3.x

界面展示

主界面

題庫管理

考試模式

刷題模式

錯題集

學(xué)習(xí)統(tǒng)計

系統(tǒng)架構(gòu)設(shè)計

類結(jié)構(gòu)圖

Excel題庫填寫格式模板

題庫題目填寫格式表

字段名類型必填說明示例
type字符串題目類型,可選值:“單選題”、“多選題”、“判斷題”“單選題”
question字符串題目內(nèi)容“Python是什么類型的語言?”
options字符串列表單選/多選必填題目選項(判斷題固定為[“正確”, “錯誤”])[“編譯型”, “解釋型”, “混合型”, “匯編型”]
answer字符串正確答案(多選題用逗號+空格分隔)“B”(單選) “A, B, C”(多選) “正確”(判斷)
score整數(shù)題目分值(默認1分)2
explanation字符串題目解析(可選)“Python是解釋型語言,代碼在運行時逐行解釋執(zhí)行。”

核心數(shù)據(jù)結(jié)構(gòu)

題庫存儲結(jié)構(gòu)

{
    "題庫名稱": [
        {
            "type": "單選題",
            "question": "問題文本",
            "options": ["A", "B", "C", "D"],
            "answer": "A",
            "score": 2
        },
        # 更多題目...
    ]
}

錯題集結(jié)構(gòu)

{
    "題庫名稱": [
        {
            "type": "單選題",
            "question": "問題文本",
            "options": ["A", "B", "C", "D"],
            "answer": "A",
            "user_answer": "B",
            "score": 2
        },
        # 更多錯題...
    ]
}

實現(xiàn)步驟詳解

1. 環(huán)境配置

首先需要安裝必要的Python庫:

pip install pyqt5 openpyxl matplotlib

2. 主窗口初始化

class BrainyQuiz(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("白澤題庫系統(tǒng)")
        self.setGeometry(100, 100, 1000, 700)
        self.setStyleSheet(self.get_stylesheet())
        
        # 初始化數(shù)據(jù)
        self.current_question_bank = None
        self.question_banks = {}
        self.current_questions = []
        self.current_index = 0
        self.user_answers = {}
        self.wrong_questions = {}
        
        # 創(chuàng)建界面
        self.init_ui()
        self.load_question_bank_list()

3. 界面布局設(shè)計

系統(tǒng)采用側(cè)邊欄導(dǎo)航+堆疊窗口的設(shè)計模式:

def init_ui(self):
    self.central_widget = QWidget()
    self.setCentralWidget(self.central_widget)
    
    # 主布局:水平布局(側(cè)邊欄+內(nèi)容區(qū))
    self.main_layout = QHBoxLayout(self.central_widget)
    
    # 創(chuàng)建側(cè)邊欄
    self.create_sidebar()
    
    # 創(chuàng)建內(nèi)容區(qū)域(堆疊窗口)
    self.content_area = QStackedWidget()
    self.create_all_pages()
    
    # 將組件添加到主布局
    self.main_layout.addWidget(self.sidebar)
    self.main_layout.addWidget(self.content_area)

4. 題庫管理實現(xiàn)

題庫支持JSON和Excel兩種格式的導(dǎo)入導(dǎo)出:

def import_question_bank(self):
    filename, _ = QFileDialog.getOpenFileName(
        self, "導(dǎo)入題庫", "", "題庫文件 (*.json *.xlsx)"
    )
    
    if filename.endswith('.json'):
        with open(filename, 'r', encoding='utf-8') as f:
            bank_name = filename.split('/')[-1].replace('.json', '')
            self.question_banks[bank_name] = json.load(f)
    elif filename.endswith('.xlsx'):
        bank_name = filename.split('/')[-1].replace('.xlsx', '')
        self.question_banks[bank_name] = self.load_excel_bank(filename)

5. 隨機組卷算法

按題型比例隨機抽取題目:

def start_exam(self):
    # 計算各題型題目數(shù)量
    single_count = int(num_questions * single_ratio / 100)
    multi_count = int(num_questions * multi_ratio / 100)
    bool_count = num_questions - single_count - multi_count
    
    # 隨機選擇題目
    selected_questions = []
    if single_count > 0:
        selected_questions.extend(random.sample(single_questions, single_count))
    if multi_count > 0:
        selected_questions.extend(random.sample(multi_questions, multi_count))
    if bool_count > 0:
        selected_questions.extend(random.sample(bool_questions, bool_count))
    
    # 隨機排序
    random.shuffle(selected_questions)

6. 刷題模式實現(xiàn)

支持三種刷題順序:

def start_practice(self):
    self.practice_order = self.order_combo.currentText()
    self.current_questions = questions.copy()
    
    if self.practice_order == "逆序":
        self.current_questions.reverse()
    elif self.practice_order == "隨機":
        random.shuffle(self.current_questions)

7. 錯題集管理

自動記錄錯題并提供復(fù)習(xí)功能:

def submit_exam(self):
    if not is_correct:
        # 添加到錯題集
        if self.current_question_bank not in self.wrong_questions:
            self.wrong_questions[self.current_question_bank] = []
        
        wrong_question = question.copy()
        wrong_question['user_answer'] = user_answer
        self.wrong_questions[self.current_question_bank].append(wrong_question)

8. 學(xué)習(xí)統(tǒng)計可視化

使用Matplotlib生成錯題分析圖表:

def show_stats(self):
    # 創(chuàng)建圖表
    fig = self.stats_canvas.figure
    fig.clear()
    
    # 錯題題型分布餅圖
    ax1 = fig.add_subplot(121)
    ax1.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
    
    # 各題庫錯題數(shù)量柱狀圖
    ax2 = fig.add_subplot(122)
    ax2.bar(bank_names, wrong_counts)
    
    self.stats_canvas.draw()

關(guān)鍵代碼解析

1. 題目顯示邏輯

def show_question(self):
    # 獲取當(dāng)前題目
    current_question = self.current_questions[self.current_index]
    
    # 顯示題目信息
    self.question_text.setText(current_question['question'])
    
    # 根據(jù)題型創(chuàng)建相應(yīng)選項
    if current_question['type'] == "單選題":
        for i, option in enumerate(current_question['options']):
            rb = QRadioButton(f"{chr(65+i)}. {option}")
            self.options_layout.addWidget(rb)

2. 答案檢查邏輯 

def check_answer(self, user_answer, correct_answer, q_type):
    if q_type == "多選題":
        # 對多選題答案進行排序比較
        user_sorted = "".join(sorted(user_answer.upper()))
        correct_sorted = "".join(sorted(correct_answer.replace(", ", "").upper()))
        return user_sorted == correct_sorted
    else:
        return str(user_answer).upper() == str(correct_answer).upper()

3. 樣式表設(shè)計

def get_stylesheet(self):
    return """
        QMainWindow { background-color: #f5f7fa; }
        QLabel { color: #333; }
        QPushButton {
            background-color: #4e73df;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
        }
        QPushButton:hover { background-color: #3a5fcd; }
    """

源碼下載

import sys
import json
import openpyxl
import random
from PyQt5 import QtGui
from PyQt5.QtGui import QIntValidator
from datetime import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLabel, QPushButton, QListWidget, QStackedWidget, QMessageBox,
                             QLineEdit, QTextEdit, QRadioButton, QCheckBox, QComboBox,
                             QGroupBox, QDialog, QFormLayout, QInputDialog, QFileDialog,
                             QTreeWidget, QTreeWidgetItem, QAbstractItemView, QTabWidget)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont, QIcon, QPixmap
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas

class BrainyQuiz(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("白澤題庫系統(tǒng)")
        self.setGeometry(100, 100, 1000, 700)
        self.setStyleSheet(self.get_stylesheet())
        
        # 初始化數(shù)據(jù)
        self.current_question_bank = None
        self.question_banks = {}
        self.current_questions = []
        self.current_index = 0
        self.user_answers = {}
        self.wrong_questions = {}
        self.exam_mode = False
        self.practice_mode = False
        self.score = 0
        self.total_score = 0
        self.practice_order = "順序"
        
        # 創(chuàng)建主界面
        self.init_ui()
        
        # 加載題庫列表
        self.load_question_bank_list()
    
    def get_stylesheet(self):
        """返回應(yīng)用程序樣式表"""
        return """
            QMainWindow {
                background-color: #f5f7fa;
            }
            QLabel {
                color: #333;
            }
            QPushButton {
                background-color: #4e73df;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                min-width: 100px;
            }
            QPushButton:hover {
                background-color: #3a5fcd;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
            QListWidget, QTreeWidget, QTextEdit, QLineEdit, QComboBox {
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 5px;
                background-color: white;
            }
            QGroupBox {
                border: 1px solid #ddd;
                border-radius: 4px;
                margin-top: 10px;
                padding-top: 15px;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
            }
            QRadioButton, QCheckBox {
                spacing: 5px;
            }
        """
    
    def init_ui(self):
        """初始化UI界面"""
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        
        self.main_layout = QHBoxLayout(self.central_widget)
        
        # 左側(cè)導(dǎo)航欄
        self.create_sidebar()
        
        # 右側(cè)內(nèi)容區(qū)域
        self.content_area = QStackedWidget()
        
        # 添加各個頁面
        self.create_all_pages()
        
        # 將側(cè)邊欄和內(nèi)容區(qū)域添加到主布局
        self.main_layout.addWidget(self.sidebar)
        self.main_layout.addWidget(self.content_area)
    
    def create_sidebar(self):
        """創(chuàng)建左側(cè)導(dǎo)航欄"""
        self.sidebar = QWidget()
        self.sidebar.setFixedWidth(200)
        self.sidebar.setStyleSheet("background-color: #2c3e50;")
        self.sidebar_layout = QVBoxLayout(self.sidebar)
        
        # 應(yīng)用標(biāo)題
        title = QLabel("?? 題庫考試系統(tǒng)")
        title.setStyleSheet("""
            QLabel {
                color: white;
                font-size: 18px;
                font-weight: bold;
                padding: 20px 10px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        self.sidebar_layout.addWidget(title)
        
        # 導(dǎo)航按鈕
        self.create_navigation_buttons()
        
        # 添加按鈕到側(cè)邊欄
        self.sidebar_layout.addStretch()
        self.sidebar_layout.addWidget(self.btn_exit)
    
    def create_navigation_buttons(self):
        """創(chuàng)建導(dǎo)航按鈕"""
        self.btn_bank = QPushButton("?? 題庫管理")
        self.btn_bank.setStyleSheet("text-align: left; padding-left: 20px;")
        self.btn_bank.clicked.connect(self.show_bank_manager)
        
        self.btn_exam = QPushButton("?? 隨機組卷")
        self.btn_exam.setStyleSheet("text-align: left; padding-left: 20px;")
        self.btn_exam.clicked.connect(self.show_exam_setup)
        
        self.btn_practice = QPushButton("?? 題海刷題")
        self.btn_practice.setStyleSheet("text-align: left; padding-left: 20px;")
        self.btn_practice.clicked.connect(self.show_practice_setup)
        
        self.btn_wrong = QPushButton("? 錯題集")
        self.btn_wrong.setStyleSheet("text-align: left; padding-left: 20px;")
        self.btn_wrong.clicked.connect(self.show_wrong_questions)
        
        self.btn_stats = QPushButton("?? 學(xué)習(xí)統(tǒng)計")
        self.btn_stats.setStyleSheet("text-align: left; padding-left: 20px;")
        self.btn_stats.clicked.connect(self.show_stats)
        
        self.btn_exit = QPushButton("?? 退出")
        self.btn_exit.setStyleSheet("text-align: left; padding-left: 20px;")
        self.btn_exit.clicked.connect(self.close)
        
        # 添加按鈕到側(cè)邊欄
        buttons = [self.btn_bank, self.btn_exam, self.btn_practice,
                  self.btn_wrong, self.btn_stats]
        for btn in buttons:
            self.sidebar_layout.addWidget(btn)
    
    def create_all_pages(self):
        """創(chuàng)建所有內(nèi)容頁面"""
        self.main_page = self.create_main_page()
        self.bank_manager_page = self.create_bank_manager_page()
        self.bank_editor_page = self.create_bank_editor_page()
        self.exam_setup_page = self.create_exam_setup_page()
        self.exam_page = self.create_exam_page()
        self.result_page = self.create_result_page()
        self.wrong_questions_page = self.create_wrong_questions_page()
        self.stats_page = self.create_stats_page()
        self.practice_setup_page = self.create_practice_setup_page()
        self.practice_page = self.create_practice_page()
        
        # 添加到堆棧窗口
        pages = [
            self.main_page, self.bank_manager_page, self.bank_editor_page,
            self.exam_setup_page, self.exam_page, self.result_page,
            self.wrong_questions_page, self.stats_page,
            self.practice_setup_page, self.practice_page
        ]
        for page in pages:
            self.content_area.addWidget(page)
    
    def create_main_page(self):
        """創(chuàng)建主頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("白澤為引,點亮你的題海修行之路")
        title.setStyleSheet("""
            QLabel {
                font-size: 24px;
                font-weight: bold;
                color: #2c3e50;
                margin-bottom: 30px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        

        
        
        # 應(yīng)用描述
        desc = QLabel("一款功能強大的刷題軟件,支持多種題型和智能學(xué)習(xí)統(tǒng)計")
        desc.setStyleSheet("font-size: 16px; color: #7f8c8d;")
        desc.setAlignment(Qt.AlignCenter)
        layout.addWidget(desc)
        
        # 插入空行
        spacer = QLabel("")
        spacer.setFixedHeight(15)  # 設(shè)置高度,10~20px 之間都可以
        layout.addWidget(spacer)
        
        # 圖標(biāo)(如果沒有資源文件則不顯示)
        icon = QLabel()
        try:
            pixmap = QPixmap("icon.ico")
            if not pixmap.isNull():
                pixmap = pixmap.scaled(100, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation)
                icon.setPixmap(pixmap)
                icon.setAlignment(Qt.AlignCenter)
                layout.addWidget(icon)
        except:
            pass
        
        layout.addStretch()
        return page
    
    def create_bank_manager_page(self):
        """創(chuàng)建題庫管理頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("?? 題庫管理")
        title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # 題庫列表
        self.bank_list = QListWidget()
        self.bank_list.setStyleSheet("font-size: 14px;")
        layout.addWidget(self.bank_list)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_new_bank = QPushButton("? 新建題庫")
        self.btn_new_bank.clicked.connect(self.create_new_bank)
        
        self.btn_import_bank = QPushButton("?? 導(dǎo)入題庫")
        self.btn_import_bank.clicked.connect(self.import_question_bank)
        
        self.btn_edit_bank = QPushButton("?? 編輯題庫")
        self.btn_edit_bank.clicked.connect(self.edit_selected_bank)
        
        self.btn_export_bank = QPushButton("?? 導(dǎo)出題庫")
        self.btn_export_bank.clicked.connect(self.export_selected_bank)
        
        self.btn_delete_bank = QPushButton("??? 刪除題庫")
        self.btn_delete_bank.clicked.connect(self.delete_selected_bank)
        
        buttons = [self.btn_new_bank, self.btn_import_bank, self.btn_edit_bank,
                  self.btn_export_bank, self.btn_delete_bank]
        for btn in buttons:
            btn_layout.addWidget(btn)
        
        layout.addLayout(btn_layout)
        
        # 返回按鈕
        self.btn_back = QPushButton("?? 返回")
        self.btn_back.clicked.connect(self.show_main_page)
        layout.addWidget(self.btn_back, alignment=Qt.AlignRight)
        
        return page
    
    def create_bank_editor_page(self):
        """創(chuàng)建題庫編輯器頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        self.bank_editor_title = QLabel()
        self.bank_editor_title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        self.bank_editor_title.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.bank_editor_title)
        
        # 題目列表
        self.question_tree = QTreeWidget()
        self.question_tree.setHeaderLabels(["題型", "題目", "選項", "答案", "分值"])
        self.question_tree.setColumnWidth(0, 80)
        self.question_tree.setColumnWidth(1, 300)
        self.question_tree.setColumnWidth(2, 200)
        self.question_tree.setColumnWidth(3, 100)
        self.question_tree.setColumnWidth(4, 60)
        self.question_tree.setSelectionMode(QAbstractItemView.SingleSelection)
        layout.addWidget(self.question_tree)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_add_question = QPushButton("? 添加題目")
        self.btn_add_question.clicked.connect(self.add_question_dialog)
        
        self.btn_edit_question = QPushButton("?? 編輯題目")
        self.btn_edit_question.clicked.connect(self.edit_question_dialog)
        
        self.btn_delete_question = QPushButton("??? 刪除題目")
        self.btn_delete_question.clicked.connect(self.delete_question)
        
        buttons = [self.btn_add_question, self.btn_edit_question, self.btn_delete_question]
        for btn in buttons:
            btn_layout.addWidget(btn)
        
        layout.addLayout(btn_layout)
        
        # 保存和返回按鈕
        bottom_btn_layout = QHBoxLayout()
        
        self.btn_save_bank = QPushButton("?? 保存題庫")
        self.btn_save_bank.clicked.connect(self.save_question_bank)
        
        self.btn_back_editor = QPushButton("?? 返回")
        self.btn_back_editor.clicked.connect(self.show_bank_manager)
        
        bottom_btn_layout.addWidget(self.btn_save_bank)
        bottom_btn_layout.addStretch()
        bottom_btn_layout.addWidget(self.btn_back_editor)
        
        layout.addLayout(bottom_btn_layout)
        
        return page
    
    def create_exam_setup_page(self):
        """創(chuàng)建組卷設(shè)置頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        self.exam_setup_title = QLabel("?? 隨機組卷設(shè)置")
        self.exam_setup_title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        self.exam_setup_title.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.exam_setup_title)
        
        # 設(shè)置表單
        form_layout = QFormLayout()
        
        # 題庫選擇
        self.bank_combo = QComboBox()
        form_layout.addRow("選擇題庫:", self.bank_combo)
        
        # 組卷設(shè)置
        self.exam_settings_group = QGroupBox("組卷設(shè)置")
        exam_layout = QVBoxLayout(self.exam_settings_group)
        
        # 題目數(shù)量
        self.num_questions = QLineEdit("10")
        self.num_questions.setValidator(QtGui.QIntValidator(1, 100))
        exam_layout.addWidget(QLabel("題目數(shù)量:"))
        exam_layout.addWidget(self.num_questions)
        
        # 題型分布
        type_layout = QHBoxLayout()
        
        self.single_ratio = QLineEdit("40")
        self.single_ratio.setValidator(QtGui.QIntValidator(0, 100))
        type_layout.addWidget(QLabel("單選:"))
        type_layout.addWidget(self.single_ratio)
        type_layout.addWidget(QLabel("%"))
        
        self.multi_ratio = QLineEdit("30")
        self.multi_ratio.setValidator(QtGui.QIntValidator(0, 100))
        type_layout.addWidget(QLabel("多選:"))
        type_layout.addWidget(self.multi_ratio)
        type_layout.addWidget(QLabel("%"))
        
        self.bool_ratio = QLineEdit("30")
        self.bool_ratio.setValidator(QtGui.QIntValidator(0, 100))
        type_layout.addWidget(QLabel("判斷:"))
        type_layout.addWidget(self.bool_ratio)
        type_layout.addWidget(QLabel("%"))
        
        exam_layout.addWidget(QLabel("題型分布:"))
        exam_layout.addLayout(type_layout)
        
        # 時間限制
        self.time_limit_label = QLabel("時間限制(分鐘):")
        self.time_limit = QLineEdit("30")
        self.time_limit.setValidator(QtGui.QIntValidator(1, 300))
        exam_layout.addWidget(self.time_limit_label)
        exam_layout.addWidget(self.time_limit)
        
        form_layout.addRow(self.exam_settings_group)
        
        layout.addLayout(form_layout)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_start_exam = QPushButton("?? 開始考試")
        self.btn_start_exam.clicked.connect(self.start_exam)
        
        self.btn_back_setup = QPushButton("?? 返回")
        self.btn_back_setup.clicked.connect(self.show_main_page)
        
        btn_layout.addWidget(self.btn_start_exam)
        btn_layout.addWidget(self.btn_back_setup)
        
        layout.addLayout(btn_layout)
        
        return page
    
    def create_exam_page(self):
        """創(chuàng)建考試頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 計時器
        self.timer_layout = QHBoxLayout()
        self.timer_label = QLabel()
        self.timer_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #e74c3c;")
        self.timer_layout.addStretch()
        self.timer_layout.addWidget(self.timer_label)
        layout.addLayout(self.timer_layout)
        
        # 進度顯示
        self.progress_label = QLabel()
        self.progress_label.setStyleSheet("font-size: 16px; font-weight: bold;")
        layout.addWidget(self.progress_label, alignment=Qt.AlignLeft)
        
        # 題目內(nèi)容
        self.question_group = QGroupBox()
        self.question_group.setStyleSheet("QGroupBox { font-size: 14px; }")
        question_layout = QVBoxLayout(self.question_group)
        
        self.question_type_label = QLabel()
        self.question_type_label.setStyleSheet("font-weight: bold; color: #3498db;")
        
        self.question_text = QLabel()
        self.question_text.setWordWrap(True)
        self.question_text.setStyleSheet("font-size: 15px;")
        
        self.options_layout = QVBoxLayout()
        
        question_layout.addWidget(self.question_type_label)
        question_layout.addWidget(self.question_text)
        question_layout.addLayout(self.options_layout)
        question_layout.addStretch()
        
        layout.addWidget(self.question_group)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_prev = QPushButton("?? 上一題")
        self.btn_prev.clicked.connect(self.prev_question)
        
        self.btn_next = QPushButton("?? 下一題")
        self.btn_next.clicked.connect(self.next_question)
        
        self.btn_submit = QPushButton("?? 交卷")
        self.btn_submit.clicked.connect(self.submit_exam)
        
        self.btn_back_exam = QPushButton("?? 返回")
        self.btn_back_exam.clicked.connect(self.confirm_exit_exam)
        
        buttons = [self.btn_prev, self.btn_next, self.btn_submit, self.btn_back_exam]
        for btn in buttons:
            btn_layout.addWidget(btn)
        
        layout.addLayout(btn_layout)
        
        return page
    
    def create_result_page(self):
        """創(chuàng)建測驗結(jié)果頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("?? 測驗結(jié)果")
        title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # 結(jié)果統(tǒng)計
        self.stats_group = QGroupBox("測驗統(tǒng)計")
        stats_layout = QFormLayout(self.stats_group)
        
        self.total_score_label = QLabel()
        self.accuracy_label = QLabel()
        
        stats_layout.addRow("總分:", self.total_score_label)
        stats_layout.addRow("正確率:", self.accuracy_label)
        
        layout.addWidget(self.stats_group)
        
        # 錯題按鈕
        self.btn_wrong_answers = QPushButton("查看錯題")
        self.btn_wrong_answers.setStyleSheet("background-color: #e74c3c;")
        self.btn_wrong_answers.clicked.connect(self.show_wrong_answers)
        layout.addWidget(self.btn_wrong_answers, alignment=Qt.AlignCenter)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_retry = QPushButton("?? 重新測驗")
        self.btn_retry.clicked.connect(self.retry_exam)
        
        self.btn_back_result = QPushButton("?? 返回主頁")
        self.btn_back_result.clicked.connect(self.show_main_page)
        
        btn_layout.addWidget(self.btn_retry)
        btn_layout.addWidget(self.btn_back_result)
        
        layout.addLayout(btn_layout)
        
        return page
    
    def create_wrong_questions_page(self):
        """創(chuàng)建錯題集頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("? 錯題集")
        title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # 題庫選擇
        bank_layout = QHBoxLayout()
        
        bank_layout.addWidget(QLabel("選擇題庫:"))
        
        self.wrong_bank_combo = QComboBox()
        self.wrong_bank_combo.currentIndexChanged.connect(self.update_wrong_list)
        bank_layout.addWidget(self.wrong_bank_combo)
        
        layout.addLayout(bank_layout)
        
        # 錯題列表
        self.wrong_tree = QTreeWidget()
        self.wrong_tree.setHeaderLabels(["題型", "題目", "正確答案", "你的答案"])
        self.wrong_tree.setColumnWidth(0, 80)
        self.wrong_tree.setColumnWidth(1, 400)
        self.wrong_tree.setColumnWidth(2, 100)
        self.wrong_tree.setColumnWidth(3, 100)
        self.wrong_tree.setSelectionMode(QAbstractItemView.SingleSelection)
        layout.addWidget(self.wrong_tree)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_detail = QPushButton("?? 查看詳情")
        self.btn_detail.clicked.connect(self.show_wrong_detail)
        
        self.btn_delete_wrong = QPushButton("??? 刪除錯題")
        self.btn_delete_wrong.clicked.connect(self.delete_wrong_question)
        
        self.btn_back_wrong = QPushButton("?? 返回")
        self.btn_back_wrong.clicked.connect(self.back_from_wrong_page)
        
        buttons = [self.btn_detail, self.btn_delete_wrong, self.btn_back_wrong]
        for btn in buttons:
            btn_layout.addWidget(btn)
        
        layout.addLayout(btn_layout)
        
        return page
    
    def create_stats_page(self):
        """創(chuàng)建學(xué)習(xí)統(tǒng)計頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("?? 學(xué)習(xí)統(tǒng)計")
        title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # 圖表區(qū)域
        self.stats_canvas = FigureCanvas(plt.Figure(figsize=(10, 5)))
        layout.addWidget(self.stats_canvas)
        
        # 返回按鈕
        self.btn_back_stats = QPushButton("?? 返回")
        self.btn_back_stats.clicked.connect(self.show_main_page)
        layout.addWidget(self.btn_back_stats, alignment=Qt.AlignRight)
        
        return page
    
    def create_practice_setup_page(self):
        """創(chuàng)建刷題設(shè)置頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("?? 題海刷題模式")
        title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # 題庫選擇
        form_layout = QFormLayout()
        self.practice_bank_combo = QComboBox()
        form_layout.addRow("選擇題庫:", self.practice_bank_combo)
        
        # 刷題順序選擇
        self.order_combo = QComboBox()
        self.order_combo.addItems(["順序", "逆序", "隨機"])
        form_layout.addRow("刷題順序:", self.order_combo)
        
        layout.addLayout(form_layout)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_start_practice = QPushButton("開始刷題")
        self.btn_start_practice.clicked.connect(self.start_practice)
        
        self.btn_back_practice = QPushButton("返回")
        self.btn_back_practice.clicked.connect(self.show_main_page)
        
        btn_layout.addWidget(self.btn_start_practice)
        btn_layout.addWidget(self.btn_back_practice)
        
        layout.addLayout(btn_layout)
        
        return page
    
    def create_practice_page(self):
        """創(chuàng)建刷題頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 進度顯示
        self.practice_progress_label = QLabel()
        self.practice_progress_label.setStyleSheet("font-size: 16px; font-weight: bold;")
        layout.addWidget(self.practice_progress_label, alignment=Qt.AlignLeft)
        
        # 題目內(nèi)容
        self.practice_question_group = QGroupBox()
        self.practice_question_group.setStyleSheet("QGroupBox { font-size: 14px; }")
        question_layout = QVBoxLayout(self.practice_question_group)
        
        self.practice_question_type_label = QLabel()
        self.practice_question_type_label.setStyleSheet("font-weight: bold; color: #3498db;")
        
        self.practice_question_text = QLabel()
        self.practice_question_text.setWordWrap(True)
        self.practice_question_text.setStyleSheet("font-size: 15px;")
        
        self.practice_options_layout = QVBoxLayout()
        
        question_layout.addWidget(self.practice_question_type_label)
        question_layout.addWidget(self.practice_question_text)
        question_layout.addLayout(self.practice_options_layout)
        question_layout.addStretch()
        
        layout.addWidget(self.practice_question_group)
        
        # 答案反饋
        self.answer_feedback = QLabel()
        self.answer_feedback.setStyleSheet("font-size: 14px; font-weight: bold;")
        self.answer_feedback.setWordWrap(True)
        layout.addWidget(self.answer_feedback)
        
        # 按鈕區(qū)域
        btn_layout = QHBoxLayout()
        
        self.btn_prev_practice = QPushButton("?? 上一題")
        self.btn_prev_practice.clicked.connect(self.prev_practice_question)
        
        self.btn_next_practice = QPushButton("?? 下一題")
        self.btn_next_practice.clicked.connect(self.next_practice_question)
        
        self.btn_submit_practice = QPushButton("提交答案")
        self.btn_submit_practice.clicked.connect(self.submit_practice_answer)
        
        self.btn_back_practice_page = QPushButton("?? 返回")
        self.btn_back_practice_page.clicked.connect(self.confirm_exit_practice)
        
        buttons = [self.btn_prev_practice, self.btn_next_practice, 
                  self.btn_submit_practice, self.btn_back_practice_page]
        for btn in buttons:
            btn_layout.addWidget(btn)
        
        layout.addLayout(btn_layout)
        
        return page
    
    # 頁面導(dǎo)航方法
    def show_main_page(self):
        """顯示主頁面"""
        self.content_area.setCurrentWidget(self.main_page)
    
    def show_bank_manager(self):
        """顯示題庫管理頁面"""
        self.bank_list.clear()
        for bank_name in self.question_banks.keys():
            self.bank_list.addItem(bank_name)
        self.content_area.setCurrentWidget(self.bank_manager_page)
    
    def show_bank_editor(self, bank_name):
        """顯示題庫編輯器頁面"""
        self.bank_editor_title.setText(f"?? 編輯題庫: {bank_name}")
        self.current_question_bank = bank_name
        self.question_tree.clear()
        
        for question in self.question_banks[bank_name]:
            q_type = question['type']
            q_text = question['question']
            options = "\n".join(question['options']) if 'options' in question else ""
            answer = ", ".join(question['answer']) if isinstance(question['answer'], list) else question['answer']
            score = question.get('score', 1)
            
            item = QTreeWidgetItem(self.question_tree)
            item.setText(0, q_type)
            item.setText(1, q_text)
            item.setText(2, options)
            item.setText(3, answer)
            item.setText(4, str(score))
        
        self.content_area.setCurrentWidget(self.bank_editor_page)
    
    def show_exam_setup(self):
        """顯示組卷設(shè)置頁面"""
        self.bank_combo.clear()
        self.bank_combo.addItems(self.question_banks.keys())
        
        if self.current_question_bank and self.current_question_bank in self.question_banks:
            index = self.bank_combo.findText(self.current_question_bank)
            if index >= 0:
                self.bank_combo.setCurrentIndex(index)
        
        self.content_area.setCurrentWidget(self.exam_setup_page)
    
    def show_practice_setup(self):
        """顯示刷題設(shè)置頁面"""
        self.practice_bank_combo.clear()
        self.practice_bank_combo.addItems(self.question_banks.keys())
        self.content_area.setCurrentWidget(self.practice_setup_page)
    
    def show_question(self):
        """顯示當(dāng)前題目"""
        if not self.current_questions:
            QMessageBox.warning(self, "錯誤", "沒有可用的題目!")
            return
        
        self.content_area.setCurrentWidget(self.exam_page)
        
        # 顯示計時器
        self.timer_layout.parentWidget().show()
        self.update_exam_timer()
        
        # 更新進度
        self.progress_label.setText(f"題目 {self.current_index + 1}/{len(self.current_questions)}")
        
        # 獲取當(dāng)前題目
        current_question = self.current_questions[self.current_index]
        q_type = current_question['type']
        q_text = current_question['question']
        options = current_question.get('options', [])
        q_score = current_question.get('score', 1)
        
        # 顯示題目信息
        self.question_type_label.setText(f"[{q_type}] (分值: {q_score})")
        self.question_text.setText(q_text)
        
        # 清除之前的選項
        while self.options_layout.count():
            child = self.options_layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()
        
        # 用戶答案變量
        if q_type == "單選題":
            self.user_answer_rbs = []
            
            for i, option in enumerate(options):
                rb = QRadioButton(f"{chr(65+i)}. {option}")
                if str(self.current_index) in self.user_answers:
                    if self.user_answers[str(self.current_index)] == chr(65+i):
                        rb.setChecked(True)
                self.user_answer_rbs.append(rb)
                self.options_layout.addWidget(rb)
        
        elif q_type == "多選題":
            self.user_answer_cbs = []
            
            for i, option in enumerate(options):
                cb = QCheckBox(f"{chr(65+i)}. {option}")
                if str(self.current_index) in self.user_answers:
                    if chr(65+i) in self.user_answers[str(self.current_index)]:
                        cb.setChecked(True)
                self.user_answer_cbs.append(cb)
                self.options_layout.addWidget(cb)
        
        elif q_type == "判斷題":
            self.user_answer_rbs = []
            
            rb_true = QRadioButton("正確")
            rb_false = QRadioButton("錯誤")
            
            if str(self.current_index) in self.user_answers:
                if self.user_answers[str(self.current_index)] == "正確":
                    rb_true.setChecked(True)
                else:
                    rb_false.setChecked(True)
            
            self.user_answer_rbs.append(rb_true)
            self.user_answer_rbs.append(rb_false)
            
            self.options_layout.addWidget(rb_true)
            self.options_layout.addWidget(rb_false)
        
        # 更新按鈕狀態(tài)
        self.btn_prev.setEnabled(self.current_index > 0)
        
        if self.current_index < len(self.current_questions) - 1:
            self.btn_next.show()
            self.btn_submit.hide()
        else:
            self.btn_next.hide()
            self.btn_submit.show()
    
    def show_practice_question(self):
        """顯示刷題題目"""
        if not self.current_questions:
            QMessageBox.warning(self, "錯誤", "沒有可用的題目!")
            return
        
        self.content_area.setCurrentWidget(self.practice_page)
        
        # 更新進度
        self.practice_progress_label.setText(f"題目 {self.current_index + 1}/{len(self.current_questions)}")
        self.answer_feedback.clear()
        
        # 獲取當(dāng)前題目
        current_question = self.current_questions[self.current_index]
        q_type = current_question['type']
        q_text = current_question['question']
        options = current_question.get('options', [])
        
        # 顯示題目信息
        self.practice_question_type_label.setText(f"[{q_type}]")
        self.practice_question_text.setText(q_text)
        
        # 清除之前的選項
        while self.practice_options_layout.count():
            child = self.practice_options_layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()
        
        # 用戶答案變量
        if q_type == "單選題":
            self.user_answer_rbs = []
            
            for i, option in enumerate(options):
                rb = QRadioButton(f"{chr(65+i)}. {option}")
                if str(self.current_index) in self.user_answers:
                    if self.user_answers[str(self.current_index)] == chr(65+i):
                        rb.setChecked(True)
                self.user_answer_rbs.append(rb)
                self.practice_options_layout.addWidget(rb)
        
        elif q_type == "多選題":
            self.user_answer_cbs = []
            
            for i, option in enumerate(options):
                cb = QCheckBox(f"{chr(65+i)}. {option}")
                if str(self.current_index) in self.user_answers:
                    if chr(65+i) in self.user_answers[str(self.current_index)]:
                        cb.setChecked(True)
                self.user_answer_cbs.append(cb)
                self.practice_options_layout.addWidget(cb)
        
        elif q_type == "判斷題":
            self.user_answer_rbs = []
            
            rb_true = QRadioButton("正確")
            rb_false = QRadioButton("錯誤")
            
            if str(self.current_index) in self.user_answers:
                if self.user_answers[str(self.current_index)] == "正確":
                    rb_true.setChecked(True)
                else:
                    rb_false.setChecked(True)
            
            self.user_answer_rbs.append(rb_true)
            self.user_answer_rbs.append(rb_false)
            
            self.practice_options_layout.addWidget(rb_true)
            self.practice_options_layout.addWidget(rb_false)
        
        # 更新按鈕狀態(tài)
        self.btn_prev_practice.setEnabled(self.current_index > 0)
        self.btn_next_practice.setEnabled(self.current_index < len(self.current_questions) - 1)
        self.btn_submit_practice.setEnabled(True)
    
    def show_exam_result(self, correct_count):
        """顯示測驗結(jié)果"""
        total_questions = len(self.current_questions)
        accuracy = (correct_count / total_questions) * 100 if total_questions > 0 else 0
        
        self.total_score_label.setText(f"{self.score}/{self.total_score}")
        self.accuracy_label.setText(f"{accuracy:.1f}% ({correct_count}/{total_questions})")
        
        # 如果沒有錯題,隱藏查看錯題按鈕
        self.btn_wrong_answers.setVisible(correct_count < total_questions)
        
        self.content_area.setCurrentWidget(self.result_page)
    
    def show_wrong_questions(self):
        """顯示錯題集頁面"""
        if not self.wrong_questions:
            QMessageBox.information(self, "提示", "錯題集為空!")
            return
        
        self.wrong_bank_combo.clear()
        self.wrong_bank_combo.addItems(self.wrong_questions.keys())
        self.update_wrong_list()
        
        self.content_area.setCurrentWidget(self.wrong_questions_page)
    
    def show_stats(self):
        """顯示學(xué)習(xí)統(tǒng)計頁面"""
        if not self.wrong_questions:
            QMessageBox.information(self, "提示", "暫無統(tǒng)計數(shù)據(jù)!")
            return
        
        # 創(chuàng)建圖表
        fig = self.stats_canvas.figure
        fig.clear()
        
        ax1 = fig.add_subplot(121)
        ax2 = fig.add_subplot(122)
        
        # 設(shè)置中文字體
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 用來正常顯示中文標(biāo)簽
        plt.rcParams['axes.unicode_minus'] = False  # 用來正常顯示負號
        
        # 錯題題型分布
        type_counts = {'單選題': 0, '多選題': 0, '判斷題': 0}
        for bank_name, questions in self.wrong_questions.items():
            for question in questions:
                q_type = question['type']
                type_counts[q_type] += 1
        
        labels = list(type_counts.keys())
        sizes = list(type_counts.values())
        
        ax1.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
        ax1.set_title('錯題題型分布')
        
        # 各題庫錯題數(shù)量
        bank_names = list(self.wrong_questions.keys())
        wrong_counts = [len(questions) for questions in self.wrong_questions.values()]
        
        ax2.bar(bank_names, wrong_counts)
        ax2.set_title('各題庫錯題數(shù)量')
        ax2.set_ylabel('數(shù)量')
        ax2.tick_params(axis='x', rotation=45)
        
        fig.tight_layout()
        self.stats_canvas.draw()
        
        self.content_area.setCurrentWidget(self.stats_page)
    
    # 題庫管理相關(guān)方法
    def import_question_bank(self):
        """導(dǎo)入題庫文件"""
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "導(dǎo)入題庫",
            "",
            "題庫文件 (*.json *.xlsx)"
        )
        
        if not filename:
            return
        
        try:
            if filename.endswith('.json'):
                with open(filename, 'r', encoding='utf-8') as f:
                    bank_name = filename.split('/')[-1].replace('.json', '')
                    self.question_banks[bank_name] = json.load(f)
            elif filename.endswith('.xlsx'):
                bank_name = filename.split('/')[-1].replace('.xlsx', '')
                self.question_banks[bank_name] = self.load_excel_bank(filename)
            
            QMessageBox.information(self, "成功", f"題庫 '{bank_name}' 導(dǎo)入成功!")
            self.show_bank_manager()
        except Exception as e:
            QMessageBox.warning(self, "錯誤", f"導(dǎo)入失敗: {str(e)}")
    
    def create_new_bank(self):
        """創(chuàng)建新題庫"""
        bank_name, ok = QInputDialog.getText(self, "新建題庫", "請輸入題庫名稱:")
        if ok and bank_name:
            if bank_name in self.question_banks:
                QMessageBox.warning(self, "錯誤", "題庫已存在!")
            else:
                self.question_banks[bank_name] = []
                self.bank_list.addItem(bank_name)
                QMessageBox.information(self, "成功", f"題庫 '{bank_name}' 創(chuàng)建成功!")
    
    def load_selected_bank(self):
        """加載選中的題庫"""
        selected_items = self.bank_list.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇一個題庫!")
            return
        
        bank_name = selected_items[0].text()
        self.current_question_bank = bank_name
        QMessageBox.information(self, "成功", f"題庫 '{bank_name}' 已加載!")
    
    def edit_selected_bank(self):
        """編輯選中的題庫"""
        selected_items = self.bank_list.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇一個題庫!")
            return
        
        bank_name = selected_items[0].text()
        self.show_bank_editor(bank_name)
    
    def export_selected_bank(self):
        """導(dǎo)出選中的題庫"""
        selected_items = self.bank_list.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇一個題庫!")
            return
        
        bank_name = selected_items[0].text()
        
        # 選擇導(dǎo)出格式
        formats = ["JSON (.json)", "Excel (.xlsx)"]
        format_choice, ok = QInputDialog.getItem(
            self, "選擇導(dǎo)出格式", "請選擇導(dǎo)出格式:", formats, 0, False
        )
        
        if ok:
            export_format = "json" if "JSON" in format_choice else "xlsx"
            self.save_question_bank(bank_name, export_format)
    
    def delete_selected_bank(self):
        """刪除選中的題庫"""
        selected_items = self.bank_list.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇一個題庫!")
            return
        
        bank_name = selected_items[0].text()
        
        reply = QMessageBox.question(
            self, 
            "確認", 
            f"確定要刪除題庫 '{bank_name}' 嗎?", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 從內(nèi)存中刪除
            del self.question_banks[bank_name]
            
            # 從列表框中刪除
            self.bank_list.takeItem(self.bank_list.row(selected_items[0]))
            
            QMessageBox.information(self, "成功", f"題庫 '{bank_name}' 已刪除!")
    
    def add_question_dialog(self):
        """添加題目對話框"""
        if not self.current_question_bank:
            return
        
        dialog = QDialog(self)
        dialog.setWindowTitle("添加題目")
        dialog.setModal(True)
        dialog.resize(600, 500)
        
        layout = QVBoxLayout(dialog)
        
        # 題型選擇
        type_layout = QHBoxLayout()
        type_layout.addWidget(QLabel("題型:"))
        
        q_type_combo = QComboBox()
        q_type_combo.addItems(["單選題", "多選題", "判斷題"])
        type_layout.addWidget(q_type_combo)
        
        layout.addLayout(type_layout)
        
        # 題目內(nèi)容
        layout.addWidget(QLabel("題目:"))
        
        question_edit = QTextEdit()
        layout.addWidget(question_edit)
        
        # 選項框架
        options_group = QGroupBox("選項")
        options_layout = QVBoxLayout(options_group)
        
        self.option_edits = []
        for i in range(4):
            option_layout = QHBoxLayout()
            option_layout.addWidget(QLabel(f"選項 {chr(65+i)}:"))
            
            option_edit = QLineEdit()
            self.option_edits.append(option_edit)
            option_layout.addWidget(option_edit)
            
            options_layout.addLayout(option_layout)
        
        layout.addWidget(options_group)
        
        # 答案框架
        answer_group = QGroupBox("答案")
        answer_layout = QVBoxLayout(answer_group)
        
        # 單選題答案
        self.single_answer_combo = QComboBox()
        self.single_answer_combo.addItems(["A", "B", "C", "D"])
        
        # 多選題答案
        self.multi_answer_checks = []
        multi_layout = QHBoxLayout()
        for i in range(4):
            cb = QCheckBox(chr(65+i))
            self.multi_answer_checks.append(cb)
            multi_layout.addWidget(cb)
        
        # 判斷題答案
        self.bool_answer_combo = QComboBox()
        self.bool_answer_combo.addItems(["正確", "錯誤"])
        
        # 默認顯示單選題答案
        answer_layout.addWidget(self.single_answer_combo)
        
        # 分值
        score_layout = QHBoxLayout()
        score_layout.addWidget(QLabel("分值:"))
        
        score_edit = QLineEdit("1")
        score_edit.setValidator(QtGui.QIntValidator(1, 10))
        score_layout.addWidget(score_edit)
        
        layout.addWidget(answer_group)
        layout.addLayout(score_layout)
        
        # 按鈕
        btn_layout = QHBoxLayout()
        
        add_btn = QPushButton("添加")
        add_btn.clicked.connect(lambda: self.add_question(
            dialog, q_type_combo, question_edit, score_edit
        ))
        
        cancel_btn = QPushButton("取消")
        cancel_btn.clicked.connect(dialog.reject)
        
        btn_layout.addWidget(add_btn)
        btn_layout.addWidget(cancel_btn)
        
        layout.addLayout(btn_layout)
        
        # 題型變化事件
        def on_type_change(index):
            # 隱藏所有答案控件
            self.single_answer_combo.hide()
            for cb in self.multi_answer_checks:
                cb.hide()
            self.bool_answer_combo.hide()
            
            selected_type = q_type_combo.currentText()
            
            if selected_type == "單選題":
                self.single_answer_combo.show()
            elif selected_type == "多選題":
                for i, cb in enumerate(self.multi_answer_checks):
                    cb.show()
                    if i >= 4:
                        cb.hide()
            elif selected_type == "判斷題":
                self.bool_answer_combo.show()
                
            # 顯示/隱藏選項
            for i, edit in enumerate(self.option_edits):
                if selected_type == "判斷題" and i >= 2:
                    edit.hide()
                    edit.parent().hide()
                else:
                    edit.show()
                    edit.parent().show()
        
        q_type_combo.currentIndexChanged.connect(on_type_change)
        on_type_change(0)  # 初始化
        
        dialog.exec_()
    
    def add_question(self, dialog, q_type_combo, question_edit, score_edit):
        """添加題目到題庫"""
        q_type = q_type_combo.currentText()
        q_text = question_edit.toPlainText().strip()
        options = []
        
        if q_type == "判斷題":
            options = ["正確", "錯誤"]
        else:
            for edit in self.option_edits[:4 if q_type != "判斷題" else 2]:
                option = edit.text().strip()
                if option:
                    options.append(option)
        
        if not q_text:
            QMessageBox.warning(dialog, "錯誤", "題目不能為空!")
            return
        
        if not options:
            QMessageBox.warning(dialog, "錯誤", "至少需要一個選項!")
            return
        
        # 獲取答案
        if q_type == "單選題":
            answer = self.single_answer_combo.currentText()
        elif q_type == "多選題":
            answer = []
            for i, cb in enumerate(self.multi_answer_checks):
                if cb.isChecked():
                    answer.append(chr(65+i))
            answer = ", ".join(answer)
        elif q_type == "判斷題":
            answer = self.bool_answer_combo.currentText()
        
        if not answer:
            QMessageBox.warning(dialog, "錯誤", "請設(shè)置正確答案!")
            return
        
        try:
            score = int(score_edit.text())
        except ValueError:
            score = 1
        
        # 創(chuàng)建題目字典
        new_question = {
            'type': q_type,
            'question': q_text,
            'options': options,
            'answer': answer,
            'score': score
        }
        
        # 添加到題庫
        self.question_banks[self.current_question_bank].append(new_question)
        
        # 更新樹形視圖
        item = QTreeWidgetItem(self.question_tree)
        item.setText(0, q_type)
        item.setText(1, q_text)
        item.setText(2, "\n".join(options))
        item.setText(3, answer)
        item.setText(4, str(score))
        
        QMessageBox.information(dialog, "成功", "題目添加成功!")
        dialog.accept()
    
    def edit_question_dialog(self):
        """編輯題目對話框"""
        selected_items = self.question_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇要編輯的題目!")
            return
        
        item = selected_items[0]
        q_type = item.text(0)
        q_text = item.text(1)
        options = item.text(2).split("\n")
        answer = item.text(3)
        score = item.text(4)
        
        # 找到題庫中的原始題目
        index = self.question_tree.indexOfTopLevelItem(item)
        original_question = self.question_banks[self.current_question_bank][index]
        
        dialog = QDialog(self)
        dialog.setWindowTitle("編輯題目")
        dialog.setModal(True)
        dialog.resize(600, 500)
        
        layout = QVBoxLayout(dialog)
        
        # 題型選擇
        type_layout = QHBoxLayout()
        type_layout.addWidget(QLabel("題型:"))
        
        q_type_combo = QComboBox()
        q_type_combo.addItems(["單選題", "多選題", "判斷題"])
        q_type_combo.setCurrentText(q_type)
        type_layout.addWidget(q_type_combo)
        
        layout.addLayout(type_layout)
        
        # 題目內(nèi)容
        layout.addWidget(QLabel("題目:"))
        
        question_edit = QTextEdit()
        question_edit.setText(q_text)
        layout.addWidget(question_edit)
        
        # 選項框架
        options_group = QGroupBox("選項")
        options_layout = QVBoxLayout(options_group)
        
        self.option_edits = []
        for i in range(4):
            option_layout = QHBoxLayout()
            option_layout.addWidget(QLabel(f"選項 {chr(65+i)}:"))
            
            option_edit = QLineEdit()
            if i < len(options):
                option_edit.setText(options[i])
            self.option_edits.append(option_edit)
            option_layout.addWidget(option_edit)
            
            options_layout.addLayout(option_layout)
        
        layout.addWidget(options_group)
        
        # 答案框架
        answer_group = QGroupBox("答案")
        answer_layout = QVBoxLayout(answer_group)
        
        # 單選題答案
        self.single_answer_combo = QComboBox()
        self.single_answer_combo.addItems(["A", "B", "C", "D"])
        
        # 多選題答案
        self.multi_answer_checks = []
        multi_layout = QHBoxLayout()
        for i in range(4):
            cb = QCheckBox(chr(65+i))
            self.multi_answer_checks.append(cb)
            multi_layout.addWidget(cb)
        
        # 判斷題答案
        self.bool_answer_combo = QComboBox()
        self.bool_answer_combo.addItems(["正確", "錯誤"])
        
        # 設(shè)置當(dāng)前答案
        if q_type == "單選題":
            self.single_answer_combo.setCurrentText(answer)
            answer_layout.addWidget(self.single_answer_combo)
        elif q_type == "多選題":
            for char in answer.split(", "):
                if char:
                    idx = ord(char.upper()) - ord('A')
                    if 0 <= idx < 4:
                        self.multi_answer_checks[idx].setChecked(True)
            answer_layout.addLayout(multi_layout)
        elif q_type == "判斷題":
            self.bool_answer_combo.setCurrentText(answer)
            answer_layout.addWidget(self.bool_answer_combo)
        
        # 分值
        score_layout = QHBoxLayout()
        score_layout.addWidget(QLabel("分值:"))
        
        score_edit = QLineEdit(score)
        score_edit.setValidator(QtGui.QIntValidator(1, 10))
        score_layout.addWidget(score_edit)
        
        layout.addWidget(answer_group)
        layout.addLayout(score_layout)
        
        # 按鈕
        btn_layout = QHBoxLayout()
        
        save_btn = QPushButton("保存")
        save_btn.clicked.connect(lambda: self.save_question_edit(
            dialog, q_type_combo, question_edit, score_edit, index
        ))
        
        cancel_btn = QPushButton("取消")
        cancel_btn.clicked.connect(dialog.reject)
        
        btn_layout.addWidget(save_btn)
        btn_layout.addWidget(cancel_btn)
        
        layout.addLayout(btn_layout)
        
        # 題型變化事件
        def on_type_change(index):
            # 隱藏所有答案控件
            self.single_answer_combo.hide()
            for cb in self.multi_answer_checks:
                cb.hide()
            self.bool_answer_combo.hide()
            
            selected_type = q_type_combo.currentText()
            
            if selected_type == "單選題":
                self.single_answer_combo.show()
            elif selected_type == "多選題":
                for i, cb in enumerate(self.multi_answer_checks):
                    cb.show()
                    if i >= 4:
                        cb.hide()
            elif selected_type == "判斷題":
                self.bool_answer_combo.show()
                
            # 顯示/隱藏選項
            for i, edit in enumerate(self.option_edits):
                if selected_type == "判斷題" and i >= 2:
                    edit.hide()
                    edit.parent().hide()
                else:
                    edit.show()
                    edit.parent().show()
        
        q_type_combo.currentIndexChanged.connect(on_type_change)
        
        dialog.exec_()
    
    def save_question_edit(self, dialog, q_type_combo, question_edit, score_edit, index):
        """保存編輯后的題目"""
        q_type = q_type_combo.currentText()
        q_text = question_edit.toPlainText().strip()
        options = []
        
        if q_type == "判斷題":
            options = ["正確", "錯誤"]
        else:
            for edit in self.option_edits[:4 if q_type != "判斷題" else 2]:
                option = edit.text().strip()
                if option:
                    options.append(option)
        
        if not q_text:
            QMessageBox.warning(dialog, "錯誤", "題目不能為空!")
            return
        
        if not options:
            QMessageBox.warning(dialog, "錯誤", "至少需要一個選項!")
            return
        
        # 獲取答案
        if q_type == "單選題":
            answer = self.single_answer_combo.currentText()
        elif q_type == "多選題":
            answer = []
            for i, cb in enumerate(self.multi_answer_checks):
                if cb.isChecked():
                    answer.append(chr(65+i))
            answer = ", ".join(answer)
        elif q_type == "判斷題":
            answer = self.bool_answer_combo.currentText()
        
        if not answer:
            QMessageBox.warning(dialog, "錯誤", "請設(shè)置正確答案!")
            return
        
        try:
            score = int(score_edit.text())
        except ValueError:
            score = 1
        
        # 更新題目字典
        updated_question = {
            'type': q_type,
            'question': q_text,
            'options': options,
            'answer': answer,
            'score': score
        }
        
        # 更新題庫
        self.question_banks[self.current_question_bank][index] = updated_question
        
        # 更新樹形視圖
        item = self.question_tree.topLevelItem(index)
        item.setText(0, q_type)
        item.setText(1, q_text)
        item.setText(2, "\n".join(options))
        item.setText(3, answer)
        item.setText(4, str(score))
        
        QMessageBox.information(dialog, "成功", "題目更新成功!")
        dialog.accept()
    
    def delete_question(self):
        """刪除題目"""
        selected_items = self.question_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇要刪除的題目!")
            return
        
        reply = QMessageBox.question(
            self, 
            "確認", 
            "確定要刪除選中的題目嗎?", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.No:
            return
        
        # 從樹形視圖中刪除
        index = self.question_tree.indexOfTopLevelItem(selected_items[0])
        self.question_tree.takeTopLevelItem(index)
        
        # 從題庫中刪除
        if index < len(self.question_banks[self.current_question_bank]):
            self.question_banks[self.current_question_bank].pop(index)
        
        QMessageBox.information(self, "成功", "題目已刪除!")
    
    def save_question_bank(self, bank_name=None, export_format="json"):
        """保存題庫到文件"""
        if not bank_name:
            bank_name = self.current_question_bank
        
        if export_format == "json":
            filename, _ = QFileDialog.getSaveFileName(
                self,
                "保存題庫",
                f"{bank_name}.json",
                "JSON 文件 (*.json)"
            )
            
            if filename:
                try:
                    with open(filename, 'w', encoding='utf-8') as f:
                        json.dump(self.question_banks[bank_name], f, ensure_ascii=False, indent=4)
                    QMessageBox.information(self, "成功", f"題庫 '{bank_name}' 已保存為JSON格式!")
                except Exception as e:
                    QMessageBox.warning(self, "錯誤", f"保存失敗: {e}")
        else:  # Excel格式
            filename, _ = QFileDialog.getSaveFileName(
                self,
                "導(dǎo)出題庫",
                f"{bank_name}.xlsx",
                "Excel 文件 (*.xlsx)"
            )
            
            if filename:
                try:
                    self.export_to_excel(bank_name, filename)
                    QMessageBox.information(self, "成功", f"題庫 '{bank_name}' 已導(dǎo)出為Excel格式!")
                except Exception as e:
                    QMessageBox.warning(self, "錯誤", f"導(dǎo)出失敗: {e}")
    
    def export_to_excel(self, bank_name, filename):
        """將題庫導(dǎo)出為Excel文件"""
        workbook = openpyxl.Workbook()
        sheet = workbook.active
        sheet.title = "題庫"
        
        # 寫入表頭
        headers = ["題型", "題目", "選項A", "選項B", "選項C", "選項D", "答案", "分值"]
        sheet.append(headers)
        
        # 寫入題目
        for question in self.question_banks[bank_name]:
            row = [
                question["type"],
                question["question"]
            ]
            
            # 添加選項
            options = question.get("options", [])
            for i in range(4):
                row.append(options[i] if i < len(options) else "")
            
            # 添加答案和分值
            row.append(question["answer"])
            row.append(question.get("score", 1))
            
            sheet.append(row)
        
        workbook.save(filename)
    
    def load_question_bank_list(self):
        """加載題庫列表"""
        # 嘗試加載本地題庫文件
        self.load_local_banks()
        
        # 如果沒有加載到題庫,使用示例題庫
        if not self.question_banks:
            self.question_banks = {
                "示例題庫": [
                    {
                        "type": "單選題",
                        "question": "Python是什么類型的語言?",
                        "options": ["編譯型", "解釋型", "混合型", "匯編型"],
                        "answer": "B",
                        "score": 2
                    },
                    {
                        "type": "多選題",
                        "question": "以下哪些是Python的數(shù)據(jù)類型?",
                        "options": ["int", "float", "string", "boolean"],
                        "answer": "A, B, C, D",
                        "score": 3
                    },
                    {
                        "type": "判斷題",
                        "question": "Python是強類型語言。",
                        "options": ["正確", "錯誤"],
                        "answer": "正確",
                        "score": 1
                    }
                ]
            }
    
    def load_local_banks(self):
        """加載本地題庫文件(.json和.xlsx)"""
        # 加載JSON題庫
        json_files = self.find_local_files(".json")
        for file in json_files:
            try:
                with open(file, 'r', encoding='utf-8') as f:
                    bank_name = file.split('/')[-1].replace('.json', '')
                    self.question_banks[bank_name] = json.load(f)
            except Exception as e:
                print(f"加載JSON題庫失敗: {file}, 錯誤: {e}")
        
        # 加載Excel題庫
        excel_files = self.find_local_files(".xlsx")
        for file in excel_files:
            try:
                bank_name = file.split('/')[-1].replace('.xlsx', '')
                self.question_banks[bank_name] = self.load_excel_bank(file)
            except Exception as e:
                print(f"加載Excel題庫失敗: {file}, 錯誤: {e}")
    
    def find_local_files(self, extension):
        """查找本地題庫文件"""
        import os
        files = []
        for file in os.listdir('.'):
            if file.endswith(extension):
                files.append(file)
        return files
    
    def load_excel_bank(self, file_path):
        """從Excel文件加載題庫"""
        workbook = openpyxl.load_workbook(file_path)
        sheet = workbook.active
        questions = []
        
        for row in sheet.iter_rows(min_row=2, values_only=True):
            if not row[0]:  # 跳過空行
                continue
                
            q_type = row[0]
            question = {
                "type": q_type,
                "question": row[1],
                "options": [],
                "answer": row[-2],
                "score": row[-1] if row[-1] else 1
            }
            
            # 處理選項
            if q_type in ["單選題", "多選題"]:
                question["options"] = [opt for opt in row[2:-2] if opt]
            elif q_type == "判斷題":
                question["options"] = ["正確", "錯誤"]
            
            questions.append(question)
        
        return questions
    
    # 考試相關(guān)方法
    def start_exam(self):
        """開始考試"""
        bank_name = self.bank_combo.currentText()
        if not bank_name:
            QMessageBox.warning(self, "錯誤", "請選擇題庫!")
            return
        
        # 加載題庫
        self.current_question_bank = bank_name
        questions = self.question_banks[bank_name]
        
        if not questions:
            QMessageBox.warning(self, "錯誤", "題庫中沒有題目!")
            return
            
        try:
            num_questions = int(self.num_questions.text())
            single_ratio = int(self.single_ratio.text())
            multi_ratio = int(self.multi_ratio.text())
            bool_ratio = int(self.bool_ratio.text())
            
            if single_ratio + multi_ratio + bool_ratio != 100:
                QMessageBox.warning(self, "錯誤", "題型比例總和必須為100%!")
                return
        except ValueError:
            QMessageBox.warning(self, "錯誤", "請輸入有效的數(shù)字!")
            return
        
        # 按題型分類題目
        single_questions = [q for q in questions if q['type'] == "單選題"]
        multi_questions = [q for q in questions if q['type'] == "多選題"]
        bool_questions = [q for q in questions if q['type'] == "判斷題"]
        
        # 計算各題型題目數(shù)量
        single_count = int(num_questions * single_ratio / 100)
        multi_count = int(num_questions * multi_ratio / 100)
        bool_count = num_questions - single_count - multi_count
        
        # 隨機選擇題目
        selected_questions = []
        
        if single_count > 0:
            if len(single_questions) >= single_count:
                selected_questions.extend(random.sample(single_questions, single_count))
            else:
                selected_questions.extend(single_questions)
        
        if multi_count > 0:
            if len(multi_questions) >= multi_count:
                selected_questions.extend(random.sample(multi_questions, multi_count))
            else:
                selected_questions.extend(multi_questions)
        
        if bool_count > 0:
            if len(bool_questions) >= bool_count:
                selected_questions.extend(random.sample(bool_questions, bool_count))
            else:
                selected_questions.extend(bool_questions)
        
        # 如果題目不足,補充隨機題目
        if len(selected_questions) < num_questions:
            remaining = num_questions - len(selected_questions)
            all_questions = [q for q in questions if q not in selected_questions]
            if all_questions:
                selected_questions.extend(random.sample(all_questions, min(remaining, len(all_questions))))
        
        # 隨機排序
        random.shuffle(selected_questions)
        
        self.total_score = sum(q.get('score', 1) for q in selected_questions)
        
        # 設(shè)置考試計時器
        try:
            time_limit = int(self.time_limit.text())
            self.exam_mode = True
            self.exam_start_time = datetime.now()
            self.exam_time_limit = time_limit * 60  # 轉(zhuǎn)換為秒
        except ValueError:
            QMessageBox.warning(self, "錯誤", "請輸入有效的時間限制!")
            return
        
        # 設(shè)置當(dāng)前題目
        self.current_questions = selected_questions
        self.current_index = 0
        self.user_answers = {}
        self.score = 0
        
        # 顯示題目
        self.show_question()
    
    def update_exam_timer(self):
        """更新考試計時器"""
        if not self.exam_mode:
            return
        
        elapsed = (datetime.now() - self.exam_start_time).total_seconds()
        remaining = max(0, self.exam_time_limit - elapsed)
        
        minutes = int(remaining // 60)
        seconds = int(remaining % 60)
        
        self.timer_label.setText(f"剩余時間: {minutes:02d}:{seconds:02d}")
        
        if remaining <= 0:
            self.submit_exam()
        else:
            QTimer.singleShot(1000, self.update_exam_timer)
    
    def prev_question(self):
        """顯示上一題"""
        self.save_current_answer()
        if self.current_index > 0:
            self.current_index -= 1
            self.show_question()
    
    def next_question(self):
        """顯示下一題"""
        self.save_current_answer()
        if self.current_index < len(self.current_questions) - 1:
            self.current_index += 1
            self.show_question()
        else:
            self.submit_exam()
    
    def save_current_answer(self):
        """保存當(dāng)前題目的答案"""
        current_question = self.current_questions[self.current_index]
        q_type = current_question['type']
        
        if q_type == "單選題":
            for i, rb in enumerate(self.user_answer_rbs):
                if rb.isChecked():
                    self.user_answers[str(self.current_index)] = chr(65+i)
                    break
        elif q_type == "多選題":
            answer = []
            for i, cb in enumerate(self.user_answer_cbs):
                if cb.isChecked():
                    answer.append(chr(65+i))
            if answer:
                self.user_answers[str(self.current_index)] = "".join(answer)
        elif q_type == "判斷題":
            if self.user_answer_rbs[0].isChecked():
                self.user_answers[str(self.current_index)] = "正確"
            elif self.user_answer_rbs[1].isChecked():
                self.user_answers[str(self.current_index)] = "錯誤"
    
    def submit_exam(self):
        """提交試卷"""
        self.save_current_answer()
        self.exam_mode = False
        
        # 計算得分
        correct_count = 0
        self.score = 0
        
        for i, question in enumerate(self.current_questions):
            user_answer = self.user_answers.get(str(i), "")
            correct_answer = question['answer']
            q_score = question.get('score', 1)
            
            if question['type'] == "多選題":
                # 對多選題答案進行排序比較
                user_answer_sorted = "".join(sorted(user_answer.upper()))
                correct_answer_sorted = "".join(sorted(correct_answer.replace(", ", "").upper()))
                is_correct = user_answer_sorted == correct_answer_sorted
            else:
                is_correct = str(user_answer).upper() == str(correct_answer).upper()
            
            if is_correct:
                self.score += q_score
                correct_count += 1
            else:
                # 添加到錯題集
                if self.current_question_bank not in self.wrong_questions:
                    self.wrong_questions[self.current_question_bank] = []
                
                wrong_question = question.copy()
                wrong_question['user_answer'] = user_answer
                wrong_question['index'] = i
                self.wrong_questions[self.current_question_bank].append(wrong_question)
        
        # 顯示結(jié)果
        self.show_exam_result(correct_count)
    
    def retry_exam(self):
        """重新測驗"""
        self.start_exam()
    
    def confirm_exit_exam(self):
        """確認退出考試"""
        reply = QMessageBox.question(
            self, 
            "確認", 
            "確定要退出當(dāng)前考試嗎? 所有進度將丟失!", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.show_main_page()
    
    # 刷題相關(guān)方法
    def start_practice(self):
        """開始刷題"""
        bank_name = self.practice_bank_combo.currentText()
        if not bank_name:
            QMessageBox.warning(self, "錯誤", "請選擇題庫!")
            return
        
        # 加載題庫
        self.current_question_bank = bank_name
        questions = self.question_banks[bank_name]
        
        if not questions:
            QMessageBox.warning(self, "錯誤", "題庫中沒有題目!")
            return
            
        # 設(shè)置刷題順序
        self.practice_order = self.order_combo.currentText()
        
        # 準(zhǔn)備題目
        self.current_questions = questions.copy()
        
        if self.practice_order == "逆序":
            self.current_questions.reverse()
        elif self.practice_order == "隨機":
            random.shuffle(self.current_questions)
        
        self.current_index = 0
        self.user_answers = {}
        self.practice_mode = True
        
        # 顯示第一題
        self.show_practice_question()
    
    def submit_practice_answer(self):
        """提交刷題答案"""
        self.save_current_practice_answer()
        current_question = self.current_questions[self.current_index]
        user_answer = self.user_answers.get(str(self.current_index), "")
        correct_answer = current_question['answer']
        
        # 檢查答案
        if current_question['type'] == "多選題":
            # 對多選題答案進行排序比較
            user_answer_sorted = "".join(sorted(user_answer.upper()))
            correct_answer_sorted = "".join(sorted(correct_answer.replace(", ", "").upper()))
            is_correct = user_answer_sorted == correct_answer_sorted
        else:
            is_correct = str(user_answer).upper() == str(correct_answer).upper()
        
        # 顯示反饋
        if is_correct:
            self.answer_feedback.setText("? 回答正確!")
            self.answer_feedback.setStyleSheet("color: green;")
        else:
            self.answer_feedback.setText(f"? 回答錯誤! 正確答案是: {correct_answer}")
            self.answer_feedback.setStyleSheet("color: red;")
            
            # 記錄錯題
            if self.current_question_bank not in self.wrong_questions:
                self.wrong_questions[self.current_question_bank] = []
            
            wrong_question = current_question.copy()
            wrong_question['user_answer'] = user_answer
            self.wrong_questions[self.current_question_bank].append(wrong_question)
        
        self.btn_submit_practice.setEnabled(False)
    
    def save_current_practice_answer(self):
        """保存當(dāng)前刷題答案"""
        current_question = self.current_questions[self.current_index]
        q_type = current_question['type']
        
        if q_type == "單選題":
            for i, rb in enumerate(self.user_answer_rbs):
                if rb.isChecked():
                    self.user_answers[str(self.current_index)] = chr(65+i)
                    break
        elif q_type == "多選題":
            answer = []
            for i, cb in enumerate(self.user_answer_cbs):
                if cb.isChecked():
                    answer.append(chr(65+i))
            if answer:
                self.user_answers[str(self.current_index)] = "".join(answer)
        elif q_type == "判斷題":
            if self.user_answer_rbs[0].isChecked():
                self.user_answers[str(self.current_index)] = "正確"
            elif self.user_answer_rbs[1].isChecked():
                self.user_answers[str(self.current_index)] = "錯誤"
    
    def prev_practice_question(self):
        """上一題"""
        if self.current_index > 0:
            self.current_index -= 1
            self.show_practice_question()
    
    def next_practice_question(self):
        """下一題"""
        if self.current_index < len(self.current_questions) - 1:
            self.current_index += 1
            self.show_practice_question()
    
    def confirm_exit_practice(self):
        """確認退出刷題"""
        reply = QMessageBox.question(
            self, 
            "確認", 
            "確定要退出當(dāng)前刷題嗎?", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.practice_mode = False
            self.show_main_page()
    
    # 錯題集相關(guān)方法
    def show_wrong_answers(self):
        """顯示錯題"""
        self.show_wrong_questions()
    
    def update_wrong_list(self):
        """更新錯題列表"""
        bank_name = self.wrong_bank_combo.currentText()
        if not bank_name:
            return
        
        # 清空樹形視圖
        self.wrong_tree.clear()
        
        # 加載錯題
        for question in self.wrong_questions.get(bank_name, []):
            q_type = question['type']
            q_text = question['question']
            answer = question['answer']
            user_answer = question.get('user_answer', '')
            
            item = QTreeWidgetItem(self.wrong_tree)
            item.setText(0, q_type)
            item.setText(1, q_text)
            item.setText(2, answer)
            item.setText(3, user_answer)
    
    def show_wrong_detail(self):
        """顯示錯題詳情"""
        selected_items = self.wrong_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇一道錯題!")
            return
        
        item = selected_items[0]
        q_type = item.text(0)
        q_text = item.text(1)
        answer = item.text(2)
        user_answer = item.text(3)
        
        # 找到原始題目
        bank_name = self.wrong_bank_combo.currentText()
        index = None
        for q in self.wrong_questions.get(bank_name, []):
            if q['question'] == q_text and q['answer'] == answer and q.get('user_answer') == user_answer:
                index = q.get('index')
                break
        
        if index is None or index >= len(self.current_questions):
            QMessageBox.warning(self, "錯誤", "無法找到原始題目!")
            return
        
        original_question = self.current_questions[index]
        
        dialog = QDialog(self)
        dialog.setWindowTitle("錯題詳情")
        dialog.setModal(True)
        dialog.resize(800, 600)
        
        layout = QVBoxLayout(dialog)
        
        # 題目類型
        type_label = QLabel(f"[{q_type}]")
        type_label.setStyleSheet("font-weight: bold; color: #3498db;")
        layout.addWidget(type_label)
        
        # 題目文本
        question_label = QLabel(q_text)
        question_label.setWordWrap(True)
        question_label.setStyleSheet("font-size: 15px;")
        layout.addWidget(question_label)
        
        # 選項
        options_group = QGroupBox("選項")
        options_layout = QVBoxLayout(options_group)
        
        for i, option in enumerate(original_question['options']):
            option_label = QLabel(f"{chr(65+i)}. {option}")
            options_layout.addWidget(option_label)
        
        layout.addWidget(options_group)
        
        # 正確答案
        correct_frame = QWidget()
        correct_layout = QHBoxLayout(correct_frame)
        
        correct_label = QLabel("正確答案:")
        correct_label.setStyleSheet("font-weight: bold; color: green;")
        
        answer_label = QLabel(answer)
        
        correct_layout.addWidget(correct_label)
        correct_layout.addWidget(answer_label)
        correct_layout.addStretch()
        
        layout.addWidget(correct_frame)
        
        # 你的答案
        user_frame = QWidget()
        user_layout = QHBoxLayout(user_frame)
        
        user_label = QLabel("你的答案:")
        user_label.setStyleSheet("font-weight: bold; color: red;")
        
        user_answer_label = QLabel(user_answer)
        
        user_layout.addWidget(user_label)
        user_layout.addWidget(user_answer_label)
        user_layout.addStretch()
        
        layout.addWidget(user_frame)
        
        # 解析(如果有)
        if 'explanation' in original_question:
            explanation_group = QGroupBox("解析")
            explanation_layout = QVBoxLayout(explanation_group)
            
            explanation_text = QTextEdit(original_question['explanation'])
            explanation_text.setReadOnly(True)
            explanation_layout.addWidget(explanation_text)
            
            layout.addWidget(explanation_group)
        
        # 關(guān)閉按鈕
        close_btn = QPushButton("關(guān)閉")
        close_btn.clicked.connect(dialog.accept)
        layout.addWidget(close_btn, alignment=Qt.AlignRight)
        
        dialog.exec_()
    
    def delete_wrong_question(self):
        """刪除錯題"""
        selected_items = self.wrong_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯誤", "請先選擇一道錯題!")
            return
        
        bank_name = self.wrong_bank_combo.currentText()
        if not bank_name or bank_name not in self.wrong_questions:
            return
        
        reply = QMessageBox.question(
            self, 
            "確認", 
            "確定要刪除這道錯題嗎?", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.No:
            return
        
        # 獲取選中的錯題信息
        item = selected_items[0]
        q_text = item.text(1)
        answer = item.text(2)
        user_answer = item.text(3)
        
        # 從錯題集中刪除
        for i, question in enumerate(self.wrong_questions[bank_name]):
            if (question['question'] == q_text and 
                question['answer'] == answer and 
                question.get('user_answer') == user_answer):
                self.wrong_questions[bank_name].pop(i)
                break
        
        # 從樹形視圖中刪除
        self.wrong_tree.takeTopLevelItem(self.wrong_tree.indexOfTopLevelItem(item))
        
        QMessageBox.information(self, "成功", "錯題已刪除!")
    
    def back_from_wrong_page(self):
        """從錯題集頁面返回"""
        if hasattr(self, 'from_result_page') and self.from_result_page:
            self.content_area.setCurrentWidget(self.result_page)
        else:
            self.show_main_page()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    # 嘗試設(shè)置應(yīng)用圖標(biāo),如果沒有則忽略
    try:
        app.setWindowIcon(QIcon("icon.ico"))
    except:
        pass
    
    # 設(shè)置全局字體
    font = QFont()
    font.setFamily("Arial")
    font.setPointSize(10)
    app.setFont(font)
    
    window = BrainyQuiz()
    window.show()
    sys.exit(app.exec_())

項目結(jié)構(gòu)

brainy-quiz/
├── main.py                # 主程序入口
├── question_banks/        # 默認題庫目錄
│   ├── sample.json        # 示例JSON題庫
│   └── sample.xlsx        # 示例Excel題庫
├── icons/                 # 圖標(biāo)資源
│   └── icon.ico           # 應(yīng)用圖標(biāo)
└── README.md              # 項目說明文檔

未來擴展與優(yōu)化目標(biāo)

1.功能擴展:

添加用戶系統(tǒng),支持多賬戶

實現(xiàn)云端同步功能

增加題目解析和知識點標(biāo)簽

2.性能優(yōu)化:

使用數(shù)據(jù)庫存儲大規(guī)模題庫

添加題目緩存機制

優(yōu)化界面渲染性能

3.用戶體驗改進:

添加夜間模式

支持自定義主題

增加快捷鍵操作

4.教育功能增強:

實現(xiàn)智能出題算法

添加學(xué)習(xí)進度跟蹤

支持題目收藏功能

總結(jié)

白澤題庫系統(tǒng)通過PyQt5實現(xiàn)了功能完備的桌面端刷題應(yīng)用,具有以下優(yōu)勢:

  • 跨平臺性:基于Python和Qt,可在Windows、macOS和Linux上運行
  • 易用性:直觀的界面設(shè)計,降低學(xué)習(xí)成本
  • 擴展性:模塊化架構(gòu)便于功能擴展
  • 數(shù)據(jù)兼容:支持主流文件格式導(dǎo)入導(dǎo)出

通過本項目的開發(fā),我們不僅掌握了PyQt5的基本使用方法,還深入理解了桌面應(yīng)用開發(fā)的全流程。未來可以進一步探索:

  • 使用PyInstaller打包為獨立可執(zhí)行文件
  • 集成機器學(xué)習(xí)算法實現(xiàn)智能推薦
  • 開發(fā)移動端配套應(yīng)用

以上就是基于Python實現(xiàn)一個簡單的題庫與在線考試系統(tǒng)的詳細內(nèi)容,更多關(guān)于Python在線考試系統(tǒng)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Sanic框架異常處理與中間件操作實例分析

    Sanic框架異常處理與中間件操作實例分析

    這篇文章主要介紹了Sanic框架異常處理與中間件操作,結(jié)合實例形式較為詳細的分析了Sanic框架拋出異常、異常處理、中間件、監(jiān)聽器相關(guān)原理與操作技巧,需要的朋友可以參考下
    2018-07-07
  • python leetcode 字符串相乘實例詳解

    python leetcode 字符串相乘實例詳解

    這篇文章主要介紹了python leetcode 字符串相乘的示例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-09-09
  • Python使用sftp實現(xiàn)傳文件夾和文件

    Python使用sftp實現(xiàn)傳文件夾和文件

    這篇文章主要為大家詳細介紹了Python使用sftp實現(xiàn)傳文件夾和文件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Python pytest裝飾器總結(jié)(實例詳解)

    Python pytest裝飾器總結(jié)(實例詳解)

    這篇文章主要介紹了Python pytest裝飾器總結(jié),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • Python?pywin32實現(xiàn)word與Excel的處理

    Python?pywin32實現(xiàn)word與Excel的處理

    這篇文章主要介紹了Python?pywin32實現(xiàn)word與Excel的處理,pywin32處理Word大多數(shù)用于格式轉(zhuǎn)換,因為一般讀寫操作都可以借助python-docx實現(xiàn),除非真的有特殊要求,但大部分企業(yè)對Wrod操作不會有太多復(fù)雜需求
    2022-08-08
  • keras自定義回調(diào)函數(shù)查看訓(xùn)練的loss和accuracy方式

    keras自定義回調(diào)函數(shù)查看訓(xùn)練的loss和accuracy方式

    這篇文章主要介紹了keras自定義回調(diào)函數(shù)查看訓(xùn)練的loss和accuracy方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • python使用時間間隔的操作及技巧分享

    python使用時間間隔的操作及技巧分享

    Python 中處理時間間隔和日期時間的操作通常涉及 datetime 模塊,它提供了豐富的功能來處理日期和時間,本文給大家介紹了一些關(guān)于時間間隔操作的技巧和示例,并通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2024-12-12
  • Python Dict找出value大于某值或key大于某值的所有項方式

    Python Dict找出value大于某值或key大于某值的所有項方式

    這篇文章主要介紹了Python Dict找出value大于某值或key大于某值的所有項方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • 使用Python處理非標(biāo)準(zhǔn)JSON的實用方案

    使用Python處理非標(biāo)準(zhǔn)JSON的實用方案

    JSON(JavaScript Object Notation)作為輕量級數(shù)據(jù)交換格式被廣泛使用,但實際開發(fā)中常遇到不符合標(biāo)準(zhǔn)規(guī)范的JSON數(shù)據(jù),本文將探討如何用Python處理這些特殊情況,并提供實用解決方案,需要的朋友可以參考下
    2025-09-09
  • 詳解Python編程中基本的數(shù)學(xué)計算使用

    詳解Python編程中基本的數(shù)學(xué)計算使用

    這篇文章主要介紹了Python編程中基本的數(shù)學(xué)計算使用,其中重點講了除法運算及相關(guān)division模塊的使用,需要的朋友可以參考下
    2016-02-02

最新評論

吉木乃县| 德安县| 永胜县| 屏山县| 阿坝县| 兴隆县| 石门县| 台安县| 荥经县| 东至县| 金秀| 改则县| 聂荣县| 南安市| 饶平县| 察哈| 松桃| 兴国县| 莱芜市| 博客| 克什克腾旗| 台北市| 开封市| 永仁县| 乌兰县| 揭东县| 奇台县| 广河县| 隆尧县| 达拉特旗| 读书| 牙克石市| 太原市| 西昌市| 西昌市| 定日县| 烟台市| 鄂托克旗| 科技| 南郑县| 磐石市|