当前位置:首页 » tkinter » 正文

用tkinter做一个简单的答题系统:单选题

答题系统设计及素材准备

今天来讲讲用tkinter做一个简单的答题系统:单选题。我们要先做一个单选题的题库才行,由于现在还没有学tkinter数据库相关知识,我决定先用一个txt的文本文件来做数据库。

txt格式的文本文件很好编辑,只要用电脑自带的记事本程序都可以打开。以下是我从我自己做的《驾照理论考试速成》软件提取出来的题库记录10条,都是单选题,第一行一条记录,各字段用英文逗号分割,字段从左到右分别是:

题目,选项1,选项2,选项3,选项4,正确答案,图片文件名

 

以下是题库内容,大家它保存为car1.txt,保存到你的代码目录里,这个txt文件编码保存为UTF-8 :

驾驶机动车在道路上违反道路交通安全法的行为,属于什么行为?,过失行为,违规行为,违章行为,违法行为,4,,
机动车驾驶人违法驾驶造成重大交通事故构成犯罪的,依法追究什么责任?,刑事责任,民事责任,直接责任,经济责任,1,,
机动车驾驶人造成事故后逃逸构成犯罪的,吊销驾驶证多长时间不得重新取得驾驶证?,5年内,10年内,20年内,终生,4,,
驾驶机动车应当随身携带哪种证件?,职业资格证,身份证,驾驶证,工作证,3,,
本篇文章的原创来自"五笔打字通"(网名),他的网站是:taobao.com,wb98.com,baidu.com,163.com,taobao.com,wb98.com,baidu.com,163.com,2,,
未取得驾驶证的学员在道路上学习驾驶技能,下列哪种做法是正确的?,使用所学车型的教练车由教练员随车指导,使用所学车型的教练车单独驾驶学习,使用所学车型的教练车由非教练员的驾驶人随车指导,使用私家车由教练员随车指导,1,,
机动车驾驶人初次申领驾驶证后的实习期是多长时间?,18个月,16个月,12个月,6个月,3,,
在实习期内驾驶机动车的,应当在车身后部粘贴或者悬挂哪种标志?,注意避让标志,注意新手标志,统一样式的实习标志,注意车距标志,3,,
驾驶机动车在路口直行遇到这种信号灯应该怎样行驶?,不得越过停止线,加速直行通过,左转弯行驶,进入路口等待,1,car_1.gif,
以欺骗、贿赂等不正当手段取得驾驶证被依法撤销驾驶许可的,多长时间不得重新申请驾驶许可?,3年内,终身,1年内,5年内,1,,

  保存好上面的数据库文件car1.txt后,我们还要准备3个图片,1 是第9条记录里要准备的car_1.gif图片,另外还要准备打勾(对)和打叉(错)的图片,以下就是3个图片,大家把它们保存文件名为car_1.gif ,  d.png ,  c.png 保存目录为编程文件目录下的imgae目录下。

car.gif

d.png     c.png

 

准备好以上资料和素材,我们开始编程,由于只是做一个简单的答题系统,所以,我只要我的程序达到以下功能:

 1.显示题目内容和相关图片

 2.点击选项显示对错

 3.上一题和下一题可以循环显示题目

大家有兴趣可以再增加统计对,错次数,打分等各种功能。

我编写的程序“单选题”答题系统做成后的界面如下所示:

1.JPG

如果题目有相关图片,这个图片插在题目和答案选项之间。如下图

202111111104034631639.jpg

1. 上面的界面用pack或grid都可以布局定位,我所以采取grid方法。除了最后2个按钮,即上一题和下一题,分别占有第1列和第2列,其它如题目,图片,答案都是跨占2列。

2. 题目,我们从数据库提取后,在前面加序号后,再显示;4个答案,我们提取后,加A. B. C. D. 后再显示。

tkinter答题系统(单选题)的界面代码

我们首先来做界面代码:

1. 先读取数据库文件 car.txt ,注意自己保存的编码,我是

