简体   繁体   中英

Registering an extension in Qt Designer with no associated widget plugin

TL;DR

I want to register a Qt Designer extension but don't want any widget plugin, so any of the following can solve my problem:

  • How do I create a plugin in Qt Designer that doesn't expose any widget in the widget box but that can register extensions?
  • How do I register the extension without subclassing of QDesignerCustomWidgetInterface ?

I'm working on a set of plugins for Qt Designer. These plugins expose custom widgets to the designer. All widgets (some dozens) inherit from a common class ( CCommonWidget ), such as:

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

CCommonWidget define some common properties for all widgets. I'd like to expose them to Qt Designer through extensions (for example, the QDesignerTaskMenuExtension ).

I started with a test in the CLabel plugin. Here the two relevant methods:

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

It worked flawlessly and I was about to extend the idea to the rest of the plugins. Instead of copy/pasting the code I started with a CCommonPlugin and make every one to inherit from it. In order to make it as re-usable as possible I changed the createExtension method to:

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

Here I realized that even if only on plugin ( CLabelPlugin ) was registering the extension factory, any other widget which inherits from CCommonWidget will show the menu! (It was pretty obvious once I discovered it but before I just didn't think on it).

Now it was easier since I hadn't to change all the plugins (dozens) but just to create a new one, a dummy common plugin , that registers the extension factory.

The dummy plugin I've first created:

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

But a blank widget is displayed in the widget box of Qt Designer. I don't want an empty widget, I want no widget !

Another option is not to use these kind of plugins but I'm struggling to find a way to register the extension without a QDesignerCustomWidgetInterface , but all that I can find is to get the extensions manager within QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) (using formEditor->extensionManager() ).

Quick answer

To hide the widget from the widget box just return an empty XML (this is an undocumented feature):

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

Reviewing the code of the plugins manager of Qt Designer, I found in the QDesignerPluginManagerPrivate::addCustomWidget method the following ( c is a pointer to QDesignerCustomWidgetInterface )

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

Given that, I saw that the default implementation of domXml does return a tiny XML fragment for a generic widget:

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

For completeness, as far as I have seen in the source code of the plugins manager of the Qt Designer, there is no way to load a plugin that doesn't inherits from 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();
    }
}

where

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM