python项目实践--基于TKinter给读文科的ta写一个背题助手!

自学了一段时间python~ 在摸爬滚打中算是了解了基本的语法。但感觉这样好像不够,光写一些简短的代码好像不满足。恰逢学习文科的女朋友问我有没有一款类似驾考宝典的app,可以自己导入题库,用来随机抽取题目回答,从而加深记忆。搜了一圈貌似没有特别对胃口的。那为什么不自己写一个呢~

说干就干!首先跟她确定了一下需求。题库中的题型有选择、判断、填空。导入题库后可以自己选择题型与章节,组成一个子题目池。在子题目池中随机抽取题目作答,并且反馈正确与否。

然后大概思考一下整个一套的流程~ 第一步(姑且叫做choose_file环节)先选择一个题库,导入了题库以后,第二步(姑且叫做entry环节)在一个复选框页面选择想要的题型与章节。第三步循环,随机抽取并回答题目。当题目回答完以后第四步(姑且叫做question_empty环节)提示已完成,并回到第二步的选择题型与章节中。

那么就开始吧~ 说明一下,完整代码会在文章的最后贴出来。

首先导入我们需要的库

# /usr/bin/python3
# -*- coding:utf-8 -*-
import tkinter as tk
import tkinter.messagebox as msg
import tkinter.filedialog as fd
from tkinter import *
import json
import random
import os
import sys

先轻微施工一下main函数。定义主窗口,并调用一个choose_file函数来导入我们需要的题库。考虑到后续按钮的command命令仅可输入函数名,对于参数的传入传出不是那么方便,因此考虑对一些原本需要传出的变量用global全局一下。

def choose_file():
    global timu_list, whole_chapter_list, whole_qtype_list
    file_path = 'NoFileChosed'
    while file_path[-5:] != '.json':  # 判断文件格式
        if file_path == '':  # 当没有导入文件时直接退出程序
            sys.exit(0)
        if file_path != 'NoFileChosed':
            msg.showwarning(title='提示', message='请选择json文件!')
        default_dir = os.path.split(os.path.realpath(__file__))[0]  # 默认路径
        file_path = tk.filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser(default_dir)))  # 在默认路径中打开选择文件对话框
    with open(file_path, 'r', encoding='utf-8') as f:
        timu_list = json.load(f)
    whole_chapter_list = []
    whole_qtype_list = []
    # 统计该题库总共含有哪些题型和章节
    for timu in timu_list:
        if timu['chapter'] not in whole_chapter_list:
            whole_chapter_list.append(timu['chapter'])
        if timu['q_type'] not in whole_qtype_list:
            whole_qtype_list.append(timu['q_type'])

main_window = Tk()
main_window.title('背题助手')
main_window.geometry('600x450')
qtype_meaning = ['选择', '填空', '判断']

choose_file()

在这里题库的格式可以根据自己的习惯设定。我个人是先将题库录入成json文件然后导入。追求整体性的朋友可以用正则等方法直接导入word文件分析。
json文件的大致范式如下(仅抽取几道题):

[
  {"chapter": "1", "q_type": "1", "content": {"title": "新石器时期,标志着人类开始通过化学变化改变材料特性的创造性活动,也标志着人类手工艺设计阶段的开端的发明是( )。", "opt_a": "瓷器", "opt_b": "青铜器", "opt_c": "陶器", "opt_d": "漆器", "ans": "C"}},
  {"chapter": "1", "q_type": "2", "content": {"title": "人类设计活动的历史大体可以划分为三个阶段,即设计的萌芽阶段、手工艺设计阶段和____阶段。", "ans": "工业设计"}},
  {"chapter": "4", "q_type": "3", "content": {"title": "英国的机械化首先开始于纺织业。", "ans": "A", "correct": ""}},
  {"chapter": "4", "q_type": "3", "content": {"title": "纸张的模数化始于美国。", "ans": "B", "correct": "德国"}}
]

其中chapter代表章节,q_type为题型,1、2、3分别对应选择、填空、判断。content里录入题目具体内容,如题面、选项、答案等信息。
获得这些信息以后,就可以在main函数内继续部署进入页面的一些控件并开始进入mainloop了。

# 续main函数
label_welcome = Label(main_window, text='请选择题型与章节!', font=('宋体', 14, 'bold'), relief='solid')
qtype_checkbutton_list = []
qtype_var_list = []
qtype_chosed_list = []
chapter_checkbutton_list = []
chapter_var_list = []
chapter_chosed_list = []
entry_ok_button = Button(main_window, text='确认', command=entry_out)
all_chapter_button = Button(main_window, text='章节全选', command=entry_out_all_chapter)
for i in range(len(whole_qtype_list)):
    qtype_var_list.append(IntVar())
    qtype_checkbutton_list.append(Checkbutton(main_window, text=qtype_meaning[int(whole_qtype_list[i]) - 1],
                                              variable=qtype_var_list[i], onvalue=1, offvalue=0))
