1. 步骤:
① 使用
Python
自带的tkinter
和ttk
库编写程序界面
② 使用第三方库
ttkbootstrap
的主题美化界面
③ 混淆加密源代码并打包修改exe程序图标
2. 使用tkinter和ttk编写Python程序GUI界面
tkinter和ttk库包含了菜单栏、按钮、标签、输入框、复选框、尺寸条、选项按钮、选值框、标签按钮、列表框、下拉式列表(组合框)、进度条、分割线、树形表格与树状图、单选按钮、顶层窗口(弹出另外的窗口)、笔记本、画布、列表框和滚动条这22个基本控件。Win10系统中这些控件在默认主题下的样子见下图的“大杂烩”。
根据我们要实现的功能来挑选可以展示结果的控件,对于需要分块显示的程序而言,可以定义一个根节点frm = Frame(self.root)
和多个子节点frm_left = Frame(frm)
、frm_middle = Frame(frm)
、frm_right = Frame(frm)
,并通过grid
属性定义各节点在X轴方向上的边距padx、Y轴方向上的边距pady和子节点在根节点中所占的行列位置关系row=m, column=n。
# 各节点初始化
frm = Frame(self.root)
frm.grid(padx='10', pady='10')
frm_left = Frame(frm)
frm_left.grid(row=0, column=0, padx='25', pady='10')
frm_middle = Frame(frm)
frm_middle.grid(row=0, column=1, padx='20', pady='10')
frm_right = Frame(frm)
frm_right.grid(row=0, column=2, padx='20', pady='10')
然后就可以在子节点添加我们需要的各种控件,编写其对应的的回调函数。以一个实际需求为例,《无线传感器网络综合设计》课程在实验课上需要验收每位同学的结果,而在人数多且收到的数据动态更新时,一个一个找同学们发送到网关的数据比较烦琐,那我们就可以写一个GUI应用程序来实现验收的过程。
使用列表框(Listbox
)来显示实时接收到的网关数据,用树形表格(Treeview
)来存放每位同学最后一次发送的数据,用树状图(Treeview
)来显示已发送数据学生顺序和未发送数据的学生名单,并给它们配置滚动条。
# (1)实时接收的数据(列表框)
self.labelrecv = Label(frm_middle, text="实时接收的数据: ", font=('宋体', 15))
self.recvlistbox = Listbox(frm_middle, width=73, height=37)
# (2)最后一次收到每人的数据(树形表格)
self.labelrecv2 = Label(frm_right, text="最后一次收到每人的数据: ", font=('宋体', 15))
self.recvlistbox2 = ttk.Treeview(frm_right, height=37, columns=('name', 'number', 'data'), selectmode='extended')
self.recvlistbox2.heading('#0', text='序号'), recvlistbox2.heading('#1', text='学号')
self.recvlistbox2.heading('#2', text='姓名'), recvlistbox2.heading('#3', text='数据')
self.recvlistbox2.column("#0", minwidth=0, width=50, stretch=NO, anchor='center')
self.recvlistbox2.column("#1", minwidth=0, width=90, stretch=NO, anchor='center')
self.recvlistbox2.column("#2", minwidth=0, width=90, stretch=NO, anchor='center')
self.recvlistbox2.column("#3", minwidth=0, width=370, stretch=NO, anchor='center')
for i in range(70):
self.recvlistbox2.insert('', index='end', text=i+1, values=('', '', '')) # 据说添加表格信息比较烦人?
self.recvlistbox2.bind('<Double-1>', treeviewClick)
# (3)用树状图来表示是否验收成功
self.recvlistbox3 = ttk.Treeview(frm_left, height=19, columns=('name'), selectmode='extended')
self.recvlistbox3.heading('#0', text='序号'), recvlistbox3.heading('#1', text='姓名')
self.recvlistbox3.column("#0", minwidth=0, width=180, stretch=NO, anchor='e')
self.recvlistbox3.column("#1", minwidth=0, width=100, stretch=NO, anchor='center')
# (4)滚动条控件定义与配置
VScroll1 = Scrollbar(frm_right, orient='vertical', command=self.recvlistbox2.yview)
VScroll1.place(relx=0.971, rely=0.068, relwidth=0.024, relheight=0.918)
# 给treeview1添加配置
self.recvlistbox2.configure(yscrollcommand=VScroll1.set)
VScroll2 = Scrollbar(frm_middle, orient='vertical', command=self.recvlistbox.yview)
VScroll2.place(relx=0.96, rely=0.068, relwidth=0.024, relheight=0.918, width=5)
# 给Listbox添加配置
self.recvlistbox.configure(yscrollcommand=VScroll2.set)
VScroll3 = Scrollbar(frm_left, orient='vertical', command=self.recvlistbox3.yview)
VScroll3.place(relx=0.939, rely=0.496, relwidth=0.024, relheight=0.5, width=10)
# 给treeview2添加配置
self.recvlistbox3.configure(yscrollcommand=VScroll3.set)
  为根节点的窗口添加**菜单栏**并使用```grid```属性调节上述定义的全部控件。
