Python选择题训练工具:高效学习、答题回顾与音频朗读一站式体验

一、引言

随着人工智能技术的不断进步,传统的教学方式已经逐渐向智能化、互动化转变。在众多英语测试题型中,选择题作为一种高效的方式被广泛应用于各类培训与考试中。为了帮助学生高效学习与自测,本篇文章将采用Python编写一款基于 Python 开发的选择题训练工具。该工具不仅支持加载 Excel 文件中的题库,还具备题干和选项展示、答题记录、音频朗读等多种功能,旨在为用户提供便捷、高效的学习体验。

二、开发背景

在日常教学过程中,老师往往需要准备大量的选择题作为测试题目。我们可以把这些题目存储在 Excel 文件中,如果手动处理和展示题目会非常繁琐。为了提高教学效率,选用一种自动化展示工具成为一种迫切的需求。本项目通过 Python 和 Tkinter 库实现了一个图形化界面应用,可以自动加载并展示选择题,记录用户答题情况,同时通过音频朗读题目,进一步增强互动性。软件的示意图如下:

软件展示

三、软件特点

  1. 题库加载与展示:支持从 Excel 文件中加载选择题,并且可以根据课程单元名称筛选题目。
  2. 音频朗读功能:使用 Python 的 Pygame 库播放题目音频,即朗读题干,帮助用户通过听力巩固已学单词。
  3. 答题记录与统计:软件会自动记录用户的答题情况,并在决定答题结束时,提供正确率和错误题目的回顾功能。
  4. 多线程支持:使用线程处理音频播放等耗时操作,避免界面卡顿,提升用户体验。同时,当完成一道题时,会自动转到下一道,并给出正确或错误的提示。正确就是显示绿色button选项,错误就显示红色button选项。
  5. 图形化界面:基于 Tkinter 实现的 GUI 界面,简单直观,易于操作。

四、使用方法

1. 安装依赖

在运行程序之前,需要安装一些 Python 库,依赖包括 openpyxl, pygame 和 requests。可以使用以下命令安装所需的库:

python 复制代码
pip install openpyxl pygame requests 

2. 准备题库

本程序需要一个 Excel 文件,并命名为【选择题.xlsx】作为题库,Excel 文件应包括如下列:

  • 单元:课程名称或章节
  • 序号:题目的编号
  • 题干:选择题的内容
  • 选项A、B、C、D:四个选择项
  • 正确答案:正确的答案选项

Excel表的内容如下:

Excel表内容

3. 运行程序

运行 Python 程序,tkinter GUI界面会自动加载,用户可以在顶部下拉框选择不同的课程,然后开始答题,结束前查看战绩,回顾错误题目,还可以点朗读通过音频功能听题干。

4. 功能概览

  • 选择题显示:在每道题目显示时,用户可以选择答案。程序会自动判断正确与否,并高亮显示选择的答案。
  • 战绩统计:用户答题完成后,可以查看自己的正确率统计。
  • 错误回顾:用户可以查看答错的题目,并且看到正确答案与自己的选择。
  • 朗读功能:用户可以点击按钮让程序朗读题干。

五、源码展示

以下是该程序的主要代码:

python 复制代码
import tkinter as tk
from tkinter import ttk, messagebox
from openpyxl import load_workbook
import random
import os,re
import pygame,requests
from io import BytesIO
from threading import Lock, Thread, Timer

def load_excel_data(filename):
    workbook = load_workbook(filename)
    sheet = workbook.active
    questions = []
    lessons = set()  # 用于存储所有课程名,避免重复
    for row in sheet.iter_rows(min_row=2, values_only=True):
        lesson = row[0]
        lessons.add(lesson)
        question = {
            '单元': lesson,
            '序号': row[1],
            '题干': row[2],
            '选项': [row[3], row[4], row[5], row[6]],
            '正确答案': row[7]
        }
        questions.append(question)
    return list(lessons), questions

lessons, questions = load_excel_data('选择题.xlsx')
random.shuffle(questions)

# 使用正则表达式从课程名中提取数字,并按数字排序课程名
sorted_lessons = sorted(lessons, key=lambda x: (lambda m: int(m.group(0)) if m else 0)(re.search(r'\d+', x)))

