【问题标题】:How can I include ui and image files while using py2exe?如何在使用 py2exe 时包含 ui 和图像文件?
【发布时间】:2012-11-16 11:09:02
【问题描述】:

我正在开发一个使用 Python 2.7 和 PySide 1.1.2 的项目。我的代码在我的 GNU/Linux 上运行没有任何问题,但我也想为 Windows(7 和 8)分发。我不能指望用户安装 Python 和 PySide,所以我决定使用 py2exe(我也尝试了 cx_freeze 和 pyinstaller)。

首先,这是我的文件树:My Project on GitHub

我创建了一个 setup.py,这里是:

# -*- coding: utf-8 -*-

from distutils.core import setup
import py2exe

setup(
    console=['bin/metusuite.py'],
    name='metusuite',
    version='0.1',
    author='H. Gökhan Sarı',
    author_email='me@th0th.me',
    packages=['metusuite_libs'],
    package_dir={'metusuite_libs': 'metusuite_libs'},
    package_data={'metusuite_libs': ['ui/*', 'images/*']},
    scripts=['bin/metusuite.py'],
    url='https://github.com/th0th/metusuite/',
    license='LICENSE.txt',
    description='METU Suite.',
    long_description=open('README.md').read(),
)

当我跑步时

setup.py py2exe

它成功地在 'dist' 文件夹中构建了 metussuite.exe,但是,由于应用程序依赖于外部用户界面文件 - 使用 Qt Designer 创建 - 并且找不到它们,我收到错误:

Designer: An error has occurred while reading the UI file at line 1, column 0: Premature end of document.
Traceback (most recent call last):
  File "metusuite.py", line 38, in <module>
  File "metusuite_libs\msCafeteriaMenu.pyc", line 37, in __init__
  File "metusuite_libs\msCafeteriaMenu.pyc", line 17, in __init__
RuntimeError: Unable to open/read ui device

我不知道应该如何将 *.ui 文件(还有一些 .png 图标)添加到该结构中。我正在考虑将 .ui 文件转换为 Python 代码,然后当我需要添加一些图标时会遇到同样的问题。

因此,如何在 py2exe 结构中添加我的 ui 和 png 文件?或者有什么替代方法可以解决我想要完成的任务吗?