保存为utf-8 , 数据库的记录不多,只有10条,我用readlines()方法读取全部文件,每一行为一个列表,我再用英英逗号用split方法分割为str1[0],str[1]…… ,分别是题目,选项1,选项2……答案,图片名。

如果图片是空,那就用 PhotoImage() 创建空图片对象。

2. 题目内容,str1[0],用标签1,la1来显示

相关图片,str1[6],用标签2,la2来显示

选项1,str1[1],用单选按钮1,ra1来显示

选项2,str1[2],用单选按钮1,ra1来显示

选项3,str1[3],用单选按钮1,ra1来显示

选项4,str1[4],用单选按钮1,ra1来显示

正确答案,str1[5],当鼠标点击各选项按钮时,在pddc函数里来判断对错,对的,在答案后面显示红勾的图片,错的,在答案选项后面显示蓝色的X

 

下面是显示的代码,都有注释,如果不明白,可能你要回过头去看看以前的文章以及加强python基本知识了。

from tkinter import *
 
def next():  # 下一题
    pass
def previous():  # 上一题
    pass
def display():  # 界面题目,答案等显示
    pass
def pddc():  # 点击选项,判断对错
    pass
 
root = Tk()
 
with open('car1.txt', 'r', encoding='utf-8') as file:  # 只读方式打开编码为utf-8的文本文件
    number = 0  # 文本文件中的行号
    line = file.readlines()  # 以读取一行为列表方法读取全部行,line为分解好的列表内容
    str1 = line[0].split(',')  # 以英文,号来分解第1行,获取题目,答案1,答案2......
 
# str1[0]:题目  str1[1]:选项1  str1[2]:选项2  str1[3]:选项3  str1[4]:选项4
# str1[5]:答案  str1[6]:图片名
 
id = str(number+1)+". "  # 题目序号 来自wb98.c0m何老师的济亨网
la1 = Label(root, text=id+str1[0], justify="left",
            anchor=W, wraplength=500)  # 题目,靠左,多行左对齐,像素500换行
la1.grid(padx=10, pady=2, sticky=W+E, columnspan=2)
 
if str1[6] == '':
    img1 = PhotoImage()  # 没有相关图片
else:
    img1 = PhotoImage(file='.\\image\\'+str1[6])  # 图片是在安装目录下的image文件夹里
 
la2 = Label(root, image=img1)  # 标签2用于显示题目相关的图片
la2.grid(padx=10, columnspan=2)
 
var = IntVar() # 创建整型变量
 
ra1 = Radiobutton(root, text='A. ' + str1[1], variable=var,
                  value=1, justify="left", wraplength=430, command=pddc)  # 选项1,靠左,多行左对齐,460像素换行
ra1.grid(padx=10, sticky=W, columnspan=2)
 
ra2 = Radiobutton(root, text='B. ' + str1[2], variable=var,
                  value=2, justify="left", wraplength=430, command=pddc)  # 选项2,靠左,多行左对齐,460像素换行
ra2.grid(padx=10, sticky=W, columnspan=2)
 
ra3 = Radiobutton(root, text='C. ' + str1[3], variable=var,
                  value=3, justify="left", wraplength=430, command=pddc)  # 选项3,靠左,多行左对齐,460像素换行
ra3.grid(padx=10, sticky=W, columnspan=2)
 
ra4 = Radiobutton(root, text='D. ' + str1[4], variable=var,
                  value=4, justify="left", wraplength=430, command=pddc)  # 选项4,靠左,多行左对齐,460像素换行
ra4.grid(padx=10, sticky=W, columnspan=2)
 
but1 = Button(root, text=" 上一题 ", command=previous)
but1.grid(row=6, column=0, sticky=E, pady=10)  # 7行1列,靠右,上下间距10像素
but2 = Button(root, text=" 下一题 ", command=next)
but2.grid(row=6, column=1, sticky=W, pady=10)  # 7行2列,靠左,上下间距10像素
 
img2 = PhotoImage(file='./image/d.png') # 打勾图对象
img3 = PhotoImage(file='./image/c.png') # 打X图对象
 
