1、写在前面
本文分为一系列步骤,使用PyInstaller将简单或复杂的 PyQt5 应用程序构建成 Windows 上的可分发 EXE 文件。 这里主要是记录将exe和dll等资源文件分离的打包形式。(把所有程序只打包成一个exe文件不做说明)
2、安装PyInstaller
建议在虚拟环境中安装,比如 conda 或者 virtualenv 或者你的应用程序虚拟环境,虚拟环境中只安装程序用到的包,以保持环境清洁。
pip3 install PyInstaller
3、准备自己的应用程序
这里我使用一个DEMO来演示打包过程,DEMO中包含窗口程序、图标等资源。其中图标你可当做是你程序中引用的外部资源,比如图片、文本、本地数据库、第三方dll等资源,他们的操作都是类似的,自己举一反三!
关于引用外部资源打包后失效,需要注意的是路径:base_dir = os.path.dirname(__file__) 用来获取程序的路径,在引用外部资源时拼接上该路径,就能保证不管程序移动到任何文件夹下,都能正常运行!!!!!
3.1 demo程序
import sys, os
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QVBoxLayout, QLabel, QPushButton, QWidget
base_dir = os.path.dirname(__file__)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Hello World")
layout = QVBoxLayout()
label = QLabel("My simple app.")
label.setMargin(10)
layout.addWidget(label)
button = QPushButton("Push")
button.setIcon(QtGui.QIcon(os.path.join(base_dir, "icons", "lightning.png")))
button.pressed.connect(self.close)
layout.addWidget(button)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon(os.path.join(base_dir, 'icons', 'hand.ico')))
w = MainWindow()
app.exec()
3.2目录结构
3.3运行效果
有标题,有图标、有Label、有按钮,按钮按一下退出程序
4、.spec文件
.spec文件包含PyInstaller用于打包应用程序的构建配置和说明,每个PyInstaller项目都有一个.spec文件。 这里只介绍常用的,配置后打包没问题的,其他的参数自己去查资料
block_cipher = None
a = Analysis(['app.py'],
pathex=[],
binaries=[],
datas=[
('icons', 'icons'),
('path1', 'path2')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['matplotlib', '...'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='Hunzi666',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
icon='icons\\hand.ico'
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='app')
.spec 如果在 Windows 上生成文件,则路径分隔符将为\\ 。要在 macOS 上使用相同.spec 的文件,需要将分隔符切换为/ 。 值得庆幸的是/ 也适用于 Windows。
4.1参数说明
a = Analysis(datas=[('icons', 'icons'),
('path1', 'path2')])
括号里面的两个参数,第一个:打包前的资源文件夹 路径,第二个:打包后的资源文件夹 路径
作用就是把原来path1 文件夹下面的所有内容拷贝到path2 文件夹中,(其中path1和path2名称要相同) 就比如demo程序中的 icons 文件夹。打包完程序之后,打包后的程序目录下肯定也要有一个icons 文件夹,且引用的路径,里面的文件要和原来的一模一样。
你可以试试,如果你不配置这个参数,看看打包后的结果。在这基础上,你手动把这些文件夹复制到打包目录里面,再看看结果,你就知道有什么用了。 你会发现通过配置参数 和 你手动复制的效果是一样的,所以你可以把你引用的第三方的所有资源,都通过这种方式复制到打包目录里面!
5、打包
写好.spec 文件后,可以运行它来打包程序。
pyinstaller app.spec
你将会看到,可以忽略。。。
U:\home\martin\helloworld>pyinstaller app.py
INFO: PyInstaller: 3.6
INFO: Python: 3.7.6
INFO: Platform: Windows-10-10.0.18362-SP0
...
...
...
INFO: Building EXE from EXE-00.toc completed successfully.
INFO: checking COLLECT
INFO: Building COLLECT because COLLECT-00.toc is non existent
INFO: Building COLLECT COLLECT-00.toc
INFO: Building COLLECT COLLECT-00.toc completed successfully.
你可以在程序的目录下,看到两个文件夹分别是dist 和build 。
- PyInstaller使用
build 文件夹来收集和准备打包文件,它包含分析结果和一些附加日志。在大多数情况下,可以忽略此文件夹的内容,除非尝试调试问题。 dist 文件夹包含要分发的文件。这包括捆绑为可执行文件的应用程序,以及任何关联的库(例如 PyQt5)和二进制.dll文件。运行应用程序所需的一切都将在此文件夹中,这意味着可以使用此文件夹并将其“分发”给其他人以运行你的应用程序。 看起来就比较专业一点是吧
现在你可以在dist 文件夹中运行Hunzi666.exe ,你就会看到你熟悉的窗口: 打包成功!
6、打包出现的问题
待补充、、、
7、一些经验
待补充、、、
8、制作windows安装程序
待补充、、、
|