在没有关联的小部件插件的情况下在 Qt Designer 中注册扩展
Registering an extension in Qt Designer with no associated widget plugin
TL;DR
我想注册一个 Qt Designer 扩展,但不想要任何 widget 插件,所以以下任何一个都可以解决我的问题:
- 如何在 Qt Designer 中创建一个不在小部件框中公开任何小部件但可以注册扩展的插件?
- 如何在不使用
QDesignerCustomWidgetInterface
的子class 的情况下注册扩展?
我正在为 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);
}
}
TL;DR
我想注册一个 Qt Designer 扩展,但不想要任何 widget 插件,所以以下任何一个都可以解决我的问题:
- 如何在 Qt Designer 中创建一个不在小部件框中公开任何小部件但可以注册扩展的插件?
- 如何在不使用
QDesignerCustomWidgetInterface
的子class 的情况下注册扩展?
我正在为 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);
}
}