5

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

首先,这是我的文件树:我在 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”文件夹中构建了 metusuite.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 文件?或者有什么替代方法可以解决我想要完成的事情吗?

4

1 回答 1

10

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

  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 后,需要通过 self.ui 访问小部件的所有连接和 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 资源系统的文档显示,资源文件实际上只是一个 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 代码中使用时,我将更改__init__GuiCafeteriaMenu 的方法以从资源中加载和使用 ui 文件:

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

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

于 2012-11-18T19:00:11.463 回答