自定义小部件插件

Qt 设计师 创建自定义小部件插件。

在此示例中,使用的小部件基于 模拟时钟示例,并且不提供任何自定义信号或槽。

准备

要提供一个可用于 Qt 设计师 的自定义小部件,我们需要提供自包含的实现并提供插件接口。在此示例中,为了方便,我们重用了 模拟时钟示例

项目文件

CMake

项目文件需要声明要构建一个链接到 Qt 设计师 库的插件

find_package(Qt6 REQUIRED COMPONENTS Core Gui UiPlugin Widgets)

qt_add_plugin(customwidgetplugin)

target_link_libraries(customwidgetplugin PUBLIC
    Qt::Core
    Qt::Gui
    Qt::UiPlugin
    Qt::Widgets
)

链接库列表指定了 Qt::UiPlugin。这表示插件仅使用抽象接口 QDesignerCustomWidgetInterfaceQDesignerCustomWidgetCollectionInterface,并且没有链接到 Qt Designer 库。当访问具有链接的 Qt 设计师 的其他接口时,应使用 Designer;这确保了插件动态链接到 Qt 设计师 库,并且在运行时依赖于它们。

以下示例显示了如何添加小部件的标题和源文件

target_sources(customwidgetplugin PRIVATE
    analogclock.cpp analogclock.h
    customwidgetplugin.cpp customwidgetplugin.h
)

我们提供了插件接口的实现,以便 Qt 设计师 可以使用自定义小部件。

同样重要的是要确保插件安装的位置是 Qt 设计师 所搜索的位置。我们通过指定项目目标路径并将其添加到要安装的项目项目列表来实现这一点

   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}"
)

自定义小部件被创建为库。当项目安装时(使用 ninja install 或等效的安装程序),它将与其他 Qt 设计师 插件一起安装。

有关插件的更多信息,请参阅 如何创建 Qt 插件 文档。

qmake

以下示例显示了如何将插件链接到 Qt 设计师

CONFIG      += plugin
TEMPLATE    = lib

QT          += widgets uiplugin

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

以下示例显示了如何添加小部件的标题和源文件

HEADERS     = analogclock.h \
              customwidgetplugin.h
SOURCES     = analogclock.cpp \
              customwidgetplugin.cpp
OTHER_FILES += analogclock.json

以下示例显示了如何将插件安装到 Qt 设计师 的插件路径

TARGET = $$qtLibraryTarget($$TARGET)

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

模拟时钟类的定义和实现

AnalogClock 类的定义和实现方式与 模拟时钟示例 中描述的完全相同。由于该类是自包含的,并且不需要任何外部配置,因此可以不进行修改,作为 Qt 设计师 中的自定义小部件使用。

模拟时钟插件类的定义

AnalogClock 类通过 AnalogClockPlugin 类暴露给 Qt Designer。这个类从 QObjectQDesignerCustomWidgetInterface 类继承,并实现了由 QDesignerCustomWidgetInterface 定义的接口。

为了确保 Qt 将该小部件识别为插件,通过添加 Q_PLUGIN_METADATA() 宏来导出有关小部件的相关信息。

class AnalogClockPlugin : public QObject, public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
    Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
    explicit AnalogClockPlugin(QObject *parent = nullptr);

    bool isContainer() const override;
    bool isInitialized() const override;
    QIcon icon() const override;
    QString domXml() const override;
    QString group() const override;
    QString includeFile() const override;
    QString name() const override;
    QString toolTip() const override;
    QString whatsThis() const override;
    QWidget *createWidget(QWidget *parent) override;
    void initialize(QDesignerFormEditorInterface *core) override;

private:
    bool initialized = false;
};

这些函数提供有关小部件的信息,供 Qt Designer小部件框 中使用。私有成员变量 initialized 被用来记录小部件是否已经被 Qt Designer 初始化。

请注意,特定于这个特定自定义小部件的类定义的一部分只有类名。

AnalogueClockPlugin 实现

类构造函数简单地调用了 QObject 基类构造函数,并将 initialized 变量设置为 false

AnalogClockPlugin::AnalogClockPlugin(QObject *parent)
    : QObject(parent)
{
}