root.mainloop()


  运行后,显示还算正常,由于还没有写其它代码,暂时看不出有什么大的问题。说明一下:代码里题目里 wraplength=500,以及4个选项里 wraplength=430 ,是考虑到题目和答案都有可能是很多字符,要换行显示才好看,我反复测试题目500个像素换行比较好,答案选项由于后面要显示对错的图片,所以要小一些,取430像素就行了。

判断对错,下一题,下一题,显示函数

下面要写4个函数: 本文章作者:何云峰 网站 wb98.com

1. 点击“上一题”按钮要调用的previous函数,此函数,主要是序号累减,然后再去调用显示函数display函数;当序号累减到第一条记录前,就让序号回到最后一条记录的序号,以便循环显示。

2. 点击“下一题”按钮要调用的next函数,此函数,主要是序号累加,然后再去调用显示函数display函数;当序号累加到最后一条记录后,就让序号回到第一条记录的序号,以便循环显示。

3. 显示函数display,此函数根据序号,用line[序号]去读取记录,再用split(‘,’)来分割记录,分别得到题目,选项1,…… 答案,图片名。再根据以上得到的内容,再用config方法把显示内容更新一下。更新后,不要忘记用var.set(0)把勾选的选项取消掉,也用ra1.config(image=’’)方法把打对,打错的标志图片去除。还有一点也要注意,要函数前,把img1这个变量定义为全局变量,因为不这样做,图片可能就不会显示了。

4. 判断对错函数 pddc ,当我们用鼠标点击4个答案选项时,根据答案str1[5],判断对错,并用代码让对,错图片显示在答案选项的后面。在函数前,先初始化,把上一次点击时出现的对错图片先清除掉。注意,在函数前,也要把img2,img3这2个对错图片对象也要设置为全局变量,否则图片不会显示出来。

4个函数代码如下:

def next():  # 下一题
    global number
    number += 1
 
    if number + 1 > len(line):  # 说明到最后一条记录的后面
        number = 0  # 回到第1条记录
    display()
 
def previous():  # 上一题
    global number
    number -= 1
 
    if number == -1:  # 说明到了第1条记录的前面
        number = len(line)-1  # 回到最后1条记录
    display()
 
def display():  # 界面题目,答案等显示
    global img1, id, str1  # img1不定义为全局变量,图像可能无法显示
    id = str(number+1)+". "  # 序号
    str1 = line[number].split(',')  # 读取新一行记录
 
    la1.config(text=id+str1[0])  # 题目前面加序号
 
    if str1[6] == '':
        img1 = PhotoImage()  # 没有相关图片
    else:
        img1 = PhotoImage(file='.\\image\\'+str1[6])  # 图片是在安装目录下的image文件夹里
 
    la2.config(image=img1)  # 重新设置,根据str1[6]内容来改变图片
 
    ra1.config(text='A. '+str1[1])  # 答案1加上A.
    ra2.config(text='B. '+str1[2])  # 答案1加上B.
    ra3.config(text='C. '+str1[3])  # 答案1加上C.
    ra4.config(text='D. '+str1[4])  # 答案1加上D.
 
    var.set(0)  # 取消原来的选择
    ra1.config(image='')  # 初始,让勾、X图都消失
    ra2.config(image='')
    ra3.config(image='')
    ra4.config(image='')
 
def pddc():  # 点击选项,判断对错
    global img2, img3
 
    ra1.config(image='') # 初始,让勾、X图都消失
    ra2.config(image='')
    ra3.config(image='')
    ra4.config(image='')
 
    if var.get() == 1:  # 点击了选项1
        if str1[5] == '1':  # 答案是选项1
            ra1.config(image=img2, compound='right')  # 打勾
        else:
            ra1.config(image=img3, compound='right')  # 打X
    elif var.get() == 2:  # 点击了选项2
        if str1[5] == '2':  # 答案是选项2
            ra2.config(image=img2, compound='right')  # 打勾
        else:
            ra2.config(image=img3, compound='right')  # 打X
    elif var.get() == 3:  # 点击了选项3
        if str1[5] == '3':  # 答案是选项3
            ra3.config(image=img2, compound='right')  # 打勾
        else:
            ra3.config(image=img3, compound='right')  # 打X
    elif var.get() == 4:  # 点击了选项4
        if str1[5] == '4':  # 答案是选项4
            ra4.config(image=img2, compound='right')  # 打勾
        else:
            ra4.config(image=img3, compound='right')  # 打X