for i in range(len(whole_chapter_list)):
    chapter_var_list.append(IntVar())
    chapter_checkbutton_list.append(Checkbutton(main_window, text=shuwei(int(whole_chapter_list[i]), ' ', 2, 'back'),
                                                variable=chapter_var_list[i], onvalue=1, offvalue=0))

entry_in()
main_window.mainloop()

在mainloop之前有一个entry_in函数和一个shuwei函数。entry_in的作用在于将选择页面的控件(包含题型、章节的复选框和两个“下一步”按钮)部署到窗口。代码如下

def entry_in():
    label_welcome.place(relwidth=0.5, relheight=0.1, relx=0.25, rely=0.05)
    entry_ok_button.place(relwidth=0.15, relheight=0.08, relx=0.25, rely=0.85)
    all_chapter_button.place(relwidth=0.15, relheight=0.08, relx=0.6, rely=0.85)
    for i in range(len(whole_qtype_list)):
        qtype_checkbutton_list[i].place(relwidth=0.2, relx=0.2, rely=0.2 + i * 0.05)
    for i in range(len(whole_chapter_list)):
        chapter_checkbutton_list[i].place(relwidth=0.2, relx=0.6, rely=0.2 + i * 0.05)

效果就像这样
python项目实践--基于TKinter给读文科的ta写一个背题助手!_第1张图片
entry界面示意图

shuwei函数其实是懒得对不同长度章节编号细致排版,直接拿空格占位达到对其效果。代码如下

def shuwei(num, character, weishu, side):
    append_text = ''
    for i in range(weishu - len(str(num))):
        append_text = append_text + character
    if side == 'front':
        return append_text + str(num)
    elif side == 'back':
        return str(num) + append_text

entry界面的两个button“确认”和“章节全选”,分别对应了手动选择题型、章节和手动选择题型以后生成子题目池。对应的command分别是entry_out和entry_out_all_chapter,代码如下

def entry_out():
    global chosed_timu
    for i in range(len(whole_qtype_list)):
        if qtype_var_list[i].get() == 1 and whole_qtype_list[i] not in qtype_chosed_list:
            qtype_chosed_list.append(whole_qtype_list[i])
        elif qtype_var_list[i].get() == 0 and whole_qtype_list[i] in qtype_chosed_list:
            qtype_chosed_list.remove(whole_qtype_list[i])
    for i in range(len(whole_chapter_list)):
        if chapter_var_list[i].get() == 1 and whole_chapter_list[i] not in chapter_chosed_list:
            chapter_chosed_list.append(whole_chapter_list[i])
        elif chapter_var_list[i].get() == 0 and whole_chapter_list[i] in chapter_chosed_list:
            chapter_chosed_list.remove(whole_chapter_list[i])
    if qtype_chosed_list != [] and chapter_chosed_list == []:
        msg.showwarning(title='提示', message='请选择章节!')
        return
    elif chapter_chosed_list != [] and qtype_chosed_list == []:
        msg.showwarning(title='提示', message='请选择题型!')
        return
    elif chapter_chosed_list == [] and qtype_chosed_list == []:
        msg.showwarning(title='提示', message='请选择题型和章节!')
        return
    elif get_question(qtype_chosed_list, chapter_chosed_list) == []:
        msg.showwarning(title='提示', message='此种组合无题目!')
        return
    else:
        label_welcome.place_forget()
        entry_ok_button.place_forget()
        all_chapter_button.place_forget()
        for i in range(len(whole_qtype_list)):
            qtype_checkbutton_list[i].place_forget()
        for i in range(len(whole_chapter_list)):
            chapter_checkbutton_list[i].place_forget()
        chosed_timu = get_question(qtype_chosed_list, chapter_chosed_list)
    random_timu()


