如何在使用 py2exe 时包含 ui 和图像文件



我正在使用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_libsmsCafeteriaMenu.pyc", line 37, in __init__
File "metusuite_libsmsCafeteriaMenu.pyc", line 17, in __init__
RuntimeError: Unable to open/read ui device

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

因此,如何在py2exe结构中添加我的UI和png文件?或者对于我想要完成的任务,是否有任何替代方法?

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

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

pyside-uic

我非常喜欢使用pyside-uic方法来加载 ui 文件,因为它是将 ui 文件加载到与我在 C++ 中对 Qt 的了解相关的程序中的最直接方法。pyside-uic包含在 PySide 应用程序中,对我来说,它可以在我的 Python 安装的脚本目录中找到,例如C:Python27Scriptspyside-uic.exe.请注意C++编译如何处理 UI 文件,我通常将 ui 文件编译为具有类似 ui_[UI 文件的名称].py:

C:Python27Scriptspyside-uic mainwindow.ui > ui_mainwindow.py

在该生成的.py文件中,pyside-uic 创建一个与前缀为 Ui_ 的 ui 文件的基类同名的类。因此,例如,如果您创建了一个包含名为 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的站点包目录中而不是在脚本中(如果它对你来说在同一个地方,你可以随时复制它)。

C:Python27libsite-packagesPySidepyside-rcc.exe

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

C:Python27libsite-packagesPySidepyside-rcc.exe -py2 MyProject.qrc > MyProject_Resources.py

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

将一切整合在一起

由于您已经直接加载了 UI 文件QUiLoader,因此只需重构 QUiLoader 语句即可加载从资源系统打开 UI 资源的 QFile。要使用资源系统中的文件,您需要做的就是将资源.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 的内容中,并将 msResources 文件作为包的一部分导入__init__.py文件中。这样,一旦您创建了.py文件并将其导入到程序中,额外的文件将封装在您的包中,您无需更改 setup.py 文件。在进行 py2exe 转换之前,运行重构的程序应该可以正常工作。此外,无论您如何处理 ui 文件,您始终需要使用资源文件才能将图标打包到程序中。出于可移植性原因,使用资源文件作为图标可能是一个好习惯。

最新更新