button点击后出现的边框_用Tkinter制作Python程序的图形用户界面(GUI),打包后比Qt5减少60M(77.5%)(实例63)...

实例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()进入消息循环,就能出现如下空界面。

edfda6c7ac2b8b5c6b75c85d9a3a7d9f.png

接下来,就要添加一些需要的控件了。先添加两个文本框和三个按钮。以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设置其背景颜色。其背景颜色牌如下图,可根据需要自由选择(看不清楚?没关系,已上传网盘,可到公众号输入“源文件”提取)。

b9c45bbd00d3f9fc8deaa4253f109147.png

设置好放置位置后,给它添加上横轴及纵轴方向的滚动条。纵轴方向的滚动条通过Scrollbar(result_show,command=result_show.yview)添加,由于是添加进列表框的,所以第一个参数是result_show而不是主窗口myWindow。通过command将滚动条的操作连接到列表框的纵轴方向上yview。通过pack将滚动条放置到右边side=RIGHT,并填充整个纵轴方向fill=Y。最后通过config(yscrollcommand = sbY.set)将滚动条配置到列表框的纵轴方向。类似的方法添加横轴方向的滚动条,因为滚动条的默认方向是垂直方向,所以需要特别指定其方向为水平方向orient = HORIZONTAL。

到此,界面准备完成,运行一下,得到如下结果。看起来还是像那么回事的。

7afc19f1c37d745e4c02c1dcd94e0742.png

from tkinter import Tk,Entry,Button,Listbox,X,Y,END,Scrollbar,RIGHT,BOTTOM,HORIZONTAL
from tkinter.filedialog import askdirectory

#用于选择“输入文件目录”
def select_dir1():
    input_entry.delete(0, END) #先清空文本框
    input_entry.insert(0, askdirectory(initialdir= "D:\\")) #选择目录并插入文本框,默认选择D盘
#用于选择“输出文件目录”
def select_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()

窗口准备好后,就需要将执行程序跟窗口各控件连接起来了。为了方便各函数互相调用,需要将所有函数和窗口设置放入类MainGUI里面。程序运行的步骤如下:

  1. 1. 弹出窗口,然后手动选择输入文件目录和输出文件目录

  2. 2. 点击“执行汇总按钮”

  3. 3. 程序将从输入文件目录对应的文本框中获取目录信息,此处通过self.input_entry.get()获得

  4. 4. 然后程序将单个“领料记录”文件的数据写入汇总文件。每写入一个,则在列表框显示信息,此处通过self.result_show.insert("end", f)实现,其中"end"指插入的位置为列表框的末尾,"f"为插入的内容

  5. 5. 写入汇总文件完成后,将结果保存到“输出文件目录”,并在列表框显示信息。

from os import listdir
from xlrd import open_workbook, xldate
from datetime import datetime
from time import time, localtime ,strftime
from openpyxl import Workbook
from openpyxl.styles import Border, Side, PatternFill, Font, GradientFill, Alignment
from tkinter import Tk,Entry,Button,Listbox,X,Y,END,Scrollbar,RIGHT,BOTTOM,HORIZONTAL
from tkinter.filedialog import askdirectory

class MainGUI():
    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()

    def select_dir1(self):
        self.input_entry.delete(0, END)
        self.input_entry.insert(0, askdirectory(initialdir= "D:\\"))

    def select_dir2(self):
        self.output_entry.delete(0, END)
        self.output_entry.insert(0, askdirectory(initialdir= "D:\\"))

    #读取xls文件中的数据
    def Get_data(self,file):
        wb = open_workbook(file) #读取工作簿
        ws = wb.sheets()[0] #选第一个工作表
        data = {}
        for row in range(7, ws.nrows-2):
            dept = ws.cell(2, 16).value #部门
            dept_id = ws.cell(3, 16).value #部门编号
            dt = ws.cell(row, 0).value #时间
            if type(dt) is float:
                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,[]) #以日期为键
            if info_list[3] != "备注": #不要业务类型为“备注”的数据
                data[date].append(info_list)
        #增加当日领取次数        
        for key in data.keys():
            for i in data[key]:
                i.append(len(data[key]))

        return data

    def Get_file_path(self,path):        
            files=[]
            for file in listdir(path):
                if file.endswith(".xls"): #排除文件夹内的其它干扰文件
                    files.append(path+"\\"+file)
            return files

    def Get_current_time(self):
        time_stamp = time()  # 当前时间的时间戳
        local_time = localtime(time_stamp)  #
        str_time = strftime('%Y-%m-%d %H.%M.%S', local_time)
        return str_time

    def Summary_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文件
        for file in files:
            data = self.Get_data(file)
            for key in data.keys():
                for i in data[key]:
                    ws.append(i)
            f = f"{file} 的内容已加入总表." # 创建一个显示项
            self.result_show.insert("end", f) #将结果添加到列表框中

        #设置字号,对齐,缩小字体填充,加边框
        #Font(bold=True)可加粗字体
        for row_number in range(2, ws.max_row+1):
            for col_number in range(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]
        for i in range(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()

程序运行的结果图如下,符合要求。

7e31649af526b278d4d8480a081deb11.png

然后开始打包操作,具体操作见实例62 。为避免干扰,还是去纯Python环境的虚拟机中打包。结果只有18.6M,比Qt5的80M,立减77.5%,效果看得见啊!

08adf89c4c7d972530f2bdf29d854dcb.png

如果您有需要处理的问题,可发邮件到邮箱:donyo@qq.com,一起探讨解决方案。微信公众号输入“源文件”提取所有源文件及资料。

917cc09803be16b558864f6ac8cff82d.png

喜欢此文,点亮“在看”!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值