运行结果,4个函数都达到了目的,没有发现大的问题,只是显示有些问题,发现:如果题目只有1行文字时,界面会根据文字的多少,改变界面的宽度,“上一题”“下一题”这2个按钮也因此不能居中显示,我决定用下面2行代码来控制表格框的最小宽度。

root.columnconfigure(0, minsize=250) 
root.columnconfigure(1, minsize=250)

设置grid布局0列和1列的最小宽度,这样,就算是题目内容只有1行文字,不管多少文字,0列和1列,这2列表格框都有相同的宽度,这样,最下面2个按钮都可以居中显示,我再用root.winfo_width() 和      root.winfo_height() 得到当题目为2行显示时的窗体宽度和高度为525和230,我再用 root.minsize(525,230)  设置窗体的最小尺寸。同时,我用代码禁止手动调节窗体宽度和高度。

root.resizable(False, False)  # 禁止手动调节窗体尺寸

还有,我发现通过“上一题”“下一题”这2个按钮变换题目时,发现题目标签显示时,有跳动的情况,效果不好,我于是在标签1,即la1创建时,加入height=2 这个参数,反正题目都可以在2行内显示完,加入这个参数后,题目转换显示时,不会再出现跳动的情况出现了。     丶丌皛

tkinter答题系统(单选题)的最部代码

以下是全部代码,都有注释,如有什么意见和问题,也可以在下面的留言跟我沟通。

from tkinter import *
 
def next():  # 下一题
    global number
    number += 1
 
    if number + 1 > len(line):  # 说明到最后一条记录的后面
        number = 0  # 回到第1条记录
    display()
 
def previous():  # 上一题
    global number
    number -= 1
 
    if number == -1:  # 说明到了第1条记录的前面
        number = len(line)-1  # 回到最后1条记录
    display()
 
def display():  # 界面题目,答案等显示
    global img1, id, str1  # img1不定义为全局变量,图像可能无法显示
    id = str(number+1)+". "  # 序号
    str1 = line[number].split(',')  # 读取新一行记录
 
    la1.config(text=id+str1[0])  # 题目前面加序号
 
    if str1[6] == '':
        img1 = PhotoImage()  # 没有相关图片
    else:
        img1 = PhotoImage(file='.\\image\\'+str1[6])  # 图片是在安装目录下的image文件夹里
 
    la2.config(image=img1)  # 重新设置,根据str1[6]内容来改变图片
 
    ra1.config(text='A. '+str1[1])  # 答案1加上A.
    ra2.config(text='B. '+str1[2])  # 答案1加上B.
    ra3.config(text='C. '+str1[3])  # 答案1加上C.
    ra4.config(text='D. '+str1[4])  # 答案1加上D.
 
    var.set(0)  # 取消原来的选择
    ra1.config(image='')  # 初始,让勾、X图都消失
    ra2.config(image='')
    ra3.config(image='')
    ra4.config(image='')
 
def pddc():  # 点击选项,判断对错
    global img2, img3
 
    ra1.config(image='') # 初始,让勾、X图都消失
    ra2.config(image='')
    ra3.config(image='')
    ra4.config(image='')
 
    if var.get() == 1:  # 点击了选项1
        if str1[5] == '1':  # 答案是选项1
            ra1.config(image=img2, compound='right')  # 打勾
        else:
            ra1.config(image=img3, compound='right')  # 打X
    elif var.get() == 2:  # 点击了选项2
        if str1[5] == '2':  # 答案是选项2
            ra2.config(image=img2, compound='right')  # 打勾
        else:
            ra2.config(image=img3, compound='right')  # 打X
    elif var.get() == 3:  # 点击了选项3
        if str1[5] == '3':  # 答案是选项3
            ra3.config(image=img2, compound='right')  # 打勾
        else:
            ra3.config(image=img3, compound='right')  # 打X
    elif var.get() == 4:  # 点击了选项4
        if str1[5] == '4':  # 答案是选项4
            ra4.config(image=img2, compound='right')  # 打勾
        else:
            ra4.config(image=img3, compound='right')  # 打X
 