def entry_out_all_chapter():
    global chosed_timu
    for i in range(len(whole_qtype_list)):
        if qtype_var_list[i].get() == 1 and whole_qtype_list[i] not in qtype_chosed_list:
            qtype_chosed_list.append(whole_qtype_list[i])
        elif qtype_var_list[i].get() == 0 and whole_qtype_list[i] in qtype_chosed_list:
            qtype_chosed_list.remove(whole_qtype_list[i])
    chapter_chosed_list = whole_chapter_list
    if qtype_chosed_list == []:
        msg.showwarning(title='提示', message='请选择题型!')
        return
    elif get_question(qtype_chosed_list, chapter_chosed_list) == []:
        msg.showwarning(title='提示', message='此种组合无题目!')
        return
    else:
        label_welcome.place_forget()
        entry_ok_button.place_forget()
        all_chapter_button.place_forget()
        for i in range(len(whole_qtype_list)):
            qtype_checkbutton_list[i].place_forget()
        for i in range(len(whole_chapter_list)):
            chapter_checkbutton_list[i].place_forget()
        chosed_timu = get_question(qtype_chosed_list, chapter_chosed_list)
    random_timu()

这两个函数内都有将entry界面控件forget的相关函数,为下一界面腾出空间。在最后均有一个get_question函数,作用是找到对应题型和章节的题目,生成一个子列表。代码如下

def get_question(qtype_chosed_list, chapter_chosed_list):
    question_chosed_list = []
    for timu in timu_list:
        if timu['q_type'] in qtype_chosed_list and timu['chapter'] in chapter_chosed_list:
            question_chosed_list.append(timu)
    return question_chosed_list

在entry_out和entry_out_all_chapter的最后调用了random_timu函数,作用是从子题目池中pop出一个,代码如下

def random_timu():
    global chosed_timu, random_question
    if chosed_timu == []:
        question_empty()
        return
    random_num = random.randint(0, len(chosed_timu) - 1)
    random_question = chosed_timu.pop(random_num)
    if random_question['q_type'] == '1':
        xuanze_on()
    elif random_question['q_type'] == '2':
        tiankong_on()
    elif random_question['q_type'] == '3':
        panduan_on()

接下来的循环,节点都是这个random_timu函数。以随机到选择题为例。进入xuanze_on函数,部署相关控件,代码如下

def xuanze_on():
    global label_answer, var_option, label_question, option_a, option_b, option_c, option_d
    label_question = Label(main_window, text=lingqiyihang(random_question['content']['title'], 38),
                           anchor='w', justify='left')
    var_option = StringVar()
    option_a = Radiobutton(main_window, text='A. ' + random_question['content']['opt_a'],
                           anchor='w', variable=var_option, value='a', command=xuanze_1)
    option_b = Radiobutton(main_window, text='B. ' + random_question['content']['opt_b'],
                           anchor='w', variable=var_option, value='b', command=xuanze_1)
    option_c = Radiobutton(main_window, text='C. ' + random_question['content']['opt_c'],
                           anchor='w', variable=var_option, value='c', command=xuanze_1)
    option_d = Radiobutton(main_window, text='D. ' + random_question['content']['opt_d'],
                           anchor='w', variable=var_option, value='d', command=xuanze_1)
    label_question.place(relwidth=0.8, relheight=0.3, relx=0.1, rely=0.05)
    option_a.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.35)
    option_b.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.4)
    option_c.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.45)
    option_d.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.5)

该函数部署了题面文本框和四个选项的单选按钮。题面文本框中有一个lingqiyihang函数,作用是对给定的num,将字符串每num个字另起一行。代码如下

def lingqiyihang(text, num):
    sth_list = []
    while len(text) > num:
        sth = text[:num]
        text = text[num:]
        sth_list.append(sth)
    return '\n'.join(sth_list) + '\n' + text

而四个按钮触发的command为entry_1,该函数将选项按钮forget,改为文本控件,并根据选择错误与否显示“答对了”或“选项是X”,代码如下

def xuanze_1():
    global next_button, label_answer, option_a_text, option_b_text, option_c_text, option_d_text
    option_a.place_forget()
    option_b.place_forget()
    option_c.place_forget()
    option_d.place_forget()
    option_a_text = Label(main_window, text='     A. ' + random_question['content']['opt_a'], anchor='w')
    option_b_text = Label(main_window, text='     B. ' + random_question['content']['opt_b'], anchor='w')
    option_c_text = Label(main_window, text='     C. ' + random_question['content']['opt_c'], anchor='w')
    option_d_text = Label(main_window, text='     D. ' + random_question['content']['opt_d'], anchor='w')
    option_a_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.352)
    option_b_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.4)
    option_c_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.452)
    option_d_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.5)
    if var_option.get() != random_question['content']['ans'].lower():
        label_answer = Label(main_window, text='答案是: ' + random_question['content']['ans'].upper(), anchor='w')
    else:
        label_answer = Label(main_window, text='答对了w', anchor='w')
    label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.65)
    next_button = Button(main_window, text='下一题', command=xuanze_off)
    next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)

