为 Qt Designer 创建自定义小部件

Qt Designer 的基于插件的架构允许用户定义和第三方自定义小部件可以像标准 Qt 小部件一样进行编辑。自定义小部件的所有功能都对 Qt Designer 可用,包括小部件属性、信号和槽。由于 Qt Designer 在表单设计过程中使用真实的从小部件,因此自定义小部件的显示效果将与预览时相同。

QtDesigner 模块为您提供在 Qt Designer 中创建自定义小部件的能力。

入门指南

要将自定义小部件集成到 Qt Designer 中,您需要一个适当的小部件描述和项目文件。

提供界面描述

为告知 Qt Designer 您想要提供的控件类型,创建一个 QDesignerCustomWidgetInterface 的子类,用于描述您的小部件公开的各种属性。这些中的大多数都是由基类中的纯虚拟函数提供,因为这些信息只能由插件的作者提供。

函数返回值的描述
name()提供小部件的类的名称。
group()小部件将在 Qt Designer 的小部件盒中的组。
toolTip()简短描述,以帮助用户在 Qt Designer 中识别小部件。
whatsThis()针对 Qt Designer 用户的小部件的更详细描述。
includeFile()必须在使用此小部件的应用程序中包含的标题文件。此信息存储在 UI 文件中,将由 uic 使用以在为包含自定义小部件的表单生成的代码中创建适当的 `#include` 语句。
icon()Qt Designer 的小部件框中表示小部件的图标。
isContainer()如果小部件将用于包含子小部件,则为 true;否则为 false。
createWidget()一个指向创建带有提供的父对象的自定义小部件实例 QWidget 指针。

注意:createWidget() 是一个工厂函数,仅负责创建小部件。直到 load() 返回之前,自定义小部件的属性将不可用。

domXml()描述小部件属性,例如其对象名称、大小提示和其他标准 QWidget 属性。
codeTemplate()此函数保留供 Qt Designer 将来使用。

还可以重新实现两个其他虚拟函数:

initialize()为自定义小部件设置扩展和其他功能。在此函数中应配置自定义容器扩展(参见QDesignerContainerExtension)和任务菜单扩展(参见QDesignerTaskMenuExtension)。
isInitialized()如果小部件已经被初始化,则返回 true;否则返回 false。重写通常检查是否已调用 initialize() 函数,并返回此测试的结果。

domXml() 函数注意事项

domXml() 函数返回由 Qt Designer 的部件工厂用于创建自定义小部件及其相关属性的 UI 文件片段。

从 Qt 4.4 开始,Qt Designer 的部件盒允许使用完整的 UI 文件来描述 一个 自定义小部件。可以使用 <ui> 标签来加载 UI 文件。指定 <ui> 标签允许添加包含自定义小部件额外信息的 <customwidget> 元素。如果不需要其他信息,可以使用 <widget> 标签。

如果自定义小部件没有提供合理的大小提示,则必须指定由 domXml() 函数在您的子类中返回的字符串中的默认几何形状。例如,Custom Widget Plugin 示例中提供的 AnalogClockPlugin 以以下方式定义默认小部件几何形状

    ...
R"(
    <property name="geometry">
      <rect>
        <x>0</x>
        <y>0</y>
        <width>100</width>
        <height>100</height>
      </rect>
    </property>
")
    ...

domXml() 函数的另一个特性是,如果它返回一个空字符串,小部件将不会被安装到 Qt Designer 的部件盒中。但是,它仍然可以被表单中的其他小部件使用。这个特性用于隐藏用户不应显式创建的,但由其他小部件所需要的小部件。

完整的自定义小部件规范看起来如下

<ui language="c++"> displayname="MyWidget">
    <widget class="widgets::MyWidget" name="mywidget"/>
    <customwidgets>
        <customwidget>
            <class>widgets::MyWidget</class>
            <addpagemethod>addPage</addpagemethod>
            <propertyspecifications>
                <stringpropertyspecification name="fileName" notr="true" type="singleline"/>
                <stringpropertyspecification name="text" type="richtext"/>
                <tooltip name="text">Explanatory text to be shown in Property Editor</tooltip>
            </propertyspecifications>
        </customwidget>
    </customwidgets>
</ui>

<ui> 标签的属性

属性存在注释
language可选"c++", "jambi"此属性指定自定义小部件的目标语言。它主要是为了防止 C++ 插件在 Qt Jambi 中出现。
displayname可选类名属性的值出现在部件盒中,并可以用来去除命名空间。

<addpagemethod> 标签会通知 Qt Designeruic 应使用哪个方法向容器部件添加页面。这适用于需要一个特定方法来添加子部件而不是通过父部件添加子部件的容器部件。特别是对于不是基于 Qt Designer 中提供的容器子类的容器,而是基于 当前页面 的概念的容器,这尤其相关。此外,您还需要为它们提供容器扩展。

<propertyspecifications> 元素可以包含属性元信息的列表。

可以使用标签 <tooltip> 来指定当在属性上悬停时在属性编辑器中显示的工具提示。属性名称由 name 属性提供,元素文本是工具提示。此功能是在 Qt 5.6 中添加的。

对于类型为字符串的属性,可以使用 <stringpropertyspecification> 标签。此标签具有以下属性

属性存在注释
namerequired属性的名称
typerequired参见下表属性的 type 值决定属性编辑器如何处理它们。
notr可选"true", "false"如果属性为 "true",则值不可翻译。

字符串属性的 type 属性值

类型
"richtext"富文本。
"multiline"多行纯文本。
"singleline"单行纯文本。
"stylesheet"CSS 样式表。
"objectname"对象名称(有效字符集的有限集合)。
"url"URL,文件名。