root = Tk()
root.title("单选题")
root.columnconfigure(0, minsize=250)  # 设置grid布局0列最小宽度
root.columnconfigure(1, minsize=250)  # 设置grid布局1列最小宽度
root.resizable(False, False)  # 禁止手动调节窗体尺寸
root.geometry('+666+444') # 设置窗体的位置
root.minsize(525,230) # 设置窗体宽与高的最小尺寸,这是无图片时窗体尺寸
 
with open('car1.txt', 'r', encoding='utf-8') as file:  # 只读方式打开编码为utf-8的文本文件
    number = 0  # 文本文件中的行号,即
    line = file.readlines()  # 以读取一行为列表方法读取全部行,line为分解好的列表内容
    str1 = line[0].split(',')  # 以英文,号来分解第1行,获取题目,答案1,答案2......
 
# str1[0]:题目  str1[1]:选项1  str1[2]:选项2  str1[3]:选项3  str1[4]:选项4
# str1[5]:答案  str1[6]:图片名
 
id = str(number+1)+". "  # 题目序号 来自wb98.c0m何老师的济亨网
la1 = Label(root, text=id+str1[0], justify="left", height=2,
            anchor=W, wraplength=500)  # 题目,靠左,多行左对齐,像素500换行
la1.grid(padx=10, pady=2, sticky=W+E, columnspan=2)
 
if str1[6] == '':
    img1 = PhotoImage()  # 没有相关图片
else:
    img1 = PhotoImage(file='.\\image\\'+str1[6])  # 图片是在安装目录下的image文件夹里
 
la2 = Label(root, image=img1)  # 标签2用于显示题目相关的图片
la2.grid(padx=10, columnspan=2)
 
var = IntVar()
 
ra1 = Radiobutton(root, text='A. ' + str1[1], variable=var,
                  value=1, justify="left", wraplength=430, command=pddc)  # 选项1,靠左,多行左对齐,460像素换行
ra1.grid(padx=10, sticky=W, columnspan=2)
 
ra2 = Radiobutton(root, text='B. ' + str1[2], variable=var,
                  value=2, justify="left", command=pddc)  # 选项2,靠左,多行左对齐,460像素换行
ra2.grid(padx=10, sticky=W, columnspan=2)
 
ra3 = Radiobutton(root, text='C. ' + str1[3], variable=var,
                  value=3, justify="left", command=pddc)  # 选项3,靠左,多行左对齐,460像素换行
ra3.grid(padx=10, sticky=W, columnspan=2)
 
ra4 = Radiobutton(root, text='D. ' + str1[4], variable=var,
                  value=4, justify="left", command=pddc)  # 选项4,靠左,多行左对齐,460像素换行
ra4.grid(padx=10, sticky=W, columnspan=2)
 
but1 = Button(root, text=" 上一题 ", command=previous)
but1.grid(row=6, column=0, sticky=E, pady=10)  # 7行1列,靠右,上下间距10像素
but2 = Button(root, text=" 下一题 ", command=next)
but2.grid(row=6, column=1, sticky=W, pady=10)  # 7行2列,靠左,上下间距10像素
 
img2 = PhotoImage(file='./image/d.png') # 打勾图对象
img3 = PhotoImage(file='./image/c.png') # 打X图对象
 
root.mainloop()

 

下一篇文章,wb98.com 我来讲讲我做的另外一个简单答题程序:多选题。


来源:济亨网

本文链接:http://wb98.com/post/310.html

    << 上一篇 下一篇 >>

    湘公网安备 43011102000514号 - 湘ICP备08100508号