点击此时产生页面的“下一步”按钮,将会触发xuanze_off函数,代码如下

def xuanze_off():
    label_question.place_forget()
    option_a_text.place_forget()
    option_b_text.place_forget()
    option_c_text.place_forget()
    option_d_text.place_forget()
    label_answer.place_forget()
    next_button.place_forget()
    random_timu()

这个函数将页面上剩余所有控件forget,并且回到random_timu函数中。选择题界面的效果如下


python项目实践--基于TKinter给读文科的ta写一个背题助手!_第2张图片
选择题选项页面

python项目实践--基于TKinter给读文科的ta写一个背题助手!_第3张图片
选择题答错时触发的效果

python项目实践--基于TKinter给读文科的ta写一个背题助手!_第4张图片
选择题答对时触发的效果

填空和判断题界面的设计思路跟选择题并无二异。代码如下

def tiankong_on():
    global label_question, answer_get, label_question, answer_sheet, answer_get_button
    label_question = Label(main_window, text=lingqiyihang(random_question['content']['title'], 38) + '\n\n请输入答案:',
                           anchor='w', justify='left')
    answer_get = StringVar()
    answer_sheet = Entry(main_window, show=None, textvariable=answer_get)
    answer_get_button = Button(main_window, text='提交', command=tiankong_1)
    label_question.place(relwidth=0.8, relheight=0.25, relx=0.1, rely=0.05)
    answer_sheet.place(relwidth=0.45, relx=0.1, rely=0.3)
    answer_get_button.place(relwidth=0.1, relheight=0.06, relx=0.6, rely=0.295)


def tiankong_1():
    global label_answer, next_button, answer_print
    answer_get_button.place_forget()
    answer_sheet.place_forget()
    if answer_get.get() == random_question['content']['ans'].lower():
        label_answer = Label(main_window, text='答对了w', anchor='w')
    else:
        label_answer = Label(main_window, text='答案是: ' + random_question['content']['ans'], anchor='w')
    answer_print = Label(main_window, text=answer_get.get(), anchor='w')
    answer_print.place(relwidth=0.45, relx=0.1, rely=0.298)
    label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.65)
    next_button = Button(main_window, text='下一题', command=tiankong_off)
    next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)


def tiankong_off():
    label_answer.place_forget()
    next_button.place_forget()
    label_question.place_forget()
    answer_print.place_forget()
    random_timu()


def panduan_on():
    global label_question, var_option, option_a, option_b
    label_question = Label(main_window, text=lingqiyihang(random_question['content']['title'], 38) + '\n\n请选择正误:',
                           anchor='w', justify='left')
    var_option = StringVar()
    option_a = Radiobutton(main_window, text='正确',
                           anchor='w', variable=var_option, value='a', command=panduan_1)
    option_b = Radiobutton(main_window, text='错误',
                           anchor='w', variable=var_option, value='b', command=panduan_1)
    label_question.place(relwidth=0.8, relheight=0.3, relx=0.1, rely=0.05)
    option_a.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.3)
    option_b.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.35)


def panduan_1():
    global label_answer, next_button, answer_get, answer_sheet, answer_get_button, option_a_text, option_b_text
    option_a.place_forget()
    option_b.place_forget()
    option_a_text = Label(main_window, text='     正确', anchor='w')
    option_b_text = Label(main_window, text='     错误', anchor='w')
    option_a_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.3)
    option_b_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.352)
    if var_option.get() == 'a' and random_question['content']['ans'].lower() == 'a':
        label_answer = Label(main_window, text='答对了w', anchor='w')
        next_button = Button(main_window, text='下一题', command=panduan_off_1)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)
    elif var_option.get() == 'a' and random_question['content']['ans'].lower() == 'b':
        label_answer = Label(main_window, text='答案是:错误    请输入改正意见:', anchor='w')
        answer_get = StringVar()
        answer_sheet = Entry(main_window, show=None, textvariable=answer_get)
        answer_get_button = Button(main_window, text='提交', command=panduan_2)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        answer_sheet.place(relwidth=0.45, relx=0.1, rely=0.5)
        answer_get_button.place(relwidth=0.1, relheight=0.06, relx=0.6, rely=0.495)
    elif var_option.get() == 'b' and random_question['content']['ans'].lower() == 'a':
        label_answer = Label(main_window, text='答案是:正确', anchor='w')
        next_button = Button(main_window, text='下一题', command=panduan_off_1)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)
    elif var_option.get() == 'b' and random_question['content']['ans'].lower() == 'b':
        label_answer = Label(main_window, text='答对了w    请输入改正意见:', anchor='w')
        answer_get = StringVar()
        answer_sheet = Entry(main_window, show=None, textvariable=answer_get)
        answer_get_button = Button(main_window, text='提交', command=panduan_2)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        answer_sheet.place(relwidth=0.45, relx=0.1, rely=0.5)
        answer_get_button.place(relwidth=0.1, relheight=0.06, relx=0.6, rely=0.495)


