QtTreePropertyBrowser 识别自定义类型反射元属性,并显示相应控件

 前言

本人使用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,然后复制前面内置的类,略微改一下

关于几个函数的说明:

value(const QtProperty*)//只在QtVariantProperty::value中调用过,如果创建的QtVariantProperty

                                        / / 不使用value函数可以不写这个

setValue(QtProperty* property, PixmapNode& val)//在对应的自定义工厂slotSetValue槽函数中调

                                                                                //用,slotSetValue会与自定义窗口的信号绑定

valueChanged(QtProperty* property, const PixmapNode& val)//自己的setValue被调用时触发,

                                                                      //并触发工厂类的slotPropertyChanged(会更新自定义

                                                                        //窗口相应值)

valueText                //QtTreePropertyBrowser相应控件显示的值

后面几个复制粘贴就行

//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())

创建相应属性栏

  • 27
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

滑稽大帝の

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值