在没有关联的小部件插件的情况下在 Qt Designer 中注册扩展

Registering an extension in Qt Designer with no associated widget plugin

TL;DR

我想注册一个 Qt Designer 扩展,但不想要任何 widget 插件,所以以下任何一个都可以解决我的问题:


我正在为 Qt Designer 开发一组插件。这些插件向设计人员公开自定义小部件。所有小部件(几十个)都继承自一个共同的 class (CCommonWidget),例如:

CCommonWidget
|-> CLabel
|-> CPushButton
...

CCommonWidget 为所有小部件定义一些通用属性。我想通过扩展(例如 QDesignerTaskMenuExtension)将它们暴露给 Qt Designer。

我开始在 CLabel 插件中进行测试。这里有两个相关的方法:

// Register the extensions in Qt Designer
void CLabelPlugin::initialize(QDesignerFormEditorInterface *formEditor)
{
    if (m_initialized) return;

    auto extensionManager = formEditor->extensionManager();
    Q_ASSERT(extensionManager);

    extensionManager->registerExtensions(new CLabelPluginFactory(extensionManager), Q_TYPEID(QDesignerTaskMenuExtension));

    m_initialized = true;
}

// The factory creates the menu extension if the widget is a CLabel
QObject* CLabelPluginFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const
{
    if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) return nullptr;

    if (auto label = dynamic_cast<CLabel*>(object))
        return new CLabelPluginMenu(label, parent);

    return nullptr;
}

它完美地工作,我正准备将这个想法扩展到其他插件。我用 CCommonPlugin 开始的代码代替 copy/pasting 代码,并让每个人都继承它。为了使其尽可能可重用,我将 createExtension 方法更改为:

QObject* CCommonPluginFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const
{
    if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) return nullptr;

    if (auto label = dynamic_cast<CCommonWidget*>(object))
        return new CCommnPluginMenu(label, parent);

    return nullptr;
}

在这里我意识到,即使只有在插件(CLabelPlugin)上注册了扩展工厂,任何其他继承自CCommonWidget的小部件都会显示菜单! (一旦我发现它就很明显了,但之前我只是没有想到它)。

现在更容易了,因为我不必更改所有插件(几十个),只需创建一个新插件,一个 虚拟通用插件,它注册了扩展工厂.

我第一次创建的虚拟插件:

class CPluginCommon : public QObject, public QDesignerCustomWidgetInterface {
    Q_OBJECT
    Q_INTERFACES( QDesignerCustomWidgetInterface )

public:
    explicit CPluginCommon( QObject* parent=0 );

public: // QDesignerCustomWidgetInterface
    QWidget* createWidget( QWidget* parent ) { return nullptr; }
    QString group() const { return QString(); }
    QIcon icon() const { return QIcon(); }
    QString includeFile() const { return QString(); }
    bool isContainer() const { return false; }
    QString name() const { return QString(); }
    QString toolTip() const { return QString(); }
    QString whatsThis() const { return QString(); }

    virtual bool isInitialized() const override {
        return m_initialized;
    }
    virtual void initialize(QDesignerFormEditorInterface *formEditor) override;

private:
    bool m_initialized;
};

但是在Qt Designer 的widget 框中显示了一个空白的widget。我不想要一个空的小部件,我想要没有小部件

另一种选择是不使用这些类型的插件,但我正在努力寻找一种方法来注册扩展 而无需 a QDesignerCustomWidgetInterface,但我所做的一切可以找到的是在 QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) 内获取扩展管理器(使用 formEditor->extensionManager())。

快答

要从小部件框中隐藏小部件,只需 return 一个空的 XML(这是一个未记录的功能):

class CPluginCommon : public QObject, public QDesignerCustomWidgetInterface {
// ...
public:
    QString domXml() const { return QString(); }
};

查看Qt Designer插件管理器的代码,在QDesignerPluginManagerPrivate::addCustomWidget方法中发现如下(c是指向QDesignerCustomWidgetInterface的指针)

const QString domXml = c->domXml();
if (!domXml.isEmpty()) { // Legacy: Empty XML means: Do not show up in widget box.

鉴于此,我看到 domXml 的默认实现 return 一个通用小部件的微小 XML 片段:

virtual QString domXml() const
{
    return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
        .arg(name()).arg(name().toLower());
}

为了完整起见,据我在 Qt Designer 的插件管理器的源代码中看到的,没有办法加载不继承自 QDesignerCustomWidgetInterface:[=20 的插件=]

// Load plugins into widget database and factory.
void QDesignerIntegration::initializePlugins(QDesignerFormEditorInterface *formEditor)
{
    // load the plugins
    WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(formEditor->widgetDataBase());
    if (widgetDataBase) {
        widgetDataBase->loadPlugins();
    }

    if (WidgetFactory *widgetFactory = qobject_cast<WidgetFactory*>(formEditor->widgetFactory())) {
        widgetFactory->loadPlugins();
    }

    if (widgetDataBase) {
        widgetDataBase->grabDefaultPropertyValues();
    }
}

哪里

void WidgetDataBase::loadPlugins()
{
    // ...

    // 2) create a list plugins
    ItemList pluginList;
    const QDesignerPluginManager *pm = m_core->pluginManager();
    foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
        pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));

    // ...
}

void WidgetFactory::loadPlugins()
{
    m_customFactory.clear();

    QDesignerPluginManager *pluginManager = m_core->pluginManager();

    QList<QDesignerCustomWidgetInterface*> lst = pluginManager->registeredCustomWidgets();
    foreach (QDesignerCustomWidgetInterface *c, lst) {
        m_customFactory.insert(c->name(), c);
    }
}