def panduan_off_1():
    label_question.place_forget()
    option_a_text.place_forget()
    option_b_text.place_forget()
    label_answer.place_forget()
    next_button.place_forget()
    random_timu()


def panduan_2():
    global label_answer_2, answer_print, next_button
    answer_get_button.place_forget()
    answer_sheet.place_forget()
    answer_print = Label(main_window, text=answer_get.get(), anchor='w')
    if answer_get.get() == random_question['content']['correct'].lower():
        label_answer_2 = Label(main_window, text='答对了w', anchor='w')
    else:
        label_answer_2 = Label(main_window, text='答案是: ' + random_question['content']['correct'], anchor='w')
    next_button = Button(main_window, text='下一题', command=panduan_off_2)
    answer_print.place(relwidth=0.45, relx=0.1, rely=0.498)
    label_answer_2.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.65)
    next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)


def panduan_off_2():
    label_question.place_forget()
    option_a_text.place_forget()
    option_b_text.place_forget()
    label_answer.place_forget()
    next_button.place_forget()
    answer_print.place_forget()
    next_button.place_forget()
    label_answer_2.place_forget()
    random_timu()

界面效果图如下


python项目实践--基于TKinter给读文科的ta写一个背题助手!_第5张图片
填空题界面
python项目实践--基于TKinter给读文科的ta写一个背题助手!_第6张图片
判断题界面

当回到random_question函数时,如果子题目池内已经没有题目,那么将触发question_empty函数,代码和效果如下

def question_empty():
    msg.showwarning(title='提示', message='所有题目都已做完!')
    entry_in()
python项目实践--基于TKinter给读文科的ta写一个背题助手!_第7张图片
子题目池已空

点击确定后将触发entry_in函数,回到entry界面。

好啦~ 算是大功告成等着女朋友的夸奖啦~ 用pyinstaller生成一个可双击执行的exe文件,连同题库的json文件一起发给她就完事了~

最后自我总结一下,作为一个自学python的小白,在设计的过程中感觉自己学到了很多,并且成品出来以后内心非常有成就感。但回过头来看好像代码还是过于凌乱、冗长了一些,变量名的命名也相当...放飞自我,呵呵~

希望各位在参考过程中包容我的不足,毕竟是我的第一个完整的小项目,虽然说不上多高大上,但也算是我成长过程中小小的一步吧。有任何意见、建议或者疑问都可以在评论区或简信中告诉我。要是能留下一个大大的赞那就太感激不过了~

完整代码(因为一开始偷懒了所以并没有定义main函数而是直接开写的,以后会注意):

# /usr/bin/python3
# -*- coding:utf-8 -*-
import tkinter as tk
import tkinter.messagebox as msg
import tkinter.filedialog as fd
from tkinter import *
import json
import random
import os
import sys


def shuwei(num, character, weishu, side):
    append_text = ''
    for i in range(weishu - len(str(num))):
        append_text = append_text + character
    if side == 'front':
        return append_text + str(num)
    elif side == 'back':
        return str(num) + append_text


def get_question(qtype_chosed_list, chapter_chosed_list):
    question_chosed_list = []
    for timu in timu_list:
        if timu['q_type'] in qtype_chosed_list and timu['chapter'] in chapter_chosed_list:
            question_chosed_list.append(timu)
    return question_chosed_list


def lingqiyihang(text, num):
    sth_list = []
    while len(text) > num:
        sth = text[:num]
        text = text[num:]
        sth_list.append(sth)
    return '\n'.join(sth_list) + '\n' + text


def question_empty():
    msg.showwarning(title='提示', message='所有题目都已做完!')
    entry_in()


def choose_file():
    global timu_list, whole_chapter_list, whole_qtype_list
    file_path = 'NoFileChosed'
    while file_path[-5:] != '.json':
        if file_path == '':
            sys.exit(0)
        if file_path != 'NoFileChosed':
            msg.showwarning(title='提示', message='请选择json文件!')
        default_dir = os.path.split(os.path.realpath(__file__))[0]
        file_path = tk.filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser(default_dir)))
    with open(file_path, 'r', encoding='utf-8') as f:
        timu_list = json.load(f)
    whole_chapter_list = []
    whole_qtype_list = []
    for timu in timu_list:
        if timu['chapter'] not in whole_chapter_list:
            whole_chapter_list.append(timu['chapter'])
        if timu['q_type'] not in whole_qtype_list:
            whole_qtype_list.append(timu['q_type'])


