使用 cx_Freeze 冻结时主 Window 图标不显示

Main Window Icon Not Displayed when Frozen with cx_Freeze

我想在使用 cx_Freeze 冻结基线后在 PyQt window 中显示自定义图标。当从 IDE(对我来说是 Spyder)中执行解冻脚本时,该图标显示正常。我正在使用 PyQt5、Python 3.6 和 Windows 10。这是我的 Python 脚本 (IconTest.py),它创建一个主 window 并显示路径到图标以及路径是否存在。图标文件需要和IconTest.py:

在同一个目录
import sys, os
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QIcon

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):        
        self.setGeometry(200, 300, 600, 100)
        if getattr(sys, 'frozen', False): #If frozen with cx_Freeze
            self.homePath = os.path.dirname(sys.executable)
        else: # Otherwise, if running as a script (e.g., within Spyder)
            self.homePath = os.path.dirname(__file__)
        self.iconFileName = os.path.join(self.homePath, 'myIcon.ico')
        self.setWindowIcon(QIcon(self.iconFileName))        
        self.setWindowTitle('Icon')
        self.label1 = QLabel(self)
        self.label2 = QLabel(self)
        self.label1.move(10, 20)
        self.label2.move(10, 40)
        self.label1.setText("Path to icon file: " + str(self.iconFileName))
        self.label2.setText("Does file exit?  " + str(os.path.exists(self.iconFileName)))
        self.show()

if __name__ == '__main__':    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

这是我在 运行 Spyder 中的脚本(解冻)时的结果。如您所见,显示了一个类似于秒表的图标:

这是我用来创建冻结基线的 setup.py:

from cx_Freeze import setup, Executable
import os, sys

exeDir = os.path.dirname(sys.executable)
platformsPath = os.path.join(exeDir, "Library\Plugins\Platforms\")
iconPath = os.path.join(os.path.dirname(__file__), "myIcon.ico")
exe=Executable(script="IconTest.py", base = "Win32GUI", icon = iconPath)
includes=[iconPath, platformsPath]
excludes=[]
packages=[]
setup(
     version = "0.1",
     description = "My Icon Demo",
     options = {'build_exe': {'excludes':excludes,'packages':packages,'include_files':includes}},
     executables = [exe]
     )

这是我在 运行 冻结脚本(build 目录中的可执行文件)时的结果。如您所见,秒表图标已替换为通用 windows 图标:

建议?

有趣的问题和很好的最小示例。经过一番搜索后,我猜想这可能与 PyQt5 缺少 plugin/DLL 以在冻结的应用程序中显示 .ico 图像文件有关。参见例如How to load .ico files in PyQt4 from network.

如果这是真的,您有 2 个选择:

  1. 使用 .png 文件作为 window 图标尝试相同的示例

  2. 如果plugins目录包含在冻结的应用程序中但找不到,请尝试添加以下语句

    pyqt_dir = os.path.dirname(PyQt5.__file__)
    QApplication.addLibraryPath(os.path.join(pyqt_dir, "plugins"))`
    

    之前

    app = QApplication(sys.argv)
    

    在你的主脚本中。参见 this answer

    如果 plugins 目录未包含在冻结的应用程序中,您需要使用 build_exe 选项的 include_files 条目告诉 cx_Freeze 包含它。要么你设法动态地让你的安装脚本将它包含在 PyQt5 正在寻找它的地方,使用 include_files 中的元组 (source_path_to_plugins, destination_path_to_plugins),或者你告诉 PyQt5 到哪里使用 QApplication.addLibraryPath 查找它。

    在你之前对这个问题的提问中,你实际上有一个条目可以在你的安装脚本中包含一个 Plugins\Platforms 目录,也许你只需要修复这个包含。请注意 cx_Freeze 版本 5.1.1(当前)和 5.1.0 将所有包移动到 build 目录的 lib 子目录中,与其他版本相反。

答案: 我一直在使用 Anaconda 平台,并在其他帖子中读到,由于 Anaconda 构建其内容的方式,PyInstaller 和 Anaconda 之间存在问题。考虑到 cx_Freeze 可能存在同样的问题,我在另一台机器上安装了 Python(没有 Anaconda),并冻结了这个新 Python 安装的脚本。 该图标按预期出现在冻结的脚本中。为了使图标正确显示,我对 setup.py 脚本进行了以下更改:

  1. 已移除import sys
  2. 删除了行 exeDir = ...
  3. 删除了行platformsPath = ...
  4. 已从 includes = 列表中删除 platformsPath

我遇到了类似的问题并发布了一个答案here

基本上,我通过将文件存储在 python 字节数组中并通过 QPixmap 将其加载到 QIcon 中来解决这个问题。