You need to enable JavaScript to run this app. 基于Python与Tkinter开发测验程序:如何用txt读取题目、答案与解析,是否改用数组?
优惠活动
大模型
产品
解决方案
定价
更多

基于Python与Tkinter开发测验程序:如何用txt读取题目、答案与解析,是否改用数组?

最简实现方案

核心认知澄清

不存在「txt存内容」和「数组存内容」二选一的问题。txt是用来离线维护题库的存储格式,程序启动时把txt内容读出来转换成内存里的列表(也就是你说的数组),既不用硬编码改题库,又能拿到数组遍历方便的好处,完全适配你的需求。
你原来想的三个txt的方案完全可行,只要解决「行号对齐」的问题就能跑,不用推翻重来。

第一步:给三个txt定固定格式,避免内容错位

如果三个txt随便写内容,很容易出现“第3题的题目匹配到第2题的解析”这种错位问题,只要按下面的规则写,就不会出问题:

  • 题目.txt:一行对应一道题,不要把一道题拆成两行写
  • 答案集合.txt:一行对应同序号题目的所有选项,用固定分隔符(比如|)把单个选项隔开,行号和题目.txt严格一一对应
  • 解析.txt:一行对应同序号题目的解析内容,行号和题目.txt严格一一对应

格式示例参考:

# 题目.txt 内容
1. Python中以下哪个不是合法的变量名?
2. Tkinter中用于创建主窗口的类是?
3. 以下哪个布局方法支持自适应窗口缩放?
# 答案集合.txt 内容(和题目行严格对齐)
A. score|B. 2_score|C. score2|D. _score
A. Tk()|B. Frame()|C. Button()|D. Label()
A. pack|B. grid|C. place|D. 以上都是
# 解析.txt 内容(和题目行严格对齐)
Python变量名不能以数字开头,因此2_score是非法命名。
Tk()是生成程序主窗口的核心类,其余均为组件或容器。
pack、grid、place三种布局均支持窗口自适应调整。

第二步:写通用的题库读取逻辑

读文件时自动过滤空行,把三个文件的内容按行匹配成结构化的题目对象,加个简单的行数校验,避免错位:

def load_quiz():
    # 读取题目
    with open("题目.txt", "r", encoding="utf-8") as f:
        q_list = [line.strip() for line in f if line.strip()]
    # 读取选项,按|拆分单个选项
    with open("答案集合.txt", "r", encoding="utf-8") as f:
        opt_list = [line.strip().split("|") for line in f if line.strip()]
    # 读取解析
    with open("解析.txt", "r", encoding="utf-8") as f:
        exp_list = [line.strip() for line in f if line.strip()]
    
    # 校验三个文件行数一致
    if not (len(q_list) == len(opt_list) == len(exp_list)):
        raise RuntimeError("三个题库文件行数不匹配,请检查内容对齐")
    
    # 组合成可遍历的题目列表(本质就是你说的数组结构)
    return [
        {"content": q, "options": o, "explain": e}
        for q, o, e in zip(q_list, opt_list, exp_list)
    ]

第三步:Tkinter端的渲染逻辑

只要维护一个当前题目的索引变量,每次切题时先清空窗口上的旧组件,再渲染新的题目Label、选项Button,点击选项后再切到解析展示界面就行:

import tkinter as tk
from tkinter import messagebox

root = tk.Tk()
root.geometry("700x500")
# 加载题库
quiz = load_quiz()
current_idx = 0

def render_question():
    # 清空所有旧组件
    for w in root.winfo_children():
        w.destroy()
    
    q = quiz[current_idx]
    # 渲染题目为Label
    tk.Label(
        root, text=q["content"], wraplength=650, 
        font=("微软雅黑", 14), pady=30
    ).pack()
    # 遍历选项生成Button
    for opt in q["options"]:
        tk.Button(
            root, text=opt, width=45, font=("微软雅黑", 12),
            pady=8, command=lambda o=opt: show_explain(o, q)
        ).pack(pady=6)

def show_explain(selected_opt, q):
    # 清空旧组件,展示解析
    for w in root.winfo_children():
        w.destroy()
    tk.Label(
        root, text=f"答案解析:{q['explain']}", 
        wraplength=650, font=("微软雅黑", 12), pady=40
    ).pack()
    # 下一题按钮
    tk.Button(root, text="下一题", width=20, command=next_q).pack(pady=20)

def next_q():
    global current_idx
    current_idx +=1
    if current_idx >= len(quiz):
        messagebox.showinfo("完成", "所有题目已作答完毕")
        root.destroy()
        return
    render_question()

# 启动第一题
render_question()
root.mainloop()

避坑提示

  • 给题目、解析的Label一定要设置wraplength参数,不然长文本会把窗口撑得超出屏幕
  • 每次切换界面时必须先调用winfo_children()清空旧组件,不然旧的按钮、标签会和新内容叠在一起
  • 如果题库量大怕行错位,可以给每道题加固定ID标记,不用完全依赖行号匹配,容错率更高

没必要为了“用数组存储”就把所有题目硬编码写在代码里,txt离线存题库的方式改起来比翻代码方便太多。

内容的提问来源于stack exchange,提问作者Unko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.28 13:27:02