def entry_in():
    label_welcome.place(relwidth=0.5, relheight=0.1, relx=0.25, rely=0.05)
    entry_ok_button.place(relwidth=0.15, relheight=0.08, relx=0.25, rely=0.85)
    all_chapter_button.place(relwidth=0.15, relheight=0.08, relx=0.6, rely=0.85)
    for i in range(len(whole_qtype_list)):
        qtype_checkbutton_list[i].place(relwidth=0.2, relx=0.2, rely=0.2 + i * 0.05)
    for i in range(len(whole_chapter_list)):
        chapter_checkbutton_list[i].place(relwidth=0.2, relx=0.6, rely=0.2 + i * 0.05)


def entry_out():
    global chosed_timu
    for i in range(len(whole_qtype_list)):
        if qtype_var_list[i].get() == 1 and whole_qtype_list[i] not in qtype_chosed_list:
            qtype_chosed_list.append(whole_qtype_list[i])
        elif qtype_var_list[i].get() == 0 and whole_qtype_list[i] in qtype_chosed_list:
            qtype_chosed_list.remove(whole_qtype_list[i])
    for i in range(len(whole_chapter_list)):
        if chapter_var_list[i].get() == 1 and whole_chapter_list[i] not in chapter_chosed_list:
            chapter_chosed_list.append(whole_chapter_list[i])
        elif chapter_var_list[i].get() == 0 and whole_chapter_list[i] in chapter_chosed_list:
            chapter_chosed_list.remove(whole_chapter_list[i])
    if qtype_chosed_list != [] and chapter_chosed_list == []:
        msg.showwarning(title='提示', message='请选择章节!')
        return
    elif chapter_chosed_list != [] and qtype_chosed_list == []:
        msg.showwarning(title='提示', message='请选择题型!')
        return
    elif chapter_chosed_list == [] and qtype_chosed_list == []:
        msg.showwarning(title='提示', message='请选择题型和章节!')
        return
    elif get_question(qtype_chosed_list, chapter_chosed_list) == []:
        msg.showwarning(title='提示', message='此种组合无题目!')
        return
    else:
        label_welcome.place_forget()
        entry_ok_button.place_forget()
        all_chapter_button.place_forget()
        for i in range(len(whole_qtype_list)):
            qtype_checkbutton_list[i].place_forget()
        for i in range(len(whole_chapter_list)):
            chapter_checkbutton_list[i].place_forget()
        chosed_timu = get_question(qtype_chosed_list, chapter_chosed_list)
    random_timu()


def entry_out_all_chapter():
    global chosed_timu
    for i in range(len(whole_qtype_list)):
        if qtype_var_list[i].get() == 1 and whole_qtype_list[i] not in qtype_chosed_list:
            qtype_chosed_list.append(whole_qtype_list[i])
        elif qtype_var_list[i].get() == 0 and whole_qtype_list[i] in qtype_chosed_list:
            qtype_chosed_list.remove(whole_qtype_list[i])
    chapter_chosed_list = whole_chapter_list
    if qtype_chosed_list == []:
        msg.showwarning(title='提示', message='请选择题型!')
        return
    elif get_question(qtype_chosed_list, chapter_chosed_list) == []:
        msg.showwarning(title='提示', message='此种组合无题目!')
        return
    else:
        label_welcome.place_forget()
        entry_ok_button.place_forget()
        all_chapter_button.place_forget()
        for i in range(len(whole_qtype_list)):
            qtype_checkbutton_list[i].place_forget()
        for i in range(len(whole_chapter_list)):
            chapter_checkbutton_list[i].place_forget()
        chosed_timu = get_question(qtype_chosed_list, chapter_chosed_list)
    random_timu()


def random_timu():
    global chosed_timu, random_question
    if chosed_timu == []:
        question_empty()
        return
    random_num = random.randint(0, len(chosed_timu) - 1)
    random_question = chosed_timu.pop(random_num)
    if random_question['q_type'] == '1':
        xuanze_on()
    elif random_question['q_type'] == '2':
        tiankong_on()
    elif random_question['q_type'] == '3':
        panduan_on()


