【PyQt5】程序打包分发(1)PyInstaller

1、写在前面

本文分为一系列步骤,使用PyInstaller将简单或复杂的 PyQt5 应用程序构建成 Windows 上的可分发 EXE 文件。
这里主要是记录将exe和dll等资源文件分离的打包形式。(把所有程序只打包成一个exe文件不做说明)
本文同样适用PySide2

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目录结构

【PyQt5】程序打包分发(1)PyInstaller_第1张图片

3.3运行效果

有标题,有图标、有Label、有按钮,按钮按一下退出程序
【PyQt5】程序打包分发(1)PyInstaller_第2张图片

4、.spec文件

.spec文件包含PyInstaller用于打包应用程序的构建配置和说明,每个PyInstaller项目都有一个.spec文件。
这里只介绍常用的,配置后打包没问题的,其他的参数自己去查资料

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(['app.py'],	# 主程序入口
             pathex=[],
             binaries=[],
             datas=[	# 外部资源路径,看下面单独介绍
             	('icons', 'icons'), 
             	('path1', 'path2')
             ],
             hiddenimports=[],
             hookspath=[],
             hooksconfig={},
             runtime_hooks=[],
             excludes=['matplotlib', '...'],	# 不需要打包的库,比如:'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',      # 设置打包后的软件名字,最终打包后的软件名就叫 Hunzi666.exe
          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参数说明

  • datas
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.

你可以在程序的目录下,看到两个文件夹分别是distbuild

  • PyInstaller使用build文件夹来收集和准备打包文件,它包含分析结果和一些附加日志。在大多数情况下,可以忽略此文件夹的内容,除非尝试调试问题。
  • dist文件夹包含要分发的文件。这包括捆绑为可执行文件的应用程序,以及任何关联的库(例如 PyQt5)和二进制.dll文件。运行应用程序所需的一切都将在此文件夹中,这意味着可以使用此文件夹并将其“分发”给其他人以运行你的应用程序。
    【PyQt5】程序打包分发(1)PyInstaller_第3张图片
    看起来就比较专业一点是吧

现在你可以在dist文件夹中运行Hunzi666.exe,你就会看到你熟悉的窗口:
【PyQt5】程序打包分发(1)PyInstaller_第4张图片
打包成功!

6、打包出现的问题

待补充、、、

7、一些经验

待补充、、、

8、制作windows安装程序

待补充、、、

你可能感兴趣的:(PyQt5,Python,python,qt5)