class QuizApp:
    def __init__(self, root):
        self.root = root
            # 设置窗口大小
        self.root.geometry("600x500")
        #self.root.resizable(False, False)
        pygame.init()
        self.all_questions = questions
        self.questions = questions  # 当前显示的问题列表
        self.current_question_index = 0
        self.correct_answers = 0
        self.wrong_answers = 0
        self.error_questions = []
        self.setup_ui()
        self.load_question()
        
    def thread_it(self,func):
        self.thread1=Thread(target=func)
        self.thread1.setDaemon(True) 
        self.thread1.start()

    def setup_ui(self):
        self.root.title("选择题训练工具")
        self.lesson_combobox = ttk.Combobox(self.root, values=['全部'] + sorted_lessons, state="readonly")
        self.lesson_combobox.pack(pady=(10, 0))
        self.lesson_combobox.set('全部')
        self.lesson_combobox.bind('<<ComboboxSelected>>', self.on_combobox_change)
        self.question_label = tk.Label(self.root, text="", font=("Times New Roman", 20), fg="blue", wraplength=520, justify=tk.LEFT) #设置文本长度,并且文本左对齐
        self.question_label.pack(pady=(10, 40))

        self.options_frame = tk.Frame(self.root)
        self.options_frame.pack(pady=20)

        option_labels = ['A', 'B', 'C', 'D']  # 选项标签
        self.option_buttons = []  # 存储选项按钮
        self.option_labels = []  # 存储选项标签控件

        for i in range(4):
            # 创建选项标签控件并放置
            label = tk.Label(self.options_frame, text=f"{option_labels[i]}.", font=("Times New Roman", 16))
            label.grid(row=i, column=0, pady=5, sticky="e")
            self.option_labels.append(label)
            
            # 创建选项按钮并放置
            btn = tk.Button(self.options_frame, text="", font=("Times New Roman", 16), width=20,
                command=lambda b=i: self.check_answer(b),  # type: ignore
                anchor="w")


            btn.grid(row=i, column=1, pady=5)
            self.option_buttons.append(btn)

        self.action_frame = tk.Frame(self.root)
        self.action_frame.pack(side=tk.BOTTOM, pady=20)
        tk.Button(self.action_frame, text="退出程序", font=("宋体", 16, "bold"), width=9, command=self.ui_quit).pack(side=tk.LEFT, padx=10)
        tk.Button(self.action_frame, text="我的战绩", font=("宋体", 16, "bold"), width=9, command=self.show_score).pack(side=tk.LEFT, padx=10)
        tk.Button(self.action_frame, text="查看错误", font=("宋体", 16, "bold"), width=9, command=self.show_errors).pack(side=tk.LEFT, padx=10)
        tk.Button(self.action_frame, text="朗读题干", font=("宋体", 16, "bold"), width=9, command=self.show_sound).pack(side=tk.LEFT, padx=10)# 其余UI代码与原来相同...

    def on_combobox_change(self, event):
        selected_lesson = self.lesson_combobox.get()
        if selected_lesson == '全部':
            self.questions = self.all_questions
        else:
            self.questions = [q for q in self.all_questions if q['单元'] == selected_lesson]
        self.current_question_index = 0
        self.correct_answers = 0
        self.wrong_answers = 0
        self.error_questions = []
        self.load_question()

    def load_question(self):
        if self.current_question_index < len(self.questions):
            question = self.questions[self.current_question_index]
            self.question_label.config(text=str(self.current_question_index+1)+". "+question['题干'],anchor='w')
            correct_answer = question['正确答案']
            options = question['选项']
            self.correct_option_index = options.index(correct_answer)
            random.shuffle(options)

            for i, option in enumerate(options):
                self.option_buttons[i].config(text=option, bg='SystemButtonFace')

    def check_answer(self, button_index):
        question = self.questions[self.current_question_index]
        selected_option = self.option_buttons[button_index].cget('text')
        correct_option = question['正确答案']
        
        # 确定正确答案按钮的索引
        correct_option_index = None
        for i, btn in enumerate(self.option_buttons):
            if btn.cget('text') == correct_option:
                correct_option_index = i
                break

        if selected_option == correct_option:
            # 用户选择了正确的答案
            self.option_buttons[button_index].config(bg='light green')
            self.correct_answers += 1
        else:
            # 用户选择了错误的答案
            self.option_buttons[button_index].config(bg='red')
            if correct_option_index is not None:
                self.option_buttons[correct_option_index].config(bg='light green')
            self.wrong_answers += 1
            self.error_questions.append((question['题干'], selected_option, question['正确答案']))

        # 准备间隔1秒显示下一个问题
        self.root.after(1000, self.next_question)


    def next_question(self):
        self.current_question_index += 1
        if self.current_question_index < len(self.questions):
            self.load_question()
        else:
            messagebox.showinfo("结束", "所有问题都已回答完毕!")

    def ui_quit(self):
        self.root.destroy()

    def show_score(self):
        messagebox.showinfo("战绩", f"正确: {self.correct_answers}\n错误: {self.wrong_answers}\n总计: {len(self.questions)}\n正确率:{self.correct_answers/len(self.questions)*100}%")
    
    def show_sound(self):
        self.thread_it(self.show_sound2)
    
    def show_errors(self):
        error_messages = "\n".join([f"题干: {q[0]},正确答案是:{q[2]}, 您的选择: {q[1]}" for q in self.error_questions])
        messagebox.showinfo("错误回顾", error_messages if error_messages else "完美!没有任何错误。")

    def show_sound2(self):
        self.current_name = self.question_label.cget("text")
        audio_path = f"https://dict.youdao.com/dictvoice?audio={self.current_name}&type=1"
        resp = requests.get(audio_path)
        audio_data = BytesIO(resp.content)
        pygame.mixer.music.load(audio_data)
        pygame.mixer.music.play()
        while pygame.mixer.music.get_busy():
            continue
        # 退出pygame

