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

时间:2017-10-02 11:06:03

标签: c++ qt qt-designer qtplugin

TL; DR

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

  • 如何在Qt Designer中创建一个插件,该插件不会在窗口小部件框中显示任何窗口小部件但可以注册扩展?
  • 如何在没有QDesignerCustomWidgetInterface
  • 的子类化的情况下注册扩展名

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

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

CCommonWidget定义所有小部件的一些常用属性。我想通过扩展程序将它们公开给Qt Designer(例如QDesignerTaskMenuExtension)。

我开始在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开始的代码,而是让每一个都继承它。为了使其尽可能可重用,我将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的小部件框中会显示一个空白小部件。我不想要一个空小部件,我想没有小部件

另一个选择是不使用这些插件,但我很难找到一种方法来注册扩展而不用一个QDesignerCustomWidgetInterface,但我能找到的只是在QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor)内使用formEditor->extensionManager()获取扩展程序管理器。

1 个答案:

答案 0 :(得分:2)

快速回答

要从窗口小部件框中隐藏窗口小部件,只需返回一个空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的默认实现确实为通用小部件返回了一个小的XML片段:

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

为了完整性,就我在Qt Designer的插件管理器的源代码中看到的那样,没有办法加载不从QDesignerCustomWidgetInterface继承的插件:

// 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);
    }
}