【问题标题】:PySide2 equivalent of PyQt5's loadUiType() to dynamically mix in UI designsPySide2 等效于 PyQt5 的 loadUiType() 以动态混合 UI 设计
【发布时间】:2019-11-01 15:23:29
【问题描述】:

TL;DR:我想从它的 uic 模块中替换 PyQt5 的 loadUiType() 函数,该模块适用于 PySide2 和 Python 3.6+。


我想将 PyQt5 应用程序迁移到 PySide2。我使用的一个常见模式是,我在 Qt Designer 中创建用户界面设计并动态加载生成的 .ui 文件作为在 Python 代码中扩展 Qt 小部件的混合类,例如主窗口本身:

from PyQt5 import QtWidgets, uic

class Window(QtWidgets.QMainWindow, uic.loadUiType('design.ui')[0]):

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        print(self.label.text())

app = QtWidgets.QApplication([])
window = Window()
window.show()
app.exec_()

这意味着我可以放弃在命令行上将.ui 设计编译为.py Python 模块。更重要的是,混合模式让我可以在导入小部件的范围内通过self.name 访问设计中定义的所有Qt 小部件,其中name 在Qt Designer 中被如此分配。

为了提供可重现的示例,这里有一个最小的 Qt 设计文件,与上述 Python 代码一起使用,其中引用为 design.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
  <class>MainWindow</class>
  <widget class="QMainWindow" name="MainWindow">
    <widget class="QWidget" name="centralwidget">
      <widget class="QLabel" name="label">
        <property name="text">
          <string>Hi, Qt.</string>
        </property>
      </widget>
    </widget>
  </widget>
</ui>

我想完成同样的任务,但使用 PySide2 并尽可能减少代码更改。问题是,PySide2 没有提供与 PyQt5 的 uic.loadUiType() 功能等效的功能,重要的是,returns the design's form class 用作混入。

有一个相关的问题,"PyQt5 to PySide2, loading UI-Files in different classes",但它的前提是加载的对象可以从 separate 类中使用,这不是我关心的问题本身。另外,(目前)唯一的答案不是我正在寻找的解决方案。其他问题及其答案(12)确定设计文件可以通过QtUiTools.QUiLoader().load('design.ui') 在 PySide2 中动态加载,但该方法返回小部件对象,而不是所需的表单类.

后一种方法在不混合导入的类的情况下,需要我为迁移更改许多代码行,因为它会导致 Python 实例变量的不同对象层次结构。在上面的示例中,self.label 必须在整个代码库中重命名为 self.ui.label

我想要的是从它的 uic 模块中替换 PyQt5 的 loadUiType(design) 函数,该模块适用于 PySide2 和 Python 3.6+,其中 design 指定到 .ui 文件的路径。

This answer,从 2013 年开始,完美地证明了这一点,但对于 PySide(基于 Qt4)和(旧版)Python 2。我如何使该代码适应在(现代)Python 上运行的 PySide2(基于 Qt5)?

【问题讨论】:

    标签: python python-3.x pyqt5 qt-designer pyside2


    【解决方案1】:

    以下是上面引用的较早答案中提出的解决方案的 Python 3.6 或更高版本和 PySide2 5.13 或更早版本(见末尾的注释)的改编:

    from PySide2 import QtWidgets
    from pyside2uic import compileUi
    from xml.etree import ElementTree
    from io import StringIO
    
    def loadUiType(design):
        """
        PySide2 equivalent of PyQt5's `uic.loadUiType()` function.
    
        Compiles the given `.ui` design file in-memory and executes the
        resulting Python code. Returns form and base class.
        """
        parsed_xml   = ElementTree.parse(design)
        widget_class = parsed_xml.find('widget').get('class')
        form_class   = parsed_xml.find('class').text
        with open(design) as input:
            output = StringIO()
            compileUi(input, output, indent=0)
            source_code = output.getvalue()
            syntax_tree = compile(source_code, filename='<string>', mode='exec')
            scope = {}
            exec(syntax_tree, scope)
            form_class = scope[f'Ui_{form_class}']
            base_class = eval(f'QtWidgets.{widget_class}')
        return (form_class, base_class)
    

    如果与主 Python 模块一起保存为 uic.py,则只需更改 import 语句即可将问题中的示例从 PyQt5 迁移到 PySide2:

    from PySide2 import QtWidgets
    import uic
    

    在 Windows 10(通过 pip install pyside2 安装)和 Manjaro Linux 18.0.4(通过 pacman-packages pyside2 @ 上使用 Python 3.7.3 和 PySide2 5.12.3 测试987654329@)。


    注意:在 5.14.0(2019 年 12 月)版本中,上述解决方案中使用的 pyside2uic 模块已从 PySide2 代码库中删除。但是,随后在 PySide2 问题跟踪器上向“bring back loadUiType”提交了请求。从版本 5.14.2.2(2020 年 5 月)开始,loadUiType 可以从 QtUiTools 模块中导入,并且可以像在 PyQt5 中一样工作。这会使问题中提出的问题过时。

    【讨论】:

    • 感谢您提供详细信息。终于找到这张纸条让我省了几个小时的痛苦。我还依靠 pyside2uic 即时编译我的 .ui。感谢上面关于删除 pyside2uic 的注释,特别是从 Pyside2==5.14.0 开始,我做了以下操作来恢复到“完全”功能的 PySide2:pip3.7 uninstall pyside2pip3.7 install pyside2==5.13.0
    【解决方案2】:

    PySide2 brought back loadUiType in May 2020。因此,如果您升级,您可以获得替代品。唯一的区别是导入:

    from PySide2.QtUiTools import loadUiType
    

    语法相同(你将使用loadUiType(&lt;file&gt;)[0]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 2020-06-26
      • 2018-08-29
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多