使用.ui文件从Designer或QtCreator与QUiLoaderpyside6-uic

本页描述了如何使用 Qt Widgets Designer 为您的 Qt for Python 项目创建基于 Qt Widgets 的图形界面。 Qt Widgets Designer 是一个图形用户界面设计工具,可以作为独立的二进制文件(pyside6-designer)使用,也可以嵌入到 Qt Creator IDE 中。在 Qt Creator 中的使用描述见 Using Qt Widgets Designer

Designer and the equivalent code

设计存储在.ui文件中,这是一种基于XML的格式。它将在项目构建时通过pyside6-uic工具转换为填充小部件实例的Python或C++代码。

要在Qt Creator中创建一个新的Qt设计表单,请选择 文件/新建 文件 项目,并选择“主窗口”作为模板。将其保存为 mainwindow.ui。在centralwidget的中心添加一个QPushButton

您的文件 mainwindow.ui 应该看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>110</x>
      <y>80</y>
      <width>201</width>
      <height>81</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

现在我们准备决定如何从Python中使用UI文件

选项A:生成一个Python类

UI文件交互的标准方法是生成一个Python类。这要归功于pyside6-uic工具。要使用此工具,您需要在控制台上运行以下命令:

pyside6-uic mainwindow.ui -o ui_mainwindow.py

我们将命令的所有输出重定向到一个名为ui_mainwindow.py的文件中,该文件将直接导入:

from ui_mainwindow import Ui_MainWindow

现在要使用它,我们应该为我们的部件创建一个个性化的类来设置这个生成的设计。

为了理解这个想法,让我们看一下整个代码:

import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import QFile
from ui_mainwindow import Ui_MainWindow

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    sys.exit(app.exec())

从之前的例子中已经知道if语句中的内容,我们的新基础类只包含两行新代码,负责从UI文件加载生成的python类:

self.ui = Ui_MainWindow()
self.ui.setupUi(self)

注意

每次对UI文件进行更改后,您都必须再次运行pyside6-uic

选项 B:直接加载

要直接加载UI文件,我们需要从QtUiTools模块中获取一个类:

from PySide6.QtUiTools import QUiLoader

QUiLoader 允许我们动态加载 ui 文件 并立即使用它:

ui_file = QFile("mainwindow.ui")
ui_file.open(QFile.ReadOnly)

loader = QUiLoader()
window = loader.load(ui_file)
window.show()

这个示例的完整代码如下所示:

# File: main.py
import sys
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication
from PySide6.QtCore import QFile, QIODevice

if __name__ == "__main__":
    app = QApplication(sys.argv)

    ui_file_name = "mainwindow.ui"
    ui_file = QFile(ui_file_name)
    if not ui_file.open(QIODevice.ReadOnly):
        print(f"Cannot open {ui_file_name}: {ui_file.errorString()}")
        sys.exit(-1)
    loader = QUiLoader()
    window = loader.load(ui_file)
    ui_file.close()
    if not window:
        print(loader.errorString())
        sys.exit(-1)
    window.show()

    sys.exit(app.exec())

然后要执行它,我们只需要在命令提示符下运行以下内容:

python main.py

注意

QUiLoader 使用 connect() 调用,将函数签名作为字符串参数用于信号/槽连接。 因此,它无法处理来自用 Python 编写的自定义小部件的 Python 类型,如 strlist,因为这些类型在内部映射到不同的 C++ 类型。

Qt Widgets Designer中的自定义小部件

Qt Widgets Designer 能够使用用户提供的(自定义)部件。 它们显示在部件框中,并且可以像 Qt 的部件一样拖放到表单上(参见 使用自定义部件与 Qt Widgets Designer )。通常,这需要将部件实现为 Qt Widgets Designer 的插件,使用 C++ 编写并实现其 QDesignerCustomWidgetInterface

Qt for Python 为此提供了一个简单的接口,类似于 registerCustomWidget()

小部件需要作为一个Python模块提供,如WigglyWidget示例(文件wigglywidget.py)或任务菜单扩展示例(文件tictactoe.py)所示。

Qt Widgets Designer中注册此功能是通过提供一个名为register*.py的注册脚本并将路径类型的环境变量PYSIDE_DESIGNER_PLUGINS指向该目录来完成的。

注册脚本的代码如下所示:

# File: registerwigglywidget.py
from wigglywidget import WigglyWidget

import QtDesigner


TOOLTIP = "A cool wiggly widget (Python)"
DOM_XML = """
<ui language='c++'>
    <widget class='WigglyWidget' name='wigglyWidget'>
        <property name='geometry'>
            <rect>
                <x>0</x>
                <y>0</y>
                <width>400</width>
                <height>200</height>
            </rect>
        </property>
        <property name='text'>
            <string>Hello, world</string>
        </property>
    </widget>
</ui>
"""

QPyDesignerCustomWidgetCollection.registerCustomWidget(WigglyWidget, module="wigglywidget",
                                                       tool_tip=TOOLTIP, xml=DOM_XML)

QPyDesignerCustomWidgetCollection 提供了 QDesignerCustomWidgetCollectionInterface 的实现,将自定义小部件暴露给Qt Widgets Designer,并提供了用于注册类型或添加 QDesignerCustomWidgetInterface 实例的静态便捷函数。

函数 registerCustomWidget() 用于向Qt Widgets Designer注册一个小部件类型。在简单的情况下,它可以像QUiLoader.registerCustomWidget()这样使用。它接受自定义小部件类型和一些可选的关键字参数,这些参数传递的值对应于 QDesignerCustomWidgetInterface的getters:

当通过启动器 pyside6-designer 启动 Qt Widgets Designer 时,自定义小部件应该在小部件框中可见。

对于高级用法,也可以将类QDesignerCustomWidgetInterface的实现传递给函数,而不是类型到addCustomWidget()。这在taskmenuextension示例中显示,其中为自定义小部件注册了自定义上下文菜单。该示例是对应的C++ 任务菜单扩展示例的移植。

Qt Widgets Designer 插件故障排除

  • 必须使用启动器 pyside6-designer。独立的 Qt Widgets Designer 将无法加载插件。

  • 菜单项 帮助/关于插件 会弹出一个对话框,显示找到的插件和可能的加载错误信息。

  • 检查控制台或Windows调试视图以获取更多错误信息。

  • 由于Python输出的缓冲,错误信息可能只在Qt Widgets Designer终止后出现。

  • 在构建 Qt for Python 时,请确保设置 --standalone 选项,以便正确安装插件。