基于tkinter的随机答题小工具,附带详细的注释

通过pyinstaller可以编译为可执行的exe

pip install pyinstaller

以下命令将main.py编译为单个执行的exe

pyinstaller -F -w -i lg.ico main.py

需要一个lg.ico图标exe放到同级目录(编译后的dist文件夹)

还需要一个 end.wav声音文件(倒计时结束声音)放到同级目录

声音播放基于playsound

pip install playsound

以下为main.py源码 做了详细的注释:

"""
随机答题
读取excel表格中的问题与解析随机抽取
实现了重复随机|去重随机
实现了自动倒计时|手动倒计时
第三方库
excel操作PfExcel基于openpyxl由作者二次封装(上个博客中有介绍)
声音播放基于playsound
"""
from time import sleep
from random import randint
from threading import Thread
from tkinter import (Tk,Button,Toplevel,Menu,IntVar,filedialog,messagebox,DISABLED,Frame,StringVar,NORMAL,END,GROOVE,Entry)
from tkinter.scrolledtext import ScrolledTextfrom playsound import playsound
from PfExcel import ExcelWorkclass Window(Tk):def __init__(self):super().__init__()# 随机选项 0:不重复 | 1:重复self.repetitive = IntVar()self.repetitive.set(0)# 倒计时选项 0:手动 | 1:自动self.autoCountdown = IntVar()self.autoCountdown.set(1)# 倒计时运行状态self.countdownNow = False# 题库地址self.filePath = ''# 问题数据self.askList = []# 解析数据self.keyList = []# ui初始化self.guiInit()# 菜单栏self.menu()# 解析值self.keyValue = ''# 问题栏self.askTextObj = self.askText()# 倒计时数值self.countdownNum = 15# 倒计时按钮的标签值self.countdownStr = StringVar()# 设置倒计时按钮的标签值为倒计时self.countdownStr.set('倒计时')# 倒计时栏self.countdown()# 随机按钮的标签值self.randomStart = StringVar()# 设置随机随机按钮的标签值为开始self.randomStart.set('开始')# 控制栏self.control()def show(self):"""展示窗口:return:"""self.mainloop()def guiInit(self):"""主窗口初始化:return:"""# 窗口宽高width = 1200height = 810# 主屏幕宽高mainWidth = self.winfo_screenwidth()mainHeight = self.winfo_screenheight()# 设置窗口大小与显示位置self.geometry(f'{width}x{height}+{int((mainWidth - width) / 2)}+{int((mainHeight - height) / 2)}')# 禁止窗口缩放self.resizable(0, 0)# 标题self.title("随机答题")# 图标self.iconbitmap("lg.ico")def menu(self):"""菜单栏:return:"""menubar = Menu(self)# 操作operate = Menu(menubar, tearoff=0)menubar.add_cascade(label="操作", menu=operate)operate.add_command(label='选择题库', command=self.selectQb)operate.add_command(label='倒计时设置', command=self.setCountdownNum)operate.add_separator()operate.add_radiobutton(label='重复随机', variable=self.repetitive, value=1)operate.add_radiobutton(label='去重随机', variable=self.repetitive, value=0)operate.add_separator()operate.add_radiobutton(label='手动倒计时', variable=self.autoCountdown, value=0)operate.add_radiobutton(label='自动倒计时', variable=self.autoCountdown, value=1)# 关于about = Menu(menubar, tearoff=0)menubar.add_cascade(label='关于', menu=about)about.add_command(label='说明', command=self.explain)about.add_separator()about.add_command(label='作者', command=self.author)self.config(menu=menubar)def askText(self):"""问题栏:return: 问题栏文本框对象"""# 问题文本框s = ScrolledText(self,bg='Azure',width=38,height=8,font=('方正姚体', 40),state=DISABLED)s.pack(pady=20)return sdef countdown(self):"""倒计时栏:return:"""# 倒计时按钮Button(self,bg='Azure',fg='red',width=6,textvariable=self.countdownStr,font=('方正姚体', 30, 'bold'),relief=GROOVE,command=self.startCountdown).pack(pady=30)def control(self):"""控制栏:return:"""# 布局容器f = Frame(self)f.pack(pady=30)# 随机按钮Button(f,bg='Azure',textvariable=self.randomStart,font=('方正姚体', 25, 'bold'),command=self.randomAsk).grid(row=0, column=1, padx=50)# 解析按钮Button(f,bg='Azure',text='解析',font=('方正姚体', 25, 'bold'),command=self.showKey).grid(row=0, column=3, padx=50)####################################################################################################################def selectQb(self):"""选择题库获取题库数据:return:"""# 获取题库地址self.filePath = filedialog.askopenfilename()# 如果题库地址为空->提示失败if self.filePath == '':messagebox.showinfo('提示', '选择失败')else:# 提示成功messagebox.showinfo('提示', '选择成功')# 加载excelexcel = ExcelWork(self.filePath)# 获取excel第一列问题数据self.askList = excel.getColumn(1)# 获取excel第一列解析数据self.keyList = excel.getColumn(2)# 退出excel.close()def setCountdownNum(self):"""设置倒计时数值弹窗:return:"""# 设置主窗口不可操作self.attributes("-disabled", 1)# 弹窗t = Toplevel(self)# 弹窗宽高width = 300height = 150# 获取主屏幕宽高mainWidth = t.winfo_screenwidth()mainHeight = t.winfo_screenheight()# 设置窗口大小与显示位置t.geometry(f'{width}x{height}+{int((mainWidth - width) / 2)}+{int((mainHeight - height - 200) / 2)}')# 禁止窗口缩放t.resizable(0, 0)# 标题t.title("倒计时设置")# 图标t.iconbitmap("lg.ico")# 输入框e = Entry(t,width=6,fg='red',font=('方正姚体', 30, 'bold'))e.pack(pady=30)# 设置输入框焦点e.focus_set()# 绑定弹窗关闭事件t.protocol("WM_DELETE_WINDOW", lambda: self.setCountdownNumClose(e, t))def setCountdownNumClose(self, e, t):"""设置倒计时数值弹窗关闭事件:param e: 设置倒计时数值弹窗输入框对象:param t: 设置倒计时数值弹窗对象:return:"""try:# 获取输入框数据self.countdownNum = int(e.get())# 销毁设置倒计时数值弹窗t.destroy()# 设置主窗口可操作self.attributes("-disabled", 0)# 窗口保持在前面self.lift()except ValueError:passdef explain(self):"""说明弹窗:return:"""# 设置主窗口不可操作self.attributes("-disabled", 1)# 弹窗t = Toplevel(self)# 弹窗宽高width = 400height = 400# 主屏幕宽高mainWidth = t.winfo_screenwidth()mainHeight = t.winfo_screenheight()# 设置窗口大小与显示位置t.geometry(f'{width}x{height}+{int((mainWidth - width) / 2)}+{int((mainHeight - height) / 2)}')# 禁止窗口缩放t.resizable(0, 0)# 标题t.title("说明")# 图标t.iconbitmap("lg.ico")# 说明文本框sk = ScrolledText(t,width=25,height=14,font=('方正姚体', 20),state=DISABLED)sk.pack(pady=20)# 设置说明文本框可编辑sk.config(state=NORMAL)# 清空说明文本框sk.delete('1.0', END)# 设置说明文本框数据msg = '1、操作->选择题库\n' \'选择excel表格文件\n' \'读取excel表格第一列为问题第二列为解析\n\n' \'2、操作->设置倒计时\n' \'默认倒计时时间为15秒\n' \'输入整数点击退出完成设置\n\n' \'3、开始\n' \'开始随机抽取题目点击结束进行答题\n' \'倒计时期间无效\n\n' \'4、解析\n' \'展示解析内容关闭倒计时\n\n' \'5、重复随机\n' \'随机过的题目会再次出现\n\n' \'6、去重随机(默认)\n' \'随机过的题目不会再次出现\n\n' \'7、手动倒计时\n' \'点击倒计时按钮进行倒计时\n' \'倒计时期间无效\n\n' \'8、自动倒计时(默认)\n' \'随机结束后自动进入倒计时'# 设置说明文本框数据sk.insert(END, msg + '\n')# 设置说明文本框不可编辑sk.config(state=DISABLED)# 绑定弹窗关闭事件t.protocol("WM_DELETE_WINDOW", lambda: self.tlClose(t))@staticmethoddef author():"""作者:return:"""messagebox.showinfo('作者', 'pingfan')####################################################################################################################def startCountdown(self):"""倒计时:return:"""# 如果倒计时状态为关if not self.countdownNow:# 倒计时动画t = Thread(target=self.countdownAnimation)# 子线程跟随主线程关闭t.daemon = Truet.start()def countdownAnimation(self):"""倒计时动画:return:"""# 设置倒计时状态为开self.countdownNow = True# 设置倒计时按钮的标签值为倒计时数值self.countdownStr.set(self.countdownNum)while True:# 动画速率1ssleep(1)# 递减倒计时按钮的标签值self.countdownStr.set(int(self.countdownStr.get()) - 1)# 如果倒计时按钮的标签值小于等于0if int(self.countdownStr.get()) <= 0:# 播放倒计时结束音t = Thread(target=playsound, args=('end.wav',))# 子线程跟随主线程关闭t.daemon = Truet.start()# 设置倒计时按钮的标签值为倒计时self.countdownStr.set('倒计时')# 设置倒计时状态为关self.countdownNow = Falsebreakdef randomAsk(self):"""随机问题:return:"""# 如果问题数量大于0if len(self.askList) > 0:# 如果倒计时运行运行状态为关if not self.countdownNow:# 如果随机按钮的标签值等于开始if self.randomStart.get() == '开始':# 设置随机按钮的标签值为结束self.randomStart.set('结束')# 问题动画t = Thread(target=self.askAnimation)# 子线程跟随主线程关闭t.daemon = Truet.start()else:# 设置随机按钮的标签值为开始->结束问题动画self.randomStart.set('开始')else:messagebox.showinfo('提示', '请选择题库')def askAnimation(self):"""问题动画:return:"""while True:# 如果问题数据大于0if len(self.askList) > 0:# 随机索引index = randint(0, len(self.askList) - 1)# 设置问题文本框可编辑self.askTextObj.config(state=NORMAL)# 清空问题文本框self.askTextObj.delete('1.0', END)# 设置问题文本框数据self.askTextObj.insert(END, str(self.askList[index]) + '\n')# 设置问题文本框不可编辑self.askTextObj.config(state=DISABLED)# 设置解析值self.keyValue = str(self.keyList[index])# 如果按钮标签值等于开始if self.randomStart.get() == '开始':# 如果去重随机为开if not self.repetitive.get():# 删除当前问题数据与解析数据self.askList.pop(index)self.keyList.pop(index)# 如果自动倒计时为开if self.autoCountdown.get():# 倒计时self.startCountdown()break# 动画速率0.05秒sleep(0.05)def showKey(self):"""解析弹窗:return:"""# 设置主窗口不可操作self.attributes("-disabled", 1)# 如果倒计时运行状态为开if self.countdownNow:# 设置倒计时按钮的标签值为0->停止倒计时动画self.countdownStr.set('0')# 弹窗t = Toplevel(self)# 弹窗宽高width = 750height = 600# 主屏幕宽高mainWidth = t.winfo_screenwidth()mainHeight = t.winfo_screenheight()# 设置窗口大小与显示位置t.geometry(f'{width}x{height}+{int((mainWidth - width) / 2)}+{int((mainHeight - height) / 2)}')# 禁止窗口缩放t.resizable(0, 0)# 标题t.title("解析")# 图标t.iconbitmap("lg.ico")# 解析文本框sk = ScrolledText(t,width=25,height=9,font=('方正姚体', 40),state=DISABLED)sk.pack(pady=20)# 设置解析文本框可编辑sk.config(state=NORMAL)# 清空解析文本框sk.delete('1.0', END)# 设置解析文本框数据sk.insert(END, self.keyValue + '\n')# 设置解析文本框不可编辑sk.config(state=DISABLED)# 绑定弹窗关闭事件t.protocol("WM_DELETE_WINDOW", lambda: self.tlClose(t))def tlClose(self, t):"""弹窗关闭事件:param t: 弹窗对象:return:"""# 销毁设置倒计时数值弹窗t.destroy()# 设置主窗口可操作self.attributes("-disabled", 0)# 窗口保持在前面self.lift()if __name__ == '__main__':# 加载窗口root = Window()# 展示窗口root.show()

