PyQt应用程序打包
前言
打包是桌面程序开发无法回避的主题。
客户不会安装,客户懒得安装。客户总是对的。
Python开发的应用程序的打包其实已经相对成熟。PyInstaller是一个常用的解决方案。
PyInstaller
安装
PyInstaller是一个Python包,安装可以通过命令行
conda install pyinstaller
或者用pip也是一样的流程。
使用
打包的时候,通常用命令行完成
pyinstaller main.py
对于PyQt5的程序,可以增加命令参数-w
来去掉终端黑窗口。
如果是多次运行,还可以增加-y
来避免询问是否删除dist文件夹。
运行
pyinstaller main.y -y -w
之后,会产生两个文件夹:build和dist。在这个文件夹下面都有一个main子目录(也就是脚本的名称)。dist文件夹就是最终拷贝给用户的。
另外,还可以用单文件方式发布。
pyinstaller main.y -y -w --onefile
或者
pyinstaller main.y -y -w -F
注意:使用单文件的方式,在运行程序的时候,需要等待解压缩的过程,启动时间可能略微延长。
spec文件
一次运行pyinstaller之后,会自动生成一个spec文件:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['linechart.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
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,
a.binaries,
a.zipfiles,
a.datas,
[],
name='linechart',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
有这个文件之后,就可以直接运行:
pyinstaller main.spec
这个文件中,可以设置可执行程序的名字,图标。最重要是datas=[]
,可以用来把预先准备的文件拷贝到发布的程序中。
#...
datas=['images', 'data', 'doc'],
#...
UPX
使用
如果对产生的发布文件大小不满意,还有一个免费的工具UPX来缩减文件尺寸。
UPX下载来就是一个执行文件。
pyinstaller main.y -y -w --upx-dir UPX可执行文件目录
收益
一个很简单的PyQt5(包括QtChart的例子)。
import random
import sys
from PyQt5.QtChart import QChart, QChartView, QLineSeries
from PyQt5.QtCore import QPointF
from PyQt5.QtGui import QPainter
from PyQt5.QtWidgets import QMainWindow, QApplication, QVBoxLayout, QWidget, QPushButton
class TestChart(QMainWindow):
def __init__(self):
super().__init__()
self.series = QLineSeries()
self.series.setName("Line 1")
self.randomize()
self.chart = QChart()
self.chart.legend().hide()
self.chart.addSeries(self.series)
self.chart.createDefaultAxes()
self.chart.axisX().setRange(0, 10)
self.chart.axisY().setRange(0, 1)
self.chart.setTitle("Simple line chart example")
self.chart.autoFillBackground()
self._chart_view = QChartView(self.chart)
self._chart_view.setRenderHint(QPainter.Antialiasing)
self._vbox = QVBoxLayout(self)
self._vbox.addWidget(self._chart_view)
self.randomize_button = QPushButton("Randomize", self)
self._vbox.addWidget(self.randomize_button)
self.randomize_button.clicked.connect(self.randomize)
self._mw = QWidget()
self._mw.setLayout(self._vbox)
self.setCentralWidget(self._mw)
def randomize(self, clicked=False):
points = [QPointF(i, data) for (i, data) in enumerate(random.random() for _ in range(10))]
self.series.replace(points)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TestChart()
window.show()
window.resize(800, 600)
sys.exit(app.exec())
上面这个程序,如果使用UPX,可以把win64最终的文件压缩包从48M缩减到36M。
结论
- Pyinstaller已经相当成熟;
- UPX可以缩减文件尺寸;
- numpy的MKL动态链接库文件很大……真的很大……