前言
本人使用qt5.15.2,让QtTreePropertyBrowser可以识别Q_PROPERTY宏引用的自定义类型,效果如下
主要是自定义了一个可以自己选择图片的控件
自定义类注册
#ifndef PIXMAPNODE_H_
#define PIXMAPNODE_H_
#include<qmetatype.h>
struct PixmapNode
{
QString _name;
};
Q_DECLARE_METATYPE(PixmapNode)
#endif // !PIXMAPNODE_H_
在QVariant::Type枚举中自定义类通过QVariant::type返回的值全部是QVariant::UserType(1024),
自定义类的枚举值可以通过qMetaTypeId<T>()和QVariant::userType()获取,比较两个值可以判断是哪一个自定义类。
自定义PropertyManager(直接写在文件源码)
这里定义一个PixmapPropertyManager,然后复制前面内置的类,略微改一下
关于几个函数的说明:
/*只在QtVariantProperty::value中调用过,如果创建的QtVariantProperty
*不使用value函数可以不写这个
*/
value(const QtProperty*);
/*在对应的自定义工厂slotSetValue槽函数中调用,slotSetValue会与自定义窗口的信号绑定
*/
setValue(QtProperty* property, PixmapNode& val);
/*自己的setValue被调用时触发,并触发工厂类的slotPropertyChanged(会更新自定义窗口相应值)
*/
valueChanged(QtProperty* property, const PixmapNode& val);
/*QtTreePropertyBrowser相应控件显示的值
*/
valueText(const QtProperty* property);
后面几行复制就行了
//qtpropertymanager.h
class PixmapPropertyManagerPrivate;
class PixmapPropertyManager : public QtAbstractPropertyManager
{
Q_OBJECT
public:
PixmapPropertyManager(QObject* parent = 0);
~PixmapPropertyManager();
PixmapNode value(const QtProperty* property) const;
public Q_SLOTS:
void setValue(QtProperty* property, PixmapNode& val);
Q_SIGNALS:
void valueChanged(QtProperty* property, const PixmapNode& val);
protected:
QString valueText(const QtProperty* property) const;
virtual void initializeProperty(QtProperty* property)override;
virtual void uninitializeProperty(QtProperty* property)override;
private:
QScopedPointer<PixmapPropertyManagerPrivate> d_ptr;
Q_DECLARE_PRIVATE(PixmapPropertyManager)
Q_DISABLE_COPY_MOVE(PixmapPropertyManager)
};
//qtpropertymanager.cpp
class PixmapPropertyManagerPrivate
{
PixmapPropertyManager* q_ptr;
Q_DECLARE_PUBLIC(PixmapPropertyManager)
public:
struct Data
{
Data(){}
PixmapNode val;
};
typedef QMap<const QtProperty*, Data> PropertyValueMap;
QMap<const QtProperty*, Data> m_values;
};
PixmapPropertyManager::PixmapPropertyManager(QObject* parent)
: QtAbstractPropertyManager(parent), d_ptr(new PixmapPropertyManagerPrivate)
{
d_ptr->q_ptr = this;
}
PixmapPropertyManager::~PixmapPropertyManager()
{
clear();
}
PixmapNode PixmapPropertyManager::value(const QtProperty* property) const
{
return getValue<PixmapNode>(d_ptr->m_values, property);
}
QString PixmapPropertyManager::valueText(const QtProperty* property) const
{
const PixmapPropertyManagerPrivate::PropertyValueMap::const_iterator it
= d_ptr->m_values.constFind(property);
if (it == d_ptr->m_values.constEnd())
return QString();
return it.value().val._name+".png";
}
void PixmapPropertyManager::setValue(QtProperty* property, PixmapNode& val)
{
const PixmapPropertyManagerPrivate::PropertyValueMap::iterator it
= d_ptr->m_values.find(property);
if (it == d_ptr->m_values.end())
return;
PixmapPropertyManagerPrivate::Data data = it.value();
if (data.val._name == val._name)
return;
data.val._name = val._name;
it.value() = data;
emit propertyChanged(property);
emit valueChanged(property, data.val);
}
void PixmapPropertyManager::initializeProperty(QtProperty* property)
{
d_ptr->m_values[property] = PixmapPropertyManagerPrivate::Data();
}
void PixmapPropertyManager::uninitializeProperty(QtProperty* property)
{
d_ptr->m_values.remove(property);
}
自定义窗口
//xxx.h
#ifndef PIXMAPSELECTEDWIDGET_H_
#define PIXMAPSELECTEDWIDGET_H_
#include<qwidget.h>
#include<qlabel.h>
#include<qpushbutton.h>
class PixmapSelectedWidget :public QWidget
{
Q_OBJECT
public:
PixmapSelectedWidget(QWidget* parent = nullptr);
void setValue(const QString&);
public slots:
void slot_PixmapChanged();
signals:
void valueChanged(const QString&);
private:
QLabel* m_label;
QPushButton* m_button;
};
#endif // !PIXMAPSELECTEDWIDGET_H_
//xxx.cpp
#include"PixmapSelectedWidget.h"
#include<QHBoxLayout>
#include<qfiledialog.h>
PixmapSelectedWidget::PixmapSelectedWidget(QWidget* parent)
:QWidget(parent),m_label(0),m_button(0)
{
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setMargin(0);
m_label = new QLabel(".png", this);
m_button = new QPushButton("select", this);
m_button->setFixedWidth(60);
layout->addWidget(m_label);
layout->addWidget(m_button);
this->setLayout(layout);
connect(m_button,
&QPushButton::clicked,
this,
&PixmapSelectedWidget::slot_PixmapChanged);
}
void PixmapSelectedWidget::setValue(const QString&name)
{
m_label->setText(name + ".png");
}
void PixmapSelectedWidget::slot_PixmapChanged()
{
QString path = QFileDialog::getOpenFileName(
this, "selected picture",
QDir::currentPath(),
QString("Image File(*.png)"
));
if (path.isEmpty())return;
int last_splitter = path.lastIndexOf('/');
QString name = path.mid(last_splitter + 1, path.length() - last_splitter - 5);
this->setValue(name);
emit valueChanged(name);
}
一个QLabel加一个按钮的控件
自定义EditorFactory(写在文件源码)
该类的特殊设计,槽函数都写在私有类里,通过Q_PRIVATE_SLOT归为公有类
这里也是对照内置类复制,略改一下就行
//qeditorfactory.h
class PixmapEditorFactoryPrivate;
class PixmapEditorFactory :public QtAbstractEditorFactory<PixmapPropertyManager>
{
Q_OBJECT
public:
PixmapEditorFactory(QObject* parent = nullptr);
~PixmapEditorFactory();
protected:
virtual void connectPropertyManager(PixmapPropertyManager* manager)override;
virtual QWidget* createEditor(PixmapPropertyManager* manager,
QtProperty* property,
QWidget* parent)override;
virtual void disconnectPropertyManager(PixmapPropertyManager* manager)override;
private:
PixmapNode m_receiver;
QScopedPointer<PixmapEditorFactoryPrivate> d_ptr;
Q_DECLARE_PRIVATE(PixmapEditorFactory)
Q_DISABLE_COPY_MOVE(PixmapEditorFactory)
Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty* property,
const PixmapNode& value))
Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QString& value))
Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject*))
};
//qeditorfactory.cpp
#include"../PixmapSelectedWidget.h"
class PixmapEditorFactoryPrivate :public EditorFactoryPrivate<PixmapSelectedWidget>
{
PixmapEditorFactory* q_ptr;
Q_DECLARE_PUBLIC(PixmapEditorFactory)
public:
void slotPropertyChanged(QtProperty* property, const PixmapNode& value);
void slotSetValue(const QString& value);
};
void PixmapEditorFactoryPrivate::slotPropertyChanged(QtProperty* property, const PixmapNode& value)
{
const auto it = m_createdEditors.constFind(property);
if (it == m_createdEditors.constEnd())
return;
for (PixmapSelectedWidget* editor : it.value()) {
editor->setValue(value._name);
}
}
void PixmapEditorFactoryPrivate::slotSetValue(const QString& value)
{
q_ptr->m_receiver._name = value;
QObject* object = q_ptr->sender();
const QMap<PixmapSelectedWidget*, QtProperty*>::ConstIterator ecend = m_editorToProperty.constEnd();
for (QMap<PixmapSelectedWidget*, QtProperty*>::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
if (itEditor.key() == object) {
QtProperty* property = itEditor.value();
PixmapPropertyManager* manager = q_ptr->propertyManager(property);
if (!manager)
return;
manager->setValue(property, q_ptr->m_receiver);
return;
}
}
//###############
PixmapEditorFactory::PixmapEditorFactory(QObject* parent)
: QtAbstractEditorFactory<PixmapPropertyManager>(parent), d_ptr(new PixmapEditorFactoryPrivate())
{
d_ptr->q_ptr = this;
}
PixmapEditorFactory::~PixmapEditorFactory()
{
qDeleteAll(d_ptr->m_editorToProperty.keys());
}
void PixmapEditorFactory::connectPropertyManager(PixmapPropertyManager* manager)
{
connect(manager,
SIGNAL(valueChanged(QtProperty*, PixmapNode)),
this,
SLOT(slotPropertyChanged(QtProperty*, PixmapNode)));
}
QWidget* PixmapEditorFactory::createEditor(PixmapPropertyManager* manager,
QtProperty* property, QWidget* parent)
{
PixmapSelectedWidget* editor = d_ptr->createEditor(property, parent);
editor->setValue(manager->value(property)._name);
connect(editor, SIGNAL(valueChanged(QString)),
this, SLOT(slotSetValue(QString)));
connect(editor, SIGNAL(destroyed(QObject*)),
this, SLOT(slotEditorDestroyed(QObject*)));
return editor;
}
void PixmapEditorFactory::disconnectPropertyManager(PixmapPropertyManager* manager)
{
disconnect(manager,
SIGNAL(valueChanged(QtProperty*, PixmapNode)),
this,
SLOT(slotPropertyChanged(QtProperty*, PixmapNode)));
}
载入QVariantPropertyManager
公有类中声明设置值槽函数
在qtvariantproperty.h的QtVariantPropertyManager中写如下UserDefine和DefineEnd间的内容
私有类中实现槽
在qtvariantproperty.cpp的QtVariantPropertyManagerPrivate中声明槽
实现槽(相关信号触发为源码内容)
初始化(QtVariantPropertyManager构造函数中)
QtVariantPropertyManager::setValue
载入QtVariantEditorFactory中
声明自定义工厂变量
初始化(QtVariantEditorFactory构造函数中)
QtVariantEditorFactory::connectPropertyManager
QtVariantEditorFactory::disconnectPropertyManager
类中反射声明
完成以上,便可使QtVariantPropertyManager::addProperty(metaProperty.userType(),metaProperty.name())
创建相应属性栏