以下为PfExcel.py源码,基于openpyxl以下命令进行安装,用来读取excel表格中的问题,解析数据

pip install openpyxl
"""
基于openpyxl的excel读写模块
提供更简单的读写方式
"""
from openpyxl import load_workbook, Workbookclass ExcelWork:def __init__(self, filePath):"""初始化, 加载excel,默认选择第一个工作表:param filePath: str: 文件地址"""self.filePath = filePathtry:# 加载excelself.excel = load_workbook(self.filePath)except FileNotFoundError:# 创建excelself.excel = Workbook(self.filePath)# 创建sheetself.createSheet('Sheet1')# 保存excelself.close()# 加载excelself.excel = load_workbook(self.filePath)# sheet设置为第一个工作表self.sheet = self.excel.activedef close(self):"""保存并退出:return:"""self.excel.save(self.filePath)def createSheet(self, sheetName):"""创建工作表:param sheetName: str: 工作表名:return:"""self.excel.create_sheet(sheetName)def getSheetTitle(self):"""获取当前工作表名称:return:  str: 工作表名称"""return self.sheet.titledef getSheetTitles(self):"""获取excel所有工作表的名称:return:  list: [工作表名称,]"""return self.excel.sheetnamesdef delSheet(self):"""删除当前工作表:return:"""self.excel.remove(self.sheet)def selectSheet(self, sheetName):"""选择工作表, 如果没有将创建:param sheetName: str: 工作表名:return:"""if sheetName in self.getSheetTitles():# 选择工作表self.sheet = self.excel[sheetName]else:# 创建工作表self.createSheet(sheetName)# 选择工作表self.sheet = self.excel[sheetName]def setCell(self, r, c, var):"""修改指定行, 列的单元格内容:param r: int: 行数:param c: int: 列数:param var: str: 修改内容:return:"""self.sheet.cell(row=r, column=c, value=var)def getCell(self, r, c):"""获取指定行, 列的单元格内容:param r: int: 行数:param c: int: 列数:return: str: 单元格内容"""return self.sheet.cell(row=r, column=c).valuedef getRow(self, r):"""获取指定行所有数据:param r: int: 行数:return: list: [数据,]"""rowList = []for cell in self.sheet[r]:rowList.append(cell.value)return rowListdef getColumn(self, c):"""获取指定列所有数据:param c: int: 列数:return: list: [数据,]"""columnList = []for temp in range(1, self.sheet.max_row + 1):columnList.append(self.getCell(temp, c))return columnList