# (5)添加菜单栏
self.menubar = tk.Menu(self.root)
self.filemenu1 = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label='文件', menu=filemenu1), \
self.filemenu1.add_command(label='保存实时接收的数据到 TXT', command=self.savelog), \
self.filemenu1.add_command(label='清空全部内容', command=self.clear_all), \
self.filemenu1.add_command(label='退出程序', command=self.root.destroy)
self.filemenu2 = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label='学生信息导入导出', menu=self.filemenu2), \
self.filemenu2.add_command(label='导入学生信息(Excel)', command=self.openshow), \
self.filemenu2.add_command(label='导出学生数据(Excel)', command=self.savedata)
self.filemenu3 = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label='帮助', menu=self.filemenu3), \
self.filemenu3.add_command(label='关于...', command=self.EzXxY), \
self.filemenu3.add_command(label='访问站点', command=self.EzXxY_network)
# 为窗口配置菜单栏
self.root.config(menu=menubar)
# (6)grid布局
# 实时接收的数据(列表框)
self.labelrecv.grid(row=0, column=0, padx=2, pady=10, sticky=W)
self.recvlistbox.grid(row=1, column=0, padx=2, pady=10, sticky=W)
# 最后一次收到每人的数据(树形表格)
self.labelrecv2.grid(row=0, column=0, padx=2, pady=10, sticky=W)
self.recvlistbox2.grid(row=1, column=0, padx=2, pady=10, sticky=W)
# 验收结果区(树状图)
self.recvlistbox3.grid(row=7, columnspan=2, pady=5) # 由于需要多行对串口进行配置,此处为第7行,跨两列的布局
由于需要读取的同学们发送到网关的数据,需要在本地PC对接收到数据的网关进行配置,以便使用串口直接读取同学们发送的信息。不过python本身不支持读取串口数据,需要额外安装第三方串口库pyserial
才能实现这部分的操作。对串口的配置和使用的功能,其他应用程序早已摸索透彻,此程序需要复现其一部分功能即可,不再详细展开(可以直接在Github上找一个来用,根据上述方法配置到应用程序的frm_left
窗口中)。
不过直接找的串口读写代码很可能会遇到各种各样的问题,比如使用多线程实现的读串口数据操作,原作者专门删掉逻辑中比较重要的部分代码,让程序运行时有各种BUG,需要我们自己解决这些问题。
最终实现的程序界面如下图所示:
3. 使用第三方库ttkbootstrap
的主题美化界面
默认主题下编写出的tkinter程序界面看起来有些古老,可以使用第三方库ttkbootstrap
进行美化,且只需更改3行
代码即可实现,非常好用。比较如下:
目前ttkbootstrap
库自带的美化主题共有18个,其中亮色主题13个,暗色主题5个,分别为:
亮色
cosmo - flatly - litera - minty - lumen - sandstone - yeti
pulse - united - morph - journal - simplex - cerculean
暗色
darkly - superhero - solar - cyborg - vapor
可自行选择使用,更改style中的theme参数即可。经minty主题美化后的程序页面如下图所示:
当然也可以搭配自己的主题样式,在终端运行ttkbootstrap
库自带的ttkcreator的demo程序即可。
python -m ttkcreator
4. 混淆加密源代码并打包修改exe程序图标
使用pyinstaller打包exe程序可以指定程序的图标,不过Windows系统上的exe应用程序图标需要支持多分辨率才可以在不同大小的图标状态下正常显示。此时就需要借助专门的ico格式图标生成器来导出多分辨率的图标文件了。
参考Murphy丶悦的博客文章,使用专业软件Axialis IconWorkshop
制作自己的应用程序图标,选择前两行有48x48、32x32、24x24、16x16像素的参数和左下角竖列的两个256x256像素的参数,导出为多分辨率的单个ico文件即可。
终端下的不同打包命令,不写-w则打包的应用程序包含Windows命令窗口:
① 加密打包为单个可执行应用程序,不含动态链接库dll及其他文件,不含命令窗口(Windows下)
pyinstaller -F -w -i tkinter_1_5.ico tkinter_1_5.py --key=EzXxY
② 加密打包应用程序,包含动态链接库dll及其他文件,不含命令窗口(Windows下)——执行速度比①块
pyinstaller -D -w -i tkinter_1_5.ico tkinter_1_5.py --key=EzXxY
本实例对应的方法②打包出的应用程序压缩包下载链接→LoRa网关串口收发验收助手_V1.5.zip←