Qt Designer 会在需要时调用 initialize() 函数初始化插件

void AnalogClockPlugin::initialize(QDesignerFormEditorInterface * /* core */)
{
    if (initialized)
        return;

    initialized = true;
}

在这个例子中,我们测试了 initialized 私有变量,只有当插件未被初始化时才将其设置为 true。尽管这个插件在初始化时不需要执行任何特殊的代码,但我们可以在初始化检查之后包括这样的代码。

isInitialized() 函数会让 Qt Designer 知道该插件是否准备好使用

bool AnalogClockPlugin::isInitialized() const
{
    return initialized;
}

通过 createWidget() 函数提供自定义小部件的实例。模拟时钟的实现非常直接

QWidget *AnalogClockPlugin::createWidget(QWidget *parent)
{
    return new AnalogClock(parent);
}

在这种情况下,自定义小部件只要求指定一个 parent。如果需要向小部件提供其他参数,它们可以在这里引入。

以下函数提供信息,供 Qt Designer 使用,以便在工具箱中表示小部件。函数 name() 返回提供自定义小部件的类的名称

QString AnalogClockPlugin::name() const
{
    return u"AnalogClock"_s;
}

函数 group() 用于描述自定义小部件所属的类别

QString AnalogClockPlugin::group() const
{
    return u"Display Widgets [Examples]"_s;
}

小部件插件将在 Qt Designer 工具箱中具有其组名字段的区域。通过函数 icon() 返回用于在工具箱中表示小部件的图标

QIcon AnalogClockPlugin::icon() const
{
    return {};
}

在这种情况下,我们返回一个空图标,表示我们没有可以使用的小部件图标。

为自定义小部件工具箱条目提供工具提示和"这是什么"帮助。函数 toolTip() 应返回一个描述小部件的简短信息

QString AnalogClockPlugin::toolTip() const
{
    return {};
}

函数 whatsThis() 可以返回一个较长的描述

QString AnalogClockPlugin::whatsThis() const
{
    return {};
}

函数 isContainer() 告诉 Qt Designer 小部件是否应该用作其他小部件的容器。如果不是,Qt Designer 不会允许用户在其内部放置小部件。

bool AnalogClockPlugin::isContainer() const
{
    return false;
}

Qt 中的大多数小部件都可以包含子小部件,但在 Qt Designer 中,只使用专用的容器小部件才合理。通过返回 false,我们表明自定义小部件不能包含其他小部件;如果我们返回 true,Qt Designer 允许在其他小部件内部放置模拟时钟以及定义布局。

函数 domXml() 提供了一种方法,可以在由 Qt Designer 使用标准的 XML 格式中包含小部件的默认设置。在这种情况下,我们只指定了小部件的几何形状

QString AnalogClockPlugin::domXml() const
{
    return uR"(
<ui language="c++">
  <widget class="AnalogClock" name="analogClock">
)"
R"(
    <property name="geometry">
      <rect>
        <x>0</x>
        <y>0</y>
        <width>100</width>
        <height>100</height>
      </rect>
    </property>
")
R"(
    <property name="toolTip">
      <string>The current time</string>
    </property>
    <property name="whatsThis">
      <string>The analog clock widget displays the current time.</string>
    </property>
  </widget>
</ui>
)"_s;
}

如果小部件提供了一个合理的大小提示,则在这里定义它不是必须的。另外,返回一个空白字符串而不是 <widget> 元素,将告诉 Qt Designer 不在小部件工具箱中安装小部件。

为了让模拟时钟小部件可用,我们实现了includeFile()函数以返回包含自定义小部件定义的头文件名

QString AnalogClockPlugin::includeFile() const
{
    return u"analogclock.h"_s;
}

示例项目 @ code.qt.io

© 2024 Qt公司有限公司。本文件中包含的文档贡献为各自所有者的版权。本提供的文档根据自由软件基金会发布的GNU Free Documentation License版本1.3的条件许可。Qt及相应商标为Qt公司有限公司在芬兰及其他国家/地区注册的商标。所有其他商标均为各自所有者的财产。