测试可用~~~~gui入门...写的可能非常啰嗦,求大佬指正~~~~

python3 tkinter 随机答题相关推荐

  1. python3+tkinter实现的黑白棋,代码完整 100%能运行

    今天分享给大家的是采用Python3+tkinter制作而成的小项目--黑白棋 tkinter是Python内置的图形化模块,简单易用,一般的小型UI程序可以快速用它实现,具体的tkinter相关知识 ...

  2. python3 tkinter电子书_python3 tkinter实现添加图片和文本

    本文在前面文章基础上介绍tkinter添加图片和文本,在这之前,我们需要安装一个图片库,叫Pillow,这个需要下载exe文件,根据下面图片下载和安装. 下载完后直接双击安装exe,默认点击下一步,直 ...

  3. python tkinter 随机抽奖程序

    1. 界面 import tkinter as tk import randoma = ["荀彧","荀攸","贾诩","郭嘉&q ...

  4. python3 tkinter

    https://morvanzhou.github.io/tutorials/python-basic/tkinter/ 李导师推荐的.非常感谢.非常棒的视频教程!!! 只不过里面的教程视频是yout ...

  5. python3 tkinter电子书_Python3 Tkinter-Text

    1.创建 from tkinter import * root=Tk() t=Text(root) t.pack() root.mainloop() 2.添加文本 from tkinter impor ...

  6. python3 tkinter详解_python tkinter基本属性详解

    1.外形尺寸 尺寸单位:只用默认的像素或者其他字符类的值!,不要用英寸毫米之类的内容. btn = tkinter.Button(root,text = '按钮') # 设置按钮尺寸,绝大多数默认单位 ...

  7. python3 tkinter 实现凯撒密码GUI界面

    Codes import tkinter as tk from tkinter import messageboxclass Kaisa():def __init__(self): # 构造函数sel ...

  8. python3 tkinter 桌面软件教程

    效果图 """"brid布局""" from tkinter import * import tkinter.filedialog ...

  9. python3 tkinter 刷新标签图片

    # coding=utf-8 import tkinter as tk import osclass RuKou(tk.Frame):"""登入的入口将要做成运行时显示接 ...

  10. python3 姓名随机生成脚本--random.randrange()用法

    首先先准备一个形式的词库,我这里用了一个列表和一些简单的姓氏: ###508个常用姓氏 xing_shi = ["赵","钱","孙",&q ...

最新文章

  1. java大作业私人管家系统_操作系统概念(Operating System Concepts)第十版期中大作业...
  2. Python学习笔记 - PostgreSQL的使用
  3. Django:模型model和数据库mysql(一)
  4. 【opencv】边缘提取或通过二值图片提取对应的三维图像(python)
  5. C2679 二进制 没有找到接受 std::string 类型的右操作数的运算符(或没有可接受的转换)
  6. BZOJ 3668: [Noi2014]起床困难综合症( 贪心 )
  7. MyEclipse创建JavaWeb应用和TomCat的配置
  8. 专科python应届生工资多少-大四应届毕业生,学了两个月Python,找工作感觉好难啊?...
  9. Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结
  10. 僵尸进程与孤儿进程(精简易懂,直接要害)
  11. CommandArgument 与 CommandName 属性
  12. (四)JSP语法详细介绍--脚本元素
  13. 10bit、8bit色彩深度,究竟差多少?
  14. 计算机Numlock键的功能,电脑开机numlock灯不亮怎么办 NumLock数字锁定键方法
  15. 分子模拟的理论与实践_活动回顾 | 信息学院模拟党支部实践成果汇报会
  16. python游戏功能_python 游戏(龙的国度)
  17. Python库turtle的趣味性用法,欢迎来品尝。
  18. [USACO 2010 Feb S]Chocolate Eating
  19. 批处理文件*.bat打开后闪退的处理方法
  20. js给label赋值功能

热门文章

  1. 服务器1U,2U的含义
  2. drupal模块_自动测试Drupal 8模块
  3. 《透视盒马:新零售操作系统的秘密》
  4. Java编程题修院子_2020大学moocJava程序设计题目答案
  5. VMware 虚拟化中:厚置备延迟置零、厚置备置零、Thin Provision三个的区别
  6. DTL autoescape
  7. IM即时通讯开发,聊天软件APP搭建,私有云部署
  8. java日志(四)--jcl和log4j及log4j2使用
  9. 小科普:到底什么是BFC、IFC、GFC和FFC,次奥?
  10. 什么是自然语言处理(NLP)?定义+应用一次性看个明白