使用 pyuic 与 uic.loadUi 的好处

Posted

技术标签:

【中文标题】使用 pyuic 与 uic.loadUi 的好处【英文标题】:Benefits of using pyuic vs uic.loadUi 【发布时间】:2020-04-16 18:56:02 【问题描述】:

我目前正在使用 python 和 Qt,这对我来说是来自 C++ 版本的新功能,我意识到在 oficial documentation 中它说可以从 .ui 加载 UI 文件或创建 python类并将文件转换为.py 文件。

我得到了使用.ui 的好处,它是动态加载的,所以不需要在每次更改时将其转换为 python 文件,但是这样做有什么好处?,你在运行时间上有什么改进吗?是别的吗?

谢谢

【问题讨论】:

【参考方案1】:

嗯,这个问题很危险地接近“基于意见”的标志,但它也是一个常见的问题,我相信它至少值得部分回答。

从概念上讲,使用pyuic 方法和uic.loadUi() 方法是相同的并且行为方式非常相似,但有一些细微差别。 为了更好地解释这一切,我将使用有关 using Designer 的文档作为参考。

pyuic 方法,或“python 对象”方法

这可能是最流行的方法,尤其是在初学者中。它的作用是创建一个用于创建 ui 的 python 对象,如果按照 “单一继承” 方法使用,它还充当 ui 本身的“接口”,因为其实例创建的ui 对象具有所有可用的小部件作为其属性:如果您创建一个按钮,它将作为ui.pushButton 可用,第一个标签将为ui.label 等等。

在上面链接的文档的第一个示例中,ui 对象是独立的;这是一个非常基本的示例(我相信它只是为了演示其用法,因为除了在 Designer 中创建的连接之外,它不会提供很多交互)并且不是很有用,但它与单继承方法非常相似:按钮将是self.ui.pushButton,等等。

如果使用“多重继承”方法,ui对象将与widget子类重合。在这种情况下,按钮将为self.pushButton,标签为self.label,等等。

从 python 的角度来看,这非常重要,因为这意味着这些属性名称将覆盖 any 将使用相同名称的其他实例属性:如果您有一个名为“saveFile”的函数并且您将按钮命名为“saveFile”,一旦返回setupUi,您将不再有任何[直接] 访问该实例方法的权限。在这种情况下,使用单一继承方法可能会有所帮助 - 但实际上,您可以更加注意函数和对象名称。

最后,如果您不知道 pyuic 生成的文件的作用和用途,您可能倾向于使用它来创建程序。出于很多原因,这是错误的,但最重要的是,因为您可能肯定会在某些时候意识到您必须编辑您的 ui,并且将新更改与修改后的代码合并显然是您不想面对的 PI​​TA .

我最近answered 提出了一个相关问题,试图解释更深入地调用setupUi() 时会发生什么。

使用uic.loadUi

我想说这是一种更“模块化”的方法,主要是因为它更直接:正如问题中已经指出的那样,您不必在每次修改 ui 文件时都不断地重新生成它们。

但是,有一个问题。

首先:显然,从 XML 文件加载、解析和构建 UI 不如直接从代码创建 ui 快(这正是 pyuic 文件在 setupUi() 中所做的事情)。

那么,至少有一个关于布局内容边距的相对较小的错误:当使用loadUi 时,默认的系统/表单边距可能会被完全忽略,如果没有明确设置,则设置为 0。有一个解决方法,在Size of verticalLayout is different in Qt Designer and PyQt program 中解释(感谢eyllanesc)。


比较

pyuic 接近

优点:

更快;在一个包含 100 个按钮和一个包含 1200 多个项目的 tablewidget 的非常简单的测试中,我测量了以下最佳结果:

pyuic 加载:33.2ms loadUi 加载:51.8ms

由于多种原因,这个比率显然不是线性的,但你可以理解

如果与单继承方式一起使用,可以防止意外的实例属性覆盖,也意味着更“包含”的对象结构 使用 python 导入可确保项目结构更加一致,尤其是在部署过程中(非 python 文件是常见的问题来源) 这些文件的内容实际上具有指导意义,尤其是对初学者而言

缺点:

始终必须记住每次更新 ui 时重新生成 python 文件;我们都知道忘记这样一个看似毫无意义的步骤是多么容易,尤其是在编码数小时之后:我见过很多情况,人们因为无法追踪的问题而在桌子上敲打头(希望是他们两个)几个小时,在意识到他们只是忘记运行 pyuic 或没有在正确的文件上运行它之前;我自己的前额还疼;-) 文件跟踪:您必须为每个 ui 计算 两个 文件,并且您可能会在迁移/forking/etc 的过程中忘记其中一个,如果您忘记了一个 ui 文件,这可能意味着你必须从头开始完全重新创建它 n00b alert:初学者通常会认为生成的python文件是用来创建程序的,这显然是错误的;不幸的是,# WARNING! 消息不够清晰(我几乎一直在向 PyQt 开发人员请求这个问题);虽然这显然不是这种方法的实际问题,但现在它会导致这样 一些 pyuic 生成文件的内容通常是不必要的(最重要的是对象名称,仅用于特定情况),这很明显,因为它是自动生成的(“你可能需要那,安全总比后悔好”);此外,与上述问题相关,人们可能会认为 pyuic 创建的所有内容实际上都是 GUI 所需要的,从而导致不必要的代码降低其可读性

loadUi方法

优点:

它直接而直接:您在 Designer 上编辑您的 ui,然后保存它(或者,至少,您记得这样做...),当您运行您的代码时,它已经存在;没有大惊小怪,没有混乱,桌子/前额是安全的(r) 文件跟踪和部署:每个 ui 只需一个文件,您可以将所有这些 ui 文件放在一个单独的文件夹中,您无需执行任何其他操作,也不会冒险在途中忘记某些内容李> 直接访问小部件(但这也可以使用多重继承方法来实现)

缺点:

上面提到的布局问题 可能的实例属性覆盖并且没有“ui”对象“containment” 加载速度稍慢 路径和部署:加载是使用os相对路径和系统分隔符完成的,所以如果你将ui放在与加载.uipy文件不同的目录中,你将不得不考虑这一点;此外,一些包管理器用于压缩所有内容,除非正确管理路径,否则会导致访问错误

在我看来,综合考虑,loadUi 方法通常是更好的选择。它不会分散我的注意力,它允许更好的概念划分(这通常很好,并且在概念上更接近于类似于 MVC 的模式)并且我坚信它更不容易出现程序员错误,对于众多原因。

但这显然是一个选择问题。

我们还应该并且永远记住,就像我们所做的所有其他选择一样,使用 ui 文件是一个选项。 有些人完全避免使用它们(就像有些人将它们从字面上用于任何事情一样),但是,就像所有事情一样,这一切并且总是取决于上下文。

【讨论】:

非常感谢您的详细回答。我真的很感激

以上是关于使用 pyuic 与 uic.loadUi 的好处的主要内容,如果未能解决你的问题,请参考以下文章

如何在不导入自定义小部件类包的情况下使用自定义小部件和 uic.loadUi?

退出主窗口时关闭子窗口

如何将场景添加到先前定义的 QGraphicsView

PyQt 5.9 中的 OpenLayers 地理定位

pyqt UI 文件 - 设置类属性

pyuic5 向后兼容性