五笔打字通主页
今天来讲讲用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目录下。
准备好以上资料和素材,我们开始编程,由于只是做一个简单的答题系统,所以,我只要我的程序达到以下功能:
1.显示题目内容和相关图片
2.点击选项显示对错
3.上一题和下一题可以循环显示题目
大家有兴趣可以再增加统计对,错次数,打分等各种功能。
我编写的程序“单选题”答题系统做成后的界面如下所示:
如果题目有相关图片,这个图片插在题目和答案选项之间。如下图
1. 上面的界面用pack或grid都可以布局定位,我所以采取grid方法。除了最后2个按钮,即上一题和下一题,分别占有第1列和第2列,其它如题目,图片,答案都是跨占2列。
2. 题目,我们从数据库提取后,在前面加序号后,再显示;4个答案,我们提取后,加A. B. C. D. 后再显示。
我们首先来做界面代码:
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行内显示完,加入这个参数后,题目转换显示时,不会再出现跳动的情况出现了。 丶丌皛
以下是全部代码,都有注释,如有什么意见和问题,也可以在下面的留言跟我沟通。
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 我来讲讲我做的另外一个简单答题程序:多选题。
来源:济亨网
本文链接:https://wb98.com/post/310.html