if __name__ == "__main__":
    root = tk.Tk()
    app = QuizApp(root)
    root.mainloop()

六、注意事项

  1. Excel 文件格式 :确保题库文件【选择题.xlsx】的格式正确,每个问题必须包含单元、序号、题干、选项和正确答案等字段。
  2. 音频播放:程序中使用了 Pygame 库进行音频播放,因此需要安装相应的音频库,并且程序会访问在线字典接口生成题目音频。
  3. 线程管理:为了避免界面卡顿,音频播放等操作被放置在单独的线程中处理,保证主界面的流畅性。
  4. 数据存储:答题结果和错误回顾会暂时保存在程序内存中,但如果需要长期保存数据,可以考虑添加导出功能。

七、总结

这款选择题训练工具通过 Python 实现了一个简单易用的答题系统,利用 Tkinter 提供了良好的用户界面,结合 Pygame 和音频播放技术,增强了选择题问答的互动性。它可以帮助学生提高学习效率,帮助教师管理题库,并提供了直观的成绩统计与错误回顾功能,是一款非常实用的教学辅助工具。

相关推荐
小馒头学python2 分钟前
【期末大作业】使用Python熟练掌握面向对象
开发语言·python·课程设计
Sunsets_Red3 分钟前
CF1548A Web of Lies 题解
c++·学习·算法·信息与通信
李雨非-19期-河北工职大5 分钟前
复盘:“辩论赛”复盘
学习
每月一号准时摆烂21 分钟前
数字逻辑(五)——用二进制来表示音频和视频
嵌入式硬件·音视频
MavenTalk22 分钟前
如何使用Python进行音频片断合成
开发语言·python·音视频·pico2wave·gtts·synthesizer
桃园码工23 分钟前
12_HTML5 Video(视频) --[HTML5 API 学习之旅]
音视频·html5·video
hnmpf34 分钟前
wtforms+flask_sqlalchemy在flask-admin视图下实现日期的修改与更新
后端·python·flask
江上挽风&sty34 分钟前
【Django篇】--创建第一个Django项目
后端·python·django
壹屋安源34 分钟前
自动生成发票数据并存入Excel
python·excel·pandas·random·datetime·faker
Jelena技术达人37 分钟前
利用Python爬虫获取微店商品详情API接口的深入指南
开发语言·爬虫·python