TL; DR
Я хочу зарегистрировать расширение 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()
).
Быстрый ответ
Чтобы скрыть виджет из поля виджета, просто верните пустой 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);
}
}
Других решений пока нет …