实例61使用PyQt5制作了图形用户界面(GUI)。这个香是香,但是打包后的安装文件太大(约80M),感觉有些美中不足啊。由于这个GUI实在简单,从现实角度实在用不着高大上的PyQt5,所以改用Python内置的Tkinter库来做图形用户界面(GUI),理论上可大幅缩小打包后的文件大小。对于简单的图形界面,Tkinter是毫无压力的。
先依葫芦画瓢,把界面搞出来再说。然后再慢慢连接程序,实现操作的交互功能。不要将库中的模块全导入,只导入要用到的模块,这样可以尽量缩小打包后的文件。这里主要用到文本框(Entry)、按钮(Button)、列表框(Listbox)、滚动条(Scrollbar)等组件以及文件目录获取模块(askdirectory),所以只导入这些即可。
定义两个“选择目录”的函数select_dir1及select_dir2,用于选择“输入文件目录”和“输出文件目录”。它们将使用按钮来调用,并将选择的目录显示在文本框中。input_entry和output_entry是后面定义的文本框。先用delete(0, END)方法将文本框清空,0和END对应文本框中的内容的开始和结束值。从0到结束都删除掉,也就等于“清空”了。之所以要清空文本框,是为了避免误操作输入了字符,影响到后面插入的路径。然后就可以通过insert方法插入选择的目录了,其中的参数0表示开始值,即从0这个位置插入选择的目录。askdirectory是选择目录的方法,会弹出对话框让我们操作。
然后通过Tk()创建一个新的界面,存入MyWindow中。然后添加标题,设置窗口大小(单位像素),添加窗口Logo。加上一句myWindow.mainloop()进入消息循环,就能出现如下空界面。
接下来,就要添加一些需要的控件了。先添加两个文本框和三个按钮。以input_entry为例,Entry()即是添加文本框的方法,其中第一个参数是目标窗口,此处是之前定义的窗口myWindow。highlightcolor指鼠标选中后显示高亮的颜色,highlightthickness指高亮的框线的粗细。这两个可有可无。然后通过place()放置到指定位置,其中x,y参数对应窗口myWindow上的坐标,都取10像素,让控件不要紧贴窗口边缘。width和height指文本框的长度和宽度,这个根据需要调整,已保持与其它控件的对齐和整个界面的美观。
然后在文本框input_entry右边添加一个按钮btn_in,它的文字显示为"输入文件目录",指令command连接到函数select_dir1,根据需要设定宽高(这里的宽高指多少个文字,比如width=10指10个字符的宽度)。同样,使用place指定放置位置。同样的方法,再添加一个文本框和两个按钮。
随后添加一个列表框result_show,用于显示操作的进度和结果,并通过bg设置其背景颜色。其背景颜色牌如下图,可根据需要自由选择(看不清楚?没关系,已上传网盘,可到公众号输入“源文件”提取)。
设置好放置位置后,给它添加上横轴及纵轴方向的滚动条。纵轴方向的滚动条通过Scrollbar(result_show,command=result_show.yview)添加,由于是添加进列表框的,所以第一个参数是result_show而不是主窗口myWindow。通过command将滚动条的操作连接到列表框的纵轴方向上yview。通过pack将滚动条放置到右边side=RIGHT,并填充整个纵轴方向fill=Y。最后通过config(yscrollcommand = sbY.set)将滚动条配置到列表框的纵轴方向。类似的方法添加横轴方向的滚动条,因为滚动条的默认方向是垂直方向,所以需要特别指定其方向为水平方向orient = HORIZONTAL。
到此,界面准备完成,运行一下,得到如下结果。看起来还是像那么回事的。
fromtkinter.filedialogimportaskdirectory #用于选择“输入文件目录” defselect_dir1(): input_entry.delete(0,END)#先清空文本框 input_entry.insert(0,askdirectory(initialdir="D:\\"))#选择目录并插入文本框,默认选择D盘 #用于选择“输出文件目录” defselect_dir2(): output_entry.delete(0,END) output_entry.insert(0,askdirectory(initialdir="D:\\")) #初始化Tk() myWindow=Tk() myWindow.title("领料记录汇总")#添加窗口标题 myWindow.geometry('590x400')#设置窗口大小 myWindow.iconbitmap("PO.ico")#添加窗口Logo #添加文本框及按钮 input_entry=Entry(myWindow,highlightcolor='red',highlightthickness=1)#添加文本框 input_entry.place(x=10,y=10,width=480,height=30)#按坐标放置,设定高度和宽度 btn_in=Button(myWindow,text='输入文件目录',command=select_dir1,width=10,height=1) btn_in.place(x=500,y=10) output_entry=Entry(myWindow,highlightcolor='blue',highlightthickness=1) output_entry.place(x=10,y=50,width=480,height=30) btn_out=Button(myWindow,text='输出文件目录',command=select_dir2,width=10,height=1) btn_out.place(x=500,y=50) btn_run=Button(myWindow,text='执行汇总',width=10,height=1) btn_run.place(x=500,y=90) #添加列表框及滚动条 result_show=Listbox(myWindow,bg='DarkSeaGreen') result_show.place(x=10,y=130,width=570,height=260) sbY=Scrollbar(result_show,command=result_show.yview)#在列表框中增加Y轴滚动条 sbY.pack(side=RIGHT,fill=Y) result_show.config(yscrollcommand=sbY.set) sbX=Scrollbar(result_show,command=result_show.xview,orient=HORIZONTAL)#在列表框中增加X轴滚动条 sbX.pack(side=BOTTOM,fill=X) result_show.config(xscrollcommand=sbX.set) myWindow.mainloop()fromtkinterimportTk,Entry,Button,Listbox,X,Y,END,Scrollbar,RIGHT,BOTTOM,HORIZONTAL
窗口准备好后,就需要将执行程序跟窗口各控件连接起来了。为了方便各函数互相调用,需要将所有函数和窗口设置放入类MainGUI里面。程序运行的步骤如下:
1. 弹出窗口,然后手动选择输入文件目录和输出文件目录
2. 点击“执行汇总按钮”
3. 程序将从输入文件目录对应的文本框中获取目录信息,此处通过self.input_entry.get()获得
4. 然后程序将单个“领料记录”文件的数据写入汇总文件。每写入一个,则在列表框显示信息,此处通过self.result_show.insert("end", f)实现,其中"end"指插入的位置为列表框的末尾,"f"为插入的内容
5. 写入汇总文件完成后,将结果保存到“输出文件目录”,并在列表框显示信息。
fromxlrdimportopen_workbook,xldate fromdatetimeimportdatetime fromtimeimporttime,localtime,strftime fromopenpyxlimportWorkbook fromopenpyxl.stylesimportBorder,Side,PatternFill,Font,GradientFill,Alignment fromtkinterimportTk,Entry,Button,Listbox,X,Y,END,Scrollbar,RIGHT,BOTTOM,HORIZONTAL fromtkinter.filedialogimportaskdirectory classMainGUI(): def__init__(self): myWindow=Tk() myWindow.title("领料记录汇总") #设置窗口大小 myWindow.geometry('590x400') myWindow.iconbitmap("PO.ico") #增加文本框 self.input_entry=Entry(myWindow,highlightcolor='red',highlightthickness=1) self.input_entry.place(x=10,y=10,width=480,height=30) self.btn_in=Button(myWindow,text='输入文件目录',command=self.select_dir1,width=10,height=1) self.btn_in.place(x=500,y=10) self.output_entry=Entry(myWindow,highlightcolor='blue',highlightthickness=1) self.output_entry.place(x=10,y=50,width=480,height=30) self.btn_out=Button(myWindow,text='输出文件目录',command=self.select_dir2,width=10,height=1) self.btn_out.place(x=500,y=50) self.btn_run=Button(myWindow,text='执行汇总',width=10,height=1,command=self.Summary_data) self.btn_run.place(x=500,y=90) #增加列表框 self.result_show=Listbox(myWindow,bg='DarkSeaGreen')#yscrollcommand=scroll_bar, self.result_show.place(x=10,y=130,width=570,height=260) self.sbY=Scrollbar(self.result_show,command=self.result_show.yview)#在列表框中增加Y轴滚动条 self.sbY.pack(side=RIGHT,fill=Y) self.result_show.config(yscrollcommand=self.sbY.set) self.sbX=Scrollbar(self.result_show,command=self.result_show.xview,orient=HORIZONTAL)#在列表框中增加X轴滚动条 self.sbX.pack(side=BOTTOM,fill=X) self.result_show.config(xscrollcommand=self.sbX.set) myWindow.mainloop() defselect_dir1(self): self.input_entry.delete(0,END) self.input_entry.insert(0,askdirectory(initialdir="D:\\")) defselect_dir2(self): self.output_entry.delete(0,END) self.output_entry.insert(0,askdirectory(initialdir="D:\\")) #读取xls文件中的数据 defGet_data(self,file): wb=open_workbook(file)#读取工作簿 ws=wb.sheets()[0]#选第一个工作表 data={} forrowinrange(7,ws.nrows-2): dept=ws.cell(2,16).value#部门 dept_id=ws.cell(3,16).value#部门编号 dt=ws.cell(row,0).value#时间 iftype(dt)isfloat: date_time=xldate.xldate_as_datetime(dt,0) else: date_time=datetime.strptime(dt,'%Y-%m-%d%H:%M:%S') business=ws.cell(row,2).value#业务类型 model=ws.cell(row,3).value#品种 qty=ws.cell(row,4).value#数量 unit_price=ws.cell(row,6).value#单价 price=ws.cell(row,8).value#总价 reward=ws.cell(row,9).value#额外值 discount=ws.cell(row,11).value#调整 balance=ws.cell(row,13).value#剩余 location=str(ws.cell(row,15).value).strip()#库位 operator=ws.cell(row,17).value#操作员 date=date_time.date()#日期 time=date_time.time()#时间 info_list=[dept,dept_id,date_time,business,model,qty,unit_price,price,reward,discount, balance,location,operator,date,time] data.setdefault(date,[])#以日期为键 ifinfo_list[3]!="备注":#不要业务类型为“备注”的数据 data[date].append(info_list) #增加当日领取次数 forkeyindata.keys(): foriindata[key]: i.append(len(data[key])) returndata defGet_file_path(self,path): files=[] forfileinlistdir(path): iffile.endswith(".xls"):#排除文件夹内的其它干扰文件 files.append(path+"\\"+file) returnfiles defGet_current_time(self): time_stamp=time()#当前时间的时间戳 local_time=localtime(time_stamp)# str_time=strftime('%Y-%m-%d%H.%M.%S',local_time) returnstr_time defSummary_data(self): thin=Side(border_style="thin",color="000000")#定义边框粗细及颜色 title=['部门','部门编号','时间','业务类型','品种','数量','单价','金额','额外值', '调整','剩余','库位','操作员','领取日期','领取时间','领取次数'] wb=Workbook() ws=wb.active ws.merge_cells("A1:P1") ws.cell(1,1).value="领料明细汇总表" ws.cell(1,1).font=Font(name=u'黑体',bold=True,size=18) ws.row_dimensions[1].height=22.2 ws.cell(1,1).alignment=Alignment(horizontal="center",vertical="center") ws.append(title) #插入数据 files=self.Get_file_path(self.input_entry.get())#get()获取文本编辑框中的输入文件目录,并获取目录下的xls文件 forfileinfiles: data=self.Get_data(file) forkeyindata.keys(): foriindata[key]: ws.append(i) f=f"{file}的内容已加入总表."#创建一个显示项 self.result_show.insert("end",f)#将结果添加到列表框中 #设置字号,对齐,缩小字体填充,加边框 #Font(bold=True)可加粗字体 forrow_numberinrange(2,ws.max_row+1): forcol_numberinrange(1,17): c=ws.cell(row=row_number,column=col_number) c.font=Font(size=9) c.border=Border(top=thin,left=thin,right=thin,bottom=thin) c.alignment=Alignment(horizontal="left",vertical="center") col_name=list("ABCDEFGHIJKLMNOP") col_width=[8,8,16,8,16,8,8,9.8,8,8,8,11,8.3,9,8,8] foriinrange(len(col_name)): ws.column_dimensions[col_name[i]].width=col_width[i] ws.column_dimensions.group('I','K',hidden=True) ws.column_dimensions.group('N','O',hidden=True) wb.save(f"{self.output_entry.get()}\\领料明细汇总表{self.Get_current_time()}.xlsx") f="-"*100#创建分割线 self.result_show.insert("end",f)#将分割线添加到列表框 f=f"领料明细汇总表{self.Get_current_time()}.xlsx已生成,请去输出文件夹查看."#创建一个显示项 self.result_show.insert("end",f)#将结果添加到列表框 f=""*100 self.result_show.insert("end",f)#将以上空格添加到列表框 if__name__=="__main__": MainGUI()fromosimportlistdir
程序运行的结果图如下,符合要求。
然后开始打包操作,具体操作见实例62 。为避免干扰,还是去纯Python环境的虚拟机中打包。结果只有18.6M,比Qt5的80M,立减77.5%,效果看得见啊!
如果您有需要处理的问题,可发邮件到邮箱:donyo@,一起探讨解决方案。微信公众号输入“源文件”提取所有源文件及资料。
喜欢此文,点亮“在看”!
button点击后出现的边框_用Tkinter制作Python程序的图形用户界面(GUI) 打包后比Qt5减少60M(77.5%)(实例63)...