上一篇写到利用Python写了一个对文本进行读取和修改的小工具,最近两天在研究给这个小程序加个界面,对于GUI这里不做赘述,到现在也算是初步完成了,写个博客记录记录。
首先是界面工具的选用,在菜鸟教程上看到的GUI模块有3款,原文链接Python GUI编程(Tkinter) 文中只对Tkinter工具做了简单的介绍,并没有太深的讲解;查找之下找到了简书上的Tkinter教程,原文链接(八)Python 图形化界面设计 这个文档对Tkinter模块做了详细的介绍和示例,有这方面需要的朋友可以详细的阅读练手。值得一提的是,文本框的输入使能在文中并没有介绍到,我在另一篇文章中找到了有关文本框输入使能的介绍,原文链接Tkinter中关于如何让用户无法编辑Text,又可进行插入、删除操作 此外,为了实现按钮结束程序的功能,需要销毁root的root对象,简书上的Tkinter教程有用到这个对象,但没有过多的描述,为了找到这个对象在vscode里尝试输入root.cl和root.des后,发现root自带一个destroy对象,确定是销毁root的对象。
由于是第一次做界面,所以定的要求比较低,并不追求界面的美观,只需要基本的功能实现即可。首先遇到的是功能按钮化,原本整合在一个while里的主程序需要拆分成若干个子程序,原程序和拆分后的程序如下:
此时的代码是基于上代加了输入验证和时间模块引入,并做了一些输出上的微调
while True:
print("**************************你爱用不用的报销记录工具**************************\n")
choose = input("选择你要进行的操作:\n1.提交报销\n2.结束报销\n3.查看所有记录\n4.结束程序\n输入:")#功能选择
print()
if not choose :
print("要我帮你做选择?")
continue
elif str(choose).isdigit() == False :
print("脸滚键盘呢?")
continue
fb = open("%s报销记录.txt"%(ADDR),mode = 'a')#确保文件存在,若不存在则在指定目录新建一个
fb.close()
if int(choose) == 1:
fb = open("%s报销记录.txt"%(ADDR),mode = 'r')#打开记录文本
getline = 0 #获取当前行数,即最后一个编号
for line in fb.readlines():
getline += 1
fb.close()
while True:
date = input("输入提交日期,如:20190101,不填则默认当前日期\n输入:")#获取日期,金额和时长
if not date:
date = DATE
elif int(date) > int(DATE):
print("日期输入有误!提交日期不可晚于今天!重新输入!")
continue
money = int(input("输入报销金额\n输入:"))
days = int(input("输入出差时长\n输入:"))
break
line = openfile()
addline(line,getline,date,money,days)
print("添加成功!\n")
elif int(choose) == 2:
fb = open("%s报销记录.txt"%(ADDR),mode = 'r')#打开记录文本
getline = 0 #获取当前行数,即最后一个编号
for line in fb.readlines():
getline += 1
fb.close()
line = openfile()
while True:
num = int(input("输入要结束的编号\n输入:"))
if num > getline:
print("无此记录!确认后再输入!\n")
continue
if line[num].find('Y') != -1 :
print("这条记录已经完成报销了,你别是在逗我吧")
continue
date = input("输入提交日期,如:20190101,不填则默认当前日期\n输入:")#获取日期和金额
if not date:
date = DATE
elif int(date) >= int(DATE):
print("日期输入有误!提交日期不可晚于今天!重新输入!")
continue
money = int(input("输入报销金额\n输入:"))
break
endline(line,num,date,money)
print("添加成功!\n")
elif int(choose) == 3:
line = openfile()
if line == []:
print("文件为空!\n")
for i in line:
print(i)
elif int(choose) == 4:
break
else :
print("没那么多功能!")
拆分后的代码:
原本的输入和输出有了明显的变化,输入是获取输入框的内容,输出是将输出内容添加到文本框中
def choose1():
txt.config(state = NORMAL)#文本框使能开,允许输入内容
#输入验证
flag = True#使while只运行一次,while的意义在于输入有误时能使用break阻止后续代码的运行
while flag:
money = inp3.get()
#money = int(input("输入报销金额\n输入:"))
days = inp1.get()
#days = int(input("输入出差时长\n输入:"))
if (not money) or (not days):
txt.insert(END,"输入不完整!\n")
txt.config(state = DISABLED)#在程序中断时及时关闭文本框使能,保证文本框只能被程序修改
break
date = inp2.get()
#date = input("输入提交日期,如:20190101,不填则默认当前日期\n输入:")#获取日期,金额和时长
if not date:
date = DATE
elif int(date) > int(DATE):
txt.insert(END,("日期输入有误!提交日期不可晚于今天!重新输入!\n"))
txt.config(state = DISABLED)
break
#print("日期输入有误!提交日期不可晚于今天!重新输入!")
fb = open("报销记录.txt",mode = 'r')#打开记录文本
getline = 0 #获取当前行数,即最后一个编号
for line in fb.readlines():
getline += 1
fb.close()
line = openfile()
addline(line,getline,date,money,days)
txt.insert(END,"添加成功!\n")
txt.insert(END,'\n')
txt.config(state = DISABLED)#本次功能结束,关闭文本框使能
inp1.delete(0, END) # 清空输入
inp2.delete(0, END) # 清空输入
inp3.delete(0, END) # 清空输入
#print("添加成功!\n")
flag = False
def choose2():
txt.config(state = NORMAL)
flag = True
while flag:
#输入检查
fb = open("报销记录.txt",mode = 'r')#打开记录文本
getline = 0 #获取当前行数,即最后一个编号
for line in fb.readlines():
getline += 1
fb.close()
num = inp1.get()
if not num:
txt.insert(END,"选择的编号不能为空!\n")
txt.config(state = DISABLED)
break
#num = int(input("输入要结束的编号\n输入:"))
elif str(num).isdigit() == False :
txt.insert(END,"让你输编号呢!\n")
#print("让你输编号呢!\n")
txt.config(state = DISABLED)
break
num = int(num)
if num > getline:
txt.insert(END,"无此记录!确认后再输入!\n")
#print("无此记录!确认后再输入!\n")
txt.config(state = DISABLED)
break
#flag = False
elif line[num].find('Y') != -1:
txt.insert(END,"这条记录已经完成报销了,你别是在逗我吧!\n")
#print("这条记录已经完成报销了,你别是在逗我吧")
txt.config(state = DISABLED)
break
#flag = False
date = inp2.get()
#date = input("输入提交日期,如:20190101,不填则默认当前日期\n输入:")#获取日期和金额
if not date:
date = DATE
elif int(date) >= int(DATE):
txt.insert(END,"日期输入有误!提交日期不可晚于今天!重新输入!\n")
#print("日期输入有误!提交日期不可晚于今天!重新输入!")
txt.config(state = DISABLED)
break
#flag = False
money = inp3.get()
line = openfile()
#money = int(input("输入报销金额\n输入:"))
endline(line,num,date,money)
txt.insert(END,"添加成功!\n")
txt.insert(END,'\n')
txt.config(state = DISABLED)
#print("添加成功!\n")
inp1.delete(0, END) # 清空输入
inp2.delete(0, END) # 清空输入
inp3.delete(0, END) # 清空输入
flag = False
def choose3():
txt.config(state = NORMAL)
line = openfile()
if line == []:
txt.insert(END,"文件为空!\n")
#print("文件为空!\n")
else:
for i in line:
txt.insert(END,i)
#print(i)
txt.insert(END,'\n')
txt.config(state = DISABLED)
def choose4():
root.destroy()
#break
界面化之后,相较于shell里执行,界面化的输出不会自动换行,需要在Text.insert里加入额外的换行
界面模块:
from tkinter import *
import datetime
time = datetime.datetime.now()
DATE = str(time.year) + str(time.month) + str(time.day)#限定日期,取当前日期,确保输入日期不在未来
#ADDR = "D:工程部svn\"
#确保文件存在
fb = open("报销记录.txt",mode = 'a')
fb.close()
root = Tk()
root.title("Py报销记录工具")
root.geometry('480x480')
lb0 = Label(root, text='爱用不用的报销记录工具',bg='#d3fbfb',fg='red',font=('华文新魏',24),width=20,height=2,relief=SUNKEN)
lb0.place(relx=0.1, rely=0.0, relwidth=0.8, relheight=0.1)
lb1 = Label(root, text="时长/编号:")
lb1.place(relx=0.0, rely=0.1, relwidth=0.15, relheight=0.1)
inp1 = Entry(root)
inp1.place(relx=0.15, rely=0.11, relwidth=0.15, relheight=0.08)
lb2 = Label(root, text="日期:")
lb2.place(relx=0.35, rely=0.1, relwidth=0.1, relheight=0.1)
inp2 = Entry(root)
inp2.place(relx=0.45, rely=0.11, relwidth=0.2, relheight=0.08)
lb3 = Label(root, text="金额:")
lb3.place(relx=0.7, rely=0.1, relwidth=0.1, relheight=0.1)
inp3 = Entry(root)
inp3.place(relx=0.8, rely=0.11, relwidth=0.2, relheight=0.08)
btn1 = Button(root, text='添加记录', command=choose1)
btn1.place(relx=0.1, rely=0.2, relwidth=0.3, relheight=0.1)
btn2 = Button(root, text='结束记录', command=choose2)
btn2.place(relx=0.1, rely=0.4, relwidth=0.3, relheight=0.1)
btn3 = Button(root, text='查看记录', command=choose3)
btn3.place(relx=0.6, rely=0.2, relwidth=0.3, relheight=0.1)
btn4 = Button(root, text='结束程序', command=choose4)
btn4.place(relx=0.6, rely=0.4, relwidth=0.3, relheight=0.1)
txt = Text(root)
txt.place(rely=0.6, relheight=0.4)
txt.config(state = DISABLED)#文本框初始使能关
root.mainloop()
界面效果:
界面化后原来的模块代码:
def openfile():
txt.insert(END,"开始读取文件\n")
#print("开始读取文件")
fb = open("报销记录.txt",mode = 'r')
lines = []
for line in fb:
lines.append(line)
txt.insert(END,"读取完成\n")
#print("读取完成")
fb.close()
return lines
def addline(line,getline,date,money,days):
#txt.insert(END,("添加前:",line,'\n'))
#print("添加前:",line)
line.append("%d N %s %d %d "%(int(getline),date,int(money),int(days)))
#txt.insert(END,("添加后:",line,'\n'))
#print("添加后:",line)
fb = open("报销记录.txt",mode = 'w')
for i in range(len(line)):
s = str(line[i]).replace('[','').replace(']','').replace("'",'').replace(',','').replace('\n','')#去除[],去除单引号
#txt.insert(END,(s,'\n'))
#print(s)
fb.write(s)
fb.write('\n')
txt.insert(END,"添加程序运行完成!\n")
#print("添加程序运行完成!")
fb.close()
def endline(line,num,date,money):
#print(line[num])
line[num] = line[num].replace('N','Y')
#print(line[num])
addstr = str(date) + ' ' + str(money)
line[num] += addstr
#print(line)
fb = open("报销记录.txt",mode = 'w')
for i in range(len(line)):
s = str(line[i]).replace('[','').replace(']','').replace("'",'').replace(',','').replace('\n','')#去除[],去除单引号
#txt.insert(END,(s,'\n'))
#print(s)
fb.write(s)
fb.write('\n')
txt.insert(END,"结束程序运行完成!\n")
#print("结束程序运行完成!")
fb.close()
基本功能已经做好了,后续准备引入父容器,使界面更美观;再引入用户和数据库吧。
望大佬们多多批评指正,菜鸟在此拜谢!