【问题讨论】:

    标签: windows py2exe pyside


    【解决方案1】:

    嗯,我认为你可以做两件现实的事情之一:

    1. 使用 pyside-uic 将您的 .ui 文件编译为 .py 文件,并修改您的代码以有条件地加载用户界面的 py 文件并将 png 文件放在 Qt 资源文件中
    2. 创建一个 Qt 资源文件,其中包含您的 ui 文件,使用 pyside-rcc 编译,然后使用 QtUiTools 或类似的过程加载 ui 文件

    pyside-uic

    我非常喜欢使用pyside-uic 方法来加载 ui 文件,因为它是将 ui 文件加载到与我在 C++ 中的 Qt 知识相关的程序中最直接的方法。 pyside-uic 包含在 PySide 应用程序中,对我来说,它位于我的 Python 安装的 Scripts 目录中,例如C:\Python27\Scripts\pyside-uic.exe。记下 C++ 编译如何处理 ui 文件,我通常将 ui 文件编译为具有类似 ui_[Name of the ui file].py 的名称:

    C:\Python27\Scripts\pyside-uic mainwindow.ui > ui_mainwindow.py
    

    在生成的 .py 文件中,pyside-uic 创建一个类,其名称与 ui 文件的基类名称相同,并以 Ui_ 开头。因此,例如,如果您创建了一个包含名为 MainWindow 的类的定义的 mainwindow.ui,则创建的类将是 Ui_MainWindow。如果 ui 文件定义了一个名为 SourceWindow 的类,则 .py 文件中的类为 Ui_SourceWindow。在 Qt Designer 中,您可以通过在对象树的根元素(窗口右上角)中设置 objectName 来设置类名。

    使用您的文件 cafeteria_menu、ui 和 dialog_login.ui,您将获得派生类 Ui_cafeteria_menu 和 Ui_dialog_login。

    生成 .py 文件后,可以通过将其导入到小部件的定义文件中并使用 Ui 文件中类的 setupUi 方法来使用它

    from PySide import QtCore, QtGui
    from ui_mainwindow import Ui_MainWindow
    
    class MainWindow(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
    
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
    

    为类定义 ui 后,小部件的所有连接和 ui 元素都需要通过 self.ui 访问

            self.ui.lineEdit.textChanged[str].connect(self.processText)
    

    由于您必须将 .png 文件放在 Qt 资源文件中,我将在下一节中讨论它。

    pyside-rcc

    pyside-uic 一样,pyside-rcc 包含在 PySide 应用程序中,尽管我的位于 Python 的 site-packages 目录中,而不是在 Scripts 中(如果它在同一个地方,你可以随时复制它)。

    C:\Python27\lib\site-packages\PySide\pyside-rcc.exe
    

    在编译 Qt 资源文件之前,您必须首先使用其中一个 Qt 工具创建它。我使用 Qt Creator 因为它可以在一个应用程序中执行几乎所有与 Qt 相关的功能。 Qt Resource System 的文档显示资源文件实际上只是一个 XML 文件,它定义了资源系统的文件路径和内部路径。您可以根据需要设置和组织文件,但是在编译时,资源文件中定义的所有文件都必须位于文件的同一目录或子目录中。定义资源文件后,您需要使用 pyside-rcc.exe 将其编译为 .py 文件。我通常将资源文件命名为与项目相同的名称,并将所有内容保存在一个资源文件中,以便更简洁地处理资源。

    C:\Python27\lib\site-packages\PySide\pyside-rcc.exe -py2 MyProject.qrc > MyProject_Resources.py
    

    -py2 开关定义文件的输出应针对 Python 2.x 进行格式化。如果您正在使用 Python 3.x 或计划将来使用它,您可以使用 -py3 开关,结果将与 Python 3.x 兼容。

    把它们放在一起

    由于您已经直接加载了 ui 文件QUiLoader,您只需重构您的 QUiLoader 语句以加载从资源系统打开 ui 资源的 QFile。要使用资源系统中的文件,您只需将您的 Resource .py 文件(从 pyside-rcc 生成的文件)导入程序的主脚本文件,资源文件的最后一行是调用qInitResources() 初始化整个程序中要使用的资源。要使用 QFile 加载文件,请使用以“:”开头的路径,然后引用在资源文件中定义的路径。您可以创建一个文件 msResources.qrc,其中包含 ui 和将您的 ui 和 png 文件定义为子类别的图像。

    所以,如果你的资源文件看起来像这样

    /ui
        cafeteria_menu.ui
        dialog_login.ui
    /images
        cafeteria-menu.png
        exit.png
        logo.png
        mail-fetch.ong
    

    而且,如果你想加载这些文件,你只需要像这样创建一个 QIcon 或 QFile:

    cafeteriaMenuIcon = QtGui.QIcon(":/images/cafeteria-menu.png")
    cafeteriaMenuUi = QtCore.QFile(":/ui/cafeteria_menu.ui")
    

    在 msCafeteriaMenu 中用于 GUICafeteriaMenu 的代码中,我只需更改 GuiCafeteriaMenu 的 __init__ 方法以从资源中加载和使用 ui 文件:

    uiFile = QFile(":/ui/cafeteria_menu.ui")
    uiFile.open(QFile.ReadOnly)
    UiLoader.load(uiFile, self)
    uiFile.close()
    

    我可能会将 pyside-rcc 的输出放入metsuite_libs 包中,放入类似msResources.py 的文件中,并将__init__.py 文件中的msResources 文件作为包的一部分导入。这样,一旦您创建了 .py 文件并将其导入您的程序,额外的文件将被封装在您的包中,您无需更改 setup.py 文件。在进行 py2exe 转换之前,运行重构的程序应该可以正常工作。此外,无论您如何处理 ui 文件,您总是需要使用资源文件才能将图标打包到程序中。出于可移植性的原因,使用资源文件作为图标可能是一个好习惯。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多