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

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

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

概述

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

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

功能特點(diǎn)

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

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

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

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

界面展示

主界面

題庫管理

考試模式

刷題模式

錯(cuò)題集

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

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

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

Excel題庫填寫格式模板

題庫題目填寫格式表

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

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

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

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

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

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

實(shí)現(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è)計(jì)

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

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. 題庫管理實(shí)現(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. 隨機(jī)組卷算法

按題型比例隨機(jī)抽取題目:

def start_exam(self):
    # 計(jì)算各題型題目數(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
    
    # 隨機(jī)選擇題目
    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))
    
    # 隨機(jī)排序
    random.shuffle(selected_questions)

6. 刷題模式實(shí)現(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 == "隨機(jī)":
        random.shuffle(self.current_questions)

7. 錯(cuò)題集管理

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

def submit_exam(self):
    if not is_correct:
        # 添加到錯(cuò)題集
        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)計(jì)可視化

使用Matplotlib生成錯(cuò)題分析圖表:

def show_stats(self):
    # 創(chuàng)建圖表
    fig = self.stats_canvas.figure
    fig.clear()
    
    # 錯(cuò)題題型分布餅圖
    ax1 = fig.add_subplot(121)
    ax1.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
    
    # 各題庫錯(cuò)題數(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)選項(xià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 == "多選題":
        # 對(duì)多選題答案進(jìn)行排序比較
        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è)計(jì)

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()
        
        # 添加各個(gè)頁面
        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("?? 隨機(jī)組卷")
        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("? 錯(cuò)題集")
        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)計(jì)")
        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("白澤為引,點(diǎn)亮你的題海修行之路")
        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("一款功能強(qiáng)大的刷題軟件,支持多種題型和智能學(xué)習(xí)統(tǒng)計(jì)")
        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(["題型", "題目", "選項(xiàng)", "答案", "分值"])
        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("?? 隨機(jī)組卷設(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)
        
        # 時(shí)間限制
        self.time_limit_label = QLabel("時(shí)間限制(分鐘):")
        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)
        
        # 計(jì)時(shí)器
        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)
        
        # 進(jìn)度顯示
        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)建測驗(yàn)結(jié)果頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("?? 測驗(yàn)結(jié)果")
        title.setStyleSheet("""
            QLabel {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 20px;
            }
        """)
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # 結(jié)果統(tǒng)計(jì)
        self.stats_group = QGroupBox("測驗(yàn)統(tǒng)計(jì)")
        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)
        
        # 錯(cuò)題按鈕
        self.btn_wrong_answers = QPushButton("查看錯(cuò)題")
        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("?? 重新測驗(yàn)")
        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)建錯(cuò)題集頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("? 錯(cuò)題集")
        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)
        
        # 錯(cuò)題列表
        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("??? 刪除錯(cuò)題")
        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)計(jì)頁面"""
        page = QWidget()
        layout = QVBoxLayout(page)
        
        # 標(biāo)題
        title = QLabel("?? 學(xué)習(xí)統(tǒng)計(jì)")
        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(["順序", "逆序", "隨機(jī)"])
        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)
        
        # 進(jìn)度顯示
        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, "錯(cuò)誤", "沒有可用的題目!")
            return
        
        self.content_area.setCurrentWidget(self.exam_page)
        
        # 顯示計(jì)時(shí)器
        self.timer_layout.parentWidget().show()
        self.update_exam_timer()
        
        # 更新進(jìn)度
        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)
        
        # 清除之前的選項(xiàng)
        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("錯(cuò)誤")
            
            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, "錯(cuò)誤", "沒有可用的題目!")
            return
        
        self.content_area.setCurrentWidget(self.practice_page)
        
        # 更新進(jìn)度
        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)
        
        # 清除之前的選項(xiàng)
        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("錯(cuò)誤")
            
            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):
        """顯示測驗(yàn)結(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})")
        
        # 如果沒有錯(cuò)題,隱藏查看錯(cuò)題按鈕
        self.btn_wrong_answers.setVisible(correct_count < total_questions)
        
        self.content_area.setCurrentWidget(self.result_page)
    
    def show_wrong_questions(self):
        """顯示錯(cuò)題集頁面"""
        if not self.wrong_questions:
            QMessageBox.information(self, "提示", "錯(cuò)題集為空!")
            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)計(jì)頁面"""
        if not self.wrong_questions:
            QMessageBox.information(self, "提示", "暫無統(tǒng)計(jì)數(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  # 用來正常顯示負(fù)號(hào)
        
        # 錯(cuò)題題型分布
        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('錯(cuò)題題型分布')
        
        # 各題庫錯(cuò)題數(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('各題庫錯(cuò)題數(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, "錯(cuò)誤", 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, "錯(cuò)誤", "題庫已存在!")
            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, "錯(cuò)誤", "請先選擇一個(gè)題庫!")
            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, "錯(cuò)誤", "請先選擇一個(gè)題庫!")
            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, "錯(cuò)誤", "請先選擇一個(gè)題庫!")
            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, "錯(cuò)誤", "請先選擇一個(gè)題庫!")
            return
        
        bank_name = selected_items[0].text()
        
        reply = QMessageBox.question(
            self, 
            "確認(rèn)", 
            f"確定要?jiǎng)h除題庫 '{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):
        """添加題目對(duì)話框"""
        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)
        
        # 選項(xiàng)框架
        options_group = QGroupBox("選項(xiàng)")
        options_layout = QVBoxLayout(options_group)
        
        self.option_edits = []
        for i in range(4):
            option_layout = QHBoxLayout()
            option_layout.addWidget(QLabel(f"選項(xiàng) {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(["正確", "錯(cuò)誤"])
        
        # 默認(rèn)顯示單選題答案
        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()
                
            # 顯示/隱藏選項(xiàng)
            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 = ["正確", "錯(cuò)誤"]
        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, "錯(cuò)誤", "題目不能為空!")
            return
        
        if not options:
            QMessageBox.warning(dialog, "錯(cuò)誤", "至少需要一個(gè)選項(xiàng)!")
            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, "錯(cuò)誤", "請?jiān)O(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):
        """編輯題目對(duì)話框"""
        selected_items = self.question_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯(cuò)誤", "請先選擇要編輯的題目!")
            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)
        
        # 選項(xiàng)框架
        options_group = QGroupBox("選項(xiàng)")
        options_layout = QVBoxLayout(options_group)
        
        self.option_edits = []
        for i in range(4):
            option_layout = QHBoxLayout()
            option_layout.addWidget(QLabel(f"選項(xiàng) {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(["正確", "錯(cuò)誤"])
        
        # 設(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()
                
            # 顯示/隱藏選項(xiàng)
            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 = ["正確", "錯(cuò)誤"]
        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, "錯(cuò)誤", "題目不能為空!")
            return
        
        if not options:
            QMessageBox.warning(dialog, "錯(cuò)誤", "至少需要一個(gè)選項(xiàng)!")
            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, "錯(cuò)誤", "請?jiān)O(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, "錯(cuò)誤", "請先選擇要?jiǎng)h除的題目!")
            return
        
        reply = QMessageBox.question(
            self, 
            "確認(rèn)", 
            "確定要?jiǎng)h除選中的題目嗎?", 
            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, "錯(cuò)誤", 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, "錯(cuò)誤", f"導(dǎo)出失敗: {e}")
    
    def export_to_excel(self, bank_name, filename):
        """將題庫導(dǎo)出為Excel文件"""
        workbook = openpyxl.Workbook()
        sheet = workbook.active
        sheet.title = "題庫"
        
        # 寫入表頭
        headers = ["題型", "題目", "選項(xiàng)A", "選項(xiàng)B", "選項(xiàng)C", "選項(xiàng)D", "答案", "分值"]
        sheet.append(headers)
        
        # 寫入題目
        for question in self.question_banks[bank_name]:
            row = [
                question["type"],
                question["question"]
            ]
            
            # 添加選項(xiàng)
            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是強(qiáng)類型語言。",
                        "options": ["正確", "錯(cuò)誤"],
                        "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}, 錯(cuò)誤: {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}, 錯(cuò)誤: {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
            }
            
            # 處理選項(xiàng)
            if q_type in ["單選題", "多選題"]:
                question["options"] = [opt for opt in row[2:-2] if opt]
            elif q_type == "判斷題":
                question["options"] = ["正確", "錯(cuò)誤"]
            
            questions.append(question)
        
        return questions
    
    # 考試相關(guān)方法
    def start_exam(self):
        """開始考試"""
        bank_name = self.bank_combo.currentText()
        if not bank_name:
            QMessageBox.warning(self, "錯(cuò)誤", "請選擇題庫!")
            return
        
        # 加載題庫
        self.current_question_bank = bank_name
        questions = self.question_banks[bank_name]
        
        if not questions:
            QMessageBox.warning(self, "錯(cuò)誤", "題庫中沒有題目!")
            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, "錯(cuò)誤", "題型比例總和必須為100%!")
                return
        except ValueError:
            QMessageBox.warning(self, "錯(cuò)誤", "請輸入有效的數(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'] == "判斷題"]
        
        # 計(jì)算各題型題目數(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
        
        # 隨機(jī)選擇題目
        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)
        
        # 如果題目不足,補(bǔ)充隨機(jī)題目
        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))))
        
        # 隨機(jī)排序
        random.shuffle(selected_questions)
        
        self.total_score = sum(q.get('score', 1) for q in selected_questions)
        
        # 設(shè)置考試計(jì)時(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, "錯(cuò)誤", "請輸入有效的時(shí)間限制!")
            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):
        """更新考試計(jì)時(shí)器"""
        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"剩余時(shí)間: {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)] = "錯(cuò)誤"
    
    def submit_exam(self):
        """提交試卷"""
        self.save_current_answer()
        self.exam_mode = False
        
        # 計(jì)算得分
        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'] == "多選題":
                # 對(duì)多選題答案進(jìn)行排序比較
                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:
                # 添加到錯(cuò)題集
                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):
        """重新測驗(yàn)"""
        self.start_exam()
    
    def confirm_exit_exam(self):
        """確認(rèn)退出考試"""
        reply = QMessageBox.question(
            self, 
            "確認(rèn)", 
            "確定要退出當(dāng)前考試嗎? 所有進(jìn)度將丟失!", 
            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, "錯(cuò)誤", "請選擇題庫!")
            return
        
        # 加載題庫
        self.current_question_bank = bank_name
        questions = self.question_banks[bank_name]
        
        if not questions:
            QMessageBox.warning(self, "錯(cuò)誤", "題庫中沒有題目!")
            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 == "隨機(jī)":
            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'] == "多選題":
            # 對(duì)多選題答案進(jìn)行排序比較
            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"? 回答錯(cuò)誤! 正確答案是: {correct_answer}")
            self.answer_feedback.setStyleSheet("color: red;")
            
            # 記錄錯(cuò)題
            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)] = "錯(cuò)誤"
    
    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):
        """確認(rèn)退出刷題"""
        reply = QMessageBox.question(
            self, 
            "確認(rèn)", 
            "確定要退出當(dāng)前刷題嗎?", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.practice_mode = False
            self.show_main_page()
    
    # 錯(cuò)題集相關(guān)方法
    def show_wrong_answers(self):
        """顯示錯(cuò)題"""
        self.show_wrong_questions()
    
    def update_wrong_list(self):
        """更新錯(cuò)題列表"""
        bank_name = self.wrong_bank_combo.currentText()
        if not bank_name:
            return
        
        # 清空樹形視圖
        self.wrong_tree.clear()
        
        # 加載錯(cuò)題
        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):
        """顯示錯(cuò)題詳情"""
        selected_items = self.wrong_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯(cuò)誤", "請先選擇一道錯(cuò)題!")
            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, "錯(cuò)誤", "無法找到原始題目!")
            return
        
        original_question = self.current_questions[index]
        
        dialog = QDialog(self)
        dialog.setWindowTitle("錯(cuò)題詳情")
        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)
        
        # 選項(xiàng)
        options_group = QGroupBox("選項(xiàng)")
        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):
        """刪除錯(cuò)題"""
        selected_items = self.wrong_tree.selectedItems()
        if not selected_items:
            QMessageBox.warning(self, "錯(cuò)誤", "請先選擇一道錯(cuò)題!")
            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, 
            "確認(rèn)", 
            "確定要?jiǎng)h除這道錯(cuò)題嗎?", 
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.No:
            return
        
        # 獲取選中的錯(cuò)題信息
        item = selected_items[0]
        q_text = item.text(1)
        answer = item.text(2)
        user_answer = item.text(3)
        
        # 從錯(cuò)題集中刪除
        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, "成功", "錯(cuò)題已刪除!")
    
    def back_from_wrong_page(self):
        """從錯(cuò)題集頁面返回"""
        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_())

項(xiàng)目結(jié)構(gòu)

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

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

1.功能擴(kuò)展:

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

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

增加題目解析和知識(shí)點(diǎn)標(biāo)簽

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

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

添加題目緩存機(jī)制

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

3.用戶體驗(yàn)改進(jìn):

添加夜間模式

支持自定義主題

增加快捷鍵操作

4.教育功能增強(qiáng):

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

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

支持題目收藏功能

總結(jié)

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

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

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

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

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

相關(guān)文章

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

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

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

    python leetcode 字符串相乘實(shí)例詳解

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

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

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

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

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

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

    這篇文章主要介紹了Python?pywin32實(shí)現(xiàn)word與Excel的處理,pywin32處理Word大多數(shù)用于格式轉(zhuǎn)換,因?yàn)橐话阕x寫操作都可以借助python-docx實(shí)現(xiàn),除非真的有特殊要求,但大部分企業(yè)對(duì)Wrod操作不會(huì)有太多復(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方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • python使用時(shí)間間隔的操作及技巧分享

    python使用時(shí)間間隔的操作及技巧分享

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

    Python Dict找出value大于某值或key大于某值的所有項(xiàng)方式

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

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

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

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

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

最新評(píng)論

宽城| 大埔县| 巴林右旗| 苏尼特右旗| 容城县| 印江| 黄石市| 乳源| 九龙坡区| 招远市| 香格里拉县| 西城区| 石阡县| 肥东县| 乐都县| 浮山县| 滦平县| 社会| 马公市| 潜山县| 虹口区| 修文县| 仁寿县| 金门县| 连云港市| 汕尾市| 鄂伦春自治旗| 密云县| 拉萨市| 济阳县| 根河市| 富宁县| 罗田县| 容城县| 茌平县| 漾濞| 钦州市| 武强县| 萍乡市| 西城区| 文成县|