插件要求

为了使插件能够在所有平台上正确工作,您需要确保它们导出Qt Designer所需的符号。

首先,插件类必须导出,以便Qt Designer可以加载插件。使用Q_PLUGIN_METADATA() 宏来执行此操作。此外,必须使用QDESIGNER_WIDGET_EXPORT 宏来定义插件中每个自定义小部件类,以便Qt Designer可以实例化它们。

创建表现良好的小部件

某些自定义小部件具有特殊用户界面特性,这可能会使它们的行为与Qt Designer中找到的许多标准小部件不同。特别是,如果某个自定义小部件由于调用QWidget::grabKeyboard() 而获取键盘,则Qt Designer的操作会受到的影响。

为了在Qt Designer中为自定义小部件提供特殊行为,提供initialize()函数的实现,以配置针对Qt Designer特定行为的 Widget 构建过程。此函数将在第一次调用createWidget()之前被调用,并可能设置一个在Qt Designer调用插件的createWidget()函数时可以测试的内置标志。

构建和安装插件

一个简单的插件

自定义小部件插件Custom Widget Plugin演示了一个简单的Qt Designer插件。

插件的工程文件必须指定自定义小部件和插件接口的头文件和源代码。通常,此文件只需指定插件的工程将被构建为库,但带有针对Qt Designer的特定插件支持。对于CMake,这是通过以下声明完成的

find_package(Qt6 REQUIRED COMPONENTS Core Gui UiPlugin Widgets)

qt_add_plugin(customwidgetplugin)
target_sources(customwidgetplugin PRIVATE
    analogclock.cpp analogclock.h
    customwidgetplugin.cpp customwidgetplugin.h
)
target_link_libraries(customwidgetplugin PUBLIC
    Qt::Core
    Qt::Gui
    Qt::UiPlugin
    Qt::Widgets
)

链接库列表指定Qt::UiPlugin。这表示插件仅使用QDesignerCustomWidgetInterfaceQDesignerCustomWidgetCollectionInterface的抽象接口,并且没有任何链接到Qt Designer库。当访问有链接的Qt Designer的其他接口时,应使用Designer,这确保插件动态链接到Qt Designer库,并且有对这些库的运行时依赖。

还需要确保插件与其他Qt Designer小部件插件一起安装

   set(INSTALL_EXAMPLEDIR "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_PLUGINS}/designer")
install(TARGETS customwidgetplugin
    RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
    BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
    LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

对于qmake

CONFIG      += plugin
TEMPLATE    = lib
HEADERS     = analogclock.h \
              customwidgetplugin.h
SOURCES     = analogclock.cpp \
              customwidgetplugin.cpp
OTHER_FILES += analogclock.json

QT变量包含关键字uiplugin,这是Qt::UiPlugin库的等效项。

还需要确保插件与其他Qt Designer小部件插件一起安装

target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target

$[QT_INSTALL_PLUGINS]变量是安装的Qt插件的占位符。您可以在运行应用程序之前设置QT_PLUGIN_PATH环境变量来配置Qt Designer在其他位置查找插件。

注意:Qt Designer将在每个提供的路径中查找一个designer子目录。

有关使用Qt应用程序自定义库和插件路径的更多信息,请参阅QCoreApplication::libraryPaths()。

如果插件在与其不兼容的模式下构建,则将不会加载和安装它们。有关插件的其他信息,请参阅Plugins HOWTO文档。

插件拆分

上述简单方法的介绍引入了一个问题,尤其是当使用有链接的Qt Designer的其他界面时:使用自定义小部件的应用程序将依赖于Qt Designer的头文件和库。在现实世界场景中,这并不是所期望的。

以下部分将描述如何解决此问题。

将小部件链接到应用程序

当使用qmake时,可以通过创建一个包含的.pri文件,在应用程序和Qt Designer之间共享自定义小部件的源文件和头文件

INCLUDEPATH += $$PWD
HEADERS += $$PWD/analogclock.h
SOURCES += $$PWD/analogclock.cpp

然后,该文件将通过插件和应用的.pro文件被包含

include(customwidget.pri)

当使用CMake时,可以将小部件的源文件类似于添加到应用程序项目中。

通过库共享小部件

另一种方法是,将小部件放入一个库中,这个库连接到Qt Designer插件,也连接到应用程序。建议使用静态库以避免运行时定位库的问题。

有关共享库的信息,请参阅创建共享库

使用QUiLoader插件

将自定义小部件添加到QUiLoader的首选方法是通过子类化并重新实现QUiLoader::createWidget()。

然而,也可以使用Qt Designer自定义小部件插件(请参阅QUiLoader::pluginPaths()和相关函数)。为了避免需要在目标设备上部署Qt Designer库,这些插件应不与Qt Designer库有链接(QT = uiplugin,请参阅为Qt Designer创建自定义小部件#BuildingandInstallingthePlugin)。

有关在Qt Designer中使用自定义小部件的更多信息,请参阅自定义小部件插件作业菜单扩展示例,以获取有关在Qt Designer中使用自定义小部件的更多信息。您还可以使用QDesignerCustomWidgetCollectionInterface类将几个自定义小部件组合成一个库。

© 2024 The Qt Company Ltd. 本文档的贡献包括各自的版权拥有者的版权。本提供的文档受GNU自由文档许可证第1.3版的条款,由自由软件基金会发布。Qt和相应的标志是芬兰及/或其他国家的The Qt Company Ltd.的商标。所有其他商标均为其各自所有者的财产。