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

Posted

技术标签:

【中文标题】使用 cx_Freeze 冻结时不显示主窗口图标【英文标题】:Main Window Icon Not Displayed when Frozen with cx_Freeze 【发布时间】:2018-10-17 17:14:34 【问题描述】:

我想在使用 cx_Freeze 冻结基线后在 PyQt 窗口中显示自定义图标。当从 IDE(对我来说是 Spyder)执行解冻脚本时,该图标显示正常。我正在使用 PyQt5、Python 3.6 和 Windows 10。这是我的 Python 脚本 (IconTest.py),它创建一个主窗口并显示图标的路径以及该路径是否存在。图标文件需要和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 目录中的可执行文件)。如您所见,秒表图标已替换为通用窗口图标:

建议?

【问题讨论】:

您必须改进最初的问题或至少删除它,而不是创建多个具有相同问题的帖子 我标记了另一个问题,供版主删除。我无法删除它,因为它已被回答。问题和回答的方向是错误的,所以我觉得有必要用最少、完整和可行的代码完全重写问题。 图标是否真的被复制到了构建文件夹中? @slalomchip 我已删除我对您其他问题的回答,以便您将其删除。 @Jannick - 是的,图标文件实际上已复制到 build 文件夹。否则,窗口中的第二行将是 False 而不是 True 【参考方案1】:

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

如果这是真的,你有两个选择:

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

    如果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 子目录中,与其他版本相反。

【讨论】:

(1) 尝试 PNG 文件没有任何区别。 (2)发现需要添加Platforms目录。我想我在最小化setup.py 时从未从exe.win-amd64-3.6 目录中删除它。我在上面的问题中更正了脚本。 (3) 我使用的是 cx_Freeze 5.1.1。我认为您可能是正确的,某处缺少 .dll 文件。我尝试了对exe.win-amd64-3.6 目录和lib 目录的不同添加。 Platform 目录必须添加到 exe.win-amd64-3.6,而不是 lib。仍在寻找正确的解决方案 - 尚未找到。 @slalomchip 您是否尝试过在设置脚本中使用packages = ['atexit', 'PyQt5'] 我在安装脚本中包含了packages = ['atexit', 'PyQt5'],但没有成功。无论PyQt5 是否在packages 列表中,生成的lib 目录中的PyQt5 目录都是相同的(6 个目录中的148 个文件)。我不明白将atexit 添加到package 列表的目的,除非我将atexit 合并到我的图标脚本中(我还没有这样做)。您建议在package 列表中包含atexit 有什么原因吗?仍在搜索。 @slalomchip 更具体地说: 1. 尝试找出在您的 python 安装中哪个 DLL 解释 .ico 图像,它应该类似于 lib\site-packages\PyQt5\Qt\plugins\imageformats\qico.dll; 2. 检查这个DLL是否被cx_Freeze包含在生成的lib目录中,它应该在某个plugins\imageformats目录中;我的猜测是,将PyQt5 添加到packages 列表会告诉cx_Freeze 包含整个PyQt5 目录; 3. 使用QApplication.addLibraryPath 告诉您的应用程序在哪里可以找到这个plugins 目录。 @slalomchip 我建议在packages 列表中包含atexit 的原因是它是在cx_FreezePyQt5 示例设置脚本中完成的,请参阅lib\site-packages\cx_Freeze\samples\PyQt5;老实说,我也不明白目的。【参考方案2】:

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

    删除import sys 删除了exeDir = ...这一行 删除了platformsPath = ...这一行 从includes = 列表中删除了platformsPath

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于使用 cx_Freeze 冻结时不显示主窗口图标的主要内容,如果未能解决你的问题,请参考以下文章

使用 cx_freeze 冻结 py 脚本时的问题

MFC EditBrowse 控件在运行时不显示文件夹图标

使用 cx_Freeze 冻结 Python 3.7 脚本时如何修复错误

使用 cx_Freeze 冻结成可执行文件后如何知道当前文件路径?

使用 cx_freeze 4.3.1 冻结 h5py 2.4 时出错

如何使用 cx_Freeze 冻结双模式(GUI 和控制台)应用程序?