def xuanze_on():
    global label_answer, var_option, label_question, option_a, option_b, option_c, option_d
    label_question = Label(main_window, text=lingqiyihang(random_question['content']['title'], 38),
                           anchor='w', justify='left')
    var_option = StringVar()
    option_a = Radiobutton(main_window, text='A. ' + random_question['content']['opt_a'],
                           anchor='w', variable=var_option, value='a', command=xuanze_1)
    option_b = Radiobutton(main_window, text='B. ' + random_question['content']['opt_b'],
                           anchor='w', variable=var_option, value='b', command=xuanze_1)
    option_c = Radiobutton(main_window, text='C. ' + random_question['content']['opt_c'],
                           anchor='w', variable=var_option, value='c', command=xuanze_1)
    option_d = Radiobutton(main_window, text='D. ' + random_question['content']['opt_d'],
                           anchor='w', variable=var_option, value='d', command=xuanze_1)
    label_question.place(relwidth=0.8, relheight=0.3, relx=0.1, rely=0.05)
    option_a.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.35)
    option_b.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.4)
    option_c.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.45)
    option_d.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.5)


def xuanze_1():
    global next_button, label_answer, option_a_text, option_b_text, option_c_text, option_d_text
    option_a.place_forget()
    option_b.place_forget()
    option_c.place_forget()
    option_d.place_forget()
    option_a_text = Label(main_window, text='     A. ' + random_question['content']['opt_a'], anchor='w')
    option_b_text = Label(main_window, text='     B. ' + random_question['content']['opt_b'], anchor='w')
    option_c_text = Label(main_window, text='     C. ' + random_question['content']['opt_c'], anchor='w')
    option_d_text = Label(main_window, text='     D. ' + random_question['content']['opt_d'], anchor='w')
    option_a_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.352)
    option_b_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.4)
    option_c_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.452)
    option_d_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.5)
    if var_option.get() != random_question['content']['ans'].lower():
        label_answer = Label(main_window, text='答案是: ' + random_question['content']['ans'].upper(), anchor='w')
    else:
        label_answer = Label(main_window, text='答对了w', anchor='w')
    label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.65)
    next_button = Button(main_window, text='下一题', command=xuanze_off)
    next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)


def xuanze_off():
    label_question.place_forget()
    option_a_text.place_forget()
    option_b_text.place_forget()
    option_c_text.place_forget()
    option_d_text.place_forget()
    label_answer.place_forget()
    next_button.place_forget()
    random_timu()


def tiankong_on():
    global label_question, answer_get, label_question, answer_sheet, answer_get_button
    label_question = Label(main_window, text=lingqiyihang(random_question['content']['title'], 38) + '\n\n请输入答案:',
                           anchor='w', justify='left')
    answer_get = StringVar()
    answer_sheet = Entry(main_window, show=None, textvariable=answer_get)
    answer_get_button = Button(main_window, text='提交', command=tiankong_1)
    label_question.place(relwidth=0.8, relheight=0.25, relx=0.1, rely=0.05)
    answer_sheet.place(relwidth=0.45, relx=0.1, rely=0.3)
    answer_get_button.place(relwidth=0.1, relheight=0.06, relx=0.6, rely=0.295)


def tiankong_1():
    global label_answer, next_button, answer_print
    answer_get_button.place_forget()
    answer_sheet.place_forget()
    if answer_get.get() == random_question['content']['ans'].lower():
        label_answer = Label(main_window, text='答对了w', anchor='w')
    else:
        label_answer = Label(main_window, text='答案是: ' + random_question['content']['ans'], anchor='w')
    answer_print = Label(main_window, text=answer_get.get(), anchor='w')
    answer_print.place(relwidth=0.45, relx=0.1, rely=0.298)
    label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.65)
    next_button = Button(main_window, text='下一题', command=tiankong_off)
    next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)


def tiankong_off():
    label_answer.place_forget()
    next_button.place_forget()
    label_question.place_forget()
    answer_print.place_forget()
    random_timu()


def panduan_on():
    global label_question, var_option, option_a, option_b
    label_question = Label(main_window, text=lingqiyihang(random_question['content']['title'], 38) + '\n\n请选择正误:',
                           anchor='w', justify='left')
    var_option = StringVar()
    option_a = Radiobutton(main_window, text='正确',
                           anchor='w', variable=var_option, value='a', command=panduan_1)
    option_b = Radiobutton(main_window, text='错误',
                           anchor='w', variable=var_option, value='b', command=panduan_1)
    label_question.place(relwidth=0.8, relheight=0.3, relx=0.1, rely=0.05)
    option_a.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.3)
    option_b.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.35)


def panduan_1():
    global label_answer, next_button, answer_get, answer_sheet, answer_get_button, option_a_text, option_b_text
    option_a.place_forget()
    option_b.place_forget()
    option_a_text = Label(main_window, text='     正确', anchor='w')
    option_b_text = Label(main_window, text='     错误', anchor='w')
    option_a_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.3)
    option_b_text.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.352)
    if var_option.get() == 'a' and random_question['content']['ans'].lower() == 'a':
        label_answer = Label(main_window, text='答对了w', anchor='w')
        next_button = Button(main_window, text='下一题', command=panduan_off_1)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)
    elif var_option.get() == 'a' and random_question['content']['ans'].lower() == 'b':
        label_answer = Label(main_window, text='答案是:错误    请输入改正意见:', anchor='w')
        answer_get = StringVar()
        answer_sheet = Entry(main_window, show=None, textvariable=answer_get)
        answer_get_button = Button(main_window, text='提交', command=panduan_2)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        answer_sheet.place(relwidth=0.45, relx=0.1, rely=0.5)
        answer_get_button.place(relwidth=0.1, relheight=0.06, relx=0.6, rely=0.495)
    elif var_option.get() == 'b' and random_question['content']['ans'].lower() == 'a':
        label_answer = Label(main_window, text='答案是:正确', anchor='w')
        next_button = Button(main_window, text='下一题', command=panduan_off_1)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)
    elif var_option.get() == 'b' and random_question['content']['ans'].lower() == 'b':
        label_answer = Label(main_window, text='答对了w    请输入改正意见:', anchor='w')
        answer_get = StringVar()
        answer_sheet = Entry(main_window, show=None, textvariable=answer_get)
        answer_get_button = Button(main_window, text='提交', command=panduan_2)
        label_answer.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.42)
        answer_sheet.place(relwidth=0.45, relx=0.1, rely=0.5)
        answer_get_button.place(relwidth=0.1, relheight=0.06, relx=0.6, rely=0.495)


def panduan_off_1():
    label_question.place_forget()
    option_a_text.place_forget()
    option_b_text.place_forget()
    label_answer.place_forget()
    next_button.place_forget()
    random_timu()


def panduan_2():
    global label_answer_2, answer_print, next_button
    answer_get_button.place_forget()
    answer_sheet.place_forget()
    answer_print = Label(main_window, text=answer_get.get(), anchor='w')
    if answer_get.get() == random_question['content']['correct'].lower():
        label_answer_2 = Label(main_window, text='答对了w', anchor='w')
    else:
        label_answer_2 = Label(main_window, text='答案是: ' + random_question['content']['correct'], anchor='w')
    next_button = Button(main_window, text='下一题', command=panduan_off_2)
    answer_print.place(relwidth=0.45, relx=0.1, rely=0.498)
    label_answer_2.place(relwidth=0.8, relheight=0.05, relx=0.1, rely=0.65)
    next_button.place(relwidth=0.15, relheight=0.08, relx=0.425, rely=0.85)


def panduan_off_2():
    label_question.place_forget()
    option_a_text.place_forget()
    option_b_text.place_forget()
    label_answer.place_forget()
    next_button.place_forget()
    answer_print.place_forget()
    next_button.place_forget()
    label_answer_2.place_forget()
    random_timu()


main_window = Tk()
main_window.title('背题助手')
main_window.geometry('600x450')
qtype_meaning = ['选择', '填空', '判断']

choose_file()

label_welcome = Label(main_window, text='请选择题型与章节!', font=('宋体', 14, 'bold'), relief='solid')
qtype_checkbutton_list = []
qtype_var_list = []
qtype_chosed_list = []
chapter_checkbutton_list = []
chapter_var_list = []
chapter_chosed_list = []
entry_ok_button = Button(main_window, text='确认', command=entry_out)
all_chapter_button = Button(main_window, text='章节全选', command=entry_out_all_chapter)
for i in range(len(whole_qtype_list)):
    qtype_var_list.append(IntVar())
    qtype_checkbutton_list.append(Checkbutton(main_window, text=qtype_meaning[int(whole_qtype_list[i]) - 1],
                                              variable=qtype_var_list[i], onvalue=1, offvalue=0))
for i in range(len(whole_chapter_list)):
    chapter_var_list.append(IntVar())
    chapter_checkbutton_list.append(Checkbutton(main_window, text=shuwei(int(whole_chapter_list[i]), ' ', 2, 'back'),
                                                variable=chapter_var_list[i], onvalue=1, offvalue=0))

entry_in()
main_window.mainloop()


你可能感兴趣的:(python项目实践--基于TKinter给读文科的ta写一个背题助手!)