DiagramDesigner/PropertyEditor/README_zh.md

4.6 KiB
Raw Blame History

QDetailsView

QDetailsView 受虚幻引擎的属性面板所启发借助Qt的反射系统可以轻易地搭建对象的属性编辑器。

其核心在于:

  • 编写基于类型的控件编辑器,自动根据对象的反射结构来组织编辑器布局。
  • 使用QML GPU渲染基于预览视图的控件管理。

使用

它的使用非常简单,只需要使用 **Q_PROPERTY(...) ** 声明 QObject 的元属性:

class QCustomObject :public QObject {
	Q_OBJECT
    Q_PROPERTY(int Int READ getInt WRITE setInt)
    Q_PROPERTY(float Float READ getFloat WRITE setFloat)   
    ...
};

然后创建 QDetailsView并指定Object

QCustomObject obj;
QDetailsView view;
view.setObject(&obj);
view.show();

你就能得到:

image-20250826114654194

定制化

关于 QPropertyHandle

QPropertyHandle 是QDetailsView操作属性的统一入口它通常通过如下接口构建

static QPropertyHandle* QPropertyHandle::FindOrCreate(
    QObject* inParent,  	// 父对象它会持有PropertyHandle周期
    QMetaType inType, 		// 该属性的元类型
    QString inPropertyPath, // 该属性的路径字段
    Getter inGetter, 		// 该属性的获取器
    Setter inSetter			// 该属性的设置器
); 		

为了保证属性值的变动可以被DetailsView响应所有对值的修改请统一使用PropertyHandle的接口

QPropertyHandle* handle = QPropertyHandle::Find(object, "propertyName");
if(handle){
    handle->setVar(QVariant::fromValue(newValue));
}

QPropertyHandle创建时要求指定parent,它将会作为子对象挂载上去,因此它的生命周期将跟随父对象,如果要清理,请调用:

static void QPropertyHandle::Cleanup(QObject* inParent);

自定义枚举

对于枚举类型,需要使用类内定义的方式,并通过**Q_ENUM(...)**声明:

class QCustomObject: public QObject {
	Q_OBJECT
public:
	enum QCustomEnum {
		One,
		Two,
		Three
	};
	Q_ENUM(QCustomEnum);
};

自定义类型编辑器

QObject的自定义类型,首先需要在定义类型时使用宏**Q_DECLARE_METATYPE(...)**进行声明。

对于只有单个编辑器控件的特定类型,可以使用如下接口直接注册类型编辑器:

QQuickDetailsViewManager::Get()->registerTypeEditor(
	metaType,
	[](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {

	}
)

在源代码的QQuickDetailsViewBasicTypeEditor.cpp目录下有许多参考示例比如QDir

registerTypeEditor(
    QMetaType::fromType<QDir>(), 
    [](QPropertyHandle* handle, QQuickItem* parent)->QQuickItem* {
        QQmlEngine* engine = qmlEngine(parent);
        QQmlContext* context = qmlContext(parent);
        QQmlComponent comp(engine);
        comp.setData(R"(
                    import QtQuick;
                    import QtQuick.Controls;
                    import "qrc:/resources/Qml/ValueEditor"
                    DirectorySelector{
                         anchors.verticalCenter: parent.verticalCenter
                         width: parent.width
                    }
                )", QUrl());
        QVariantMap initialProperties;
        initialProperties["parent"] = QVariant::fromValue(parent);
        auto valueEditor = qobject_cast<QQuickItem*>(comp.createWithInitialProperties(initialProperties, context));
        if (!comp.errors().isEmpty()) {
            qDebug() << comp.errorString();
        }
        valueEditor->setParentItem(parent);
        valueEditor->setProperty("value", handle->getVar());
        connect(valueEditor, SIGNAL(asValueChanged(QVariant)), handle, SLOT(setVar(QVariant)));		
        connect(handle, SIGNAL(asRequestRollback(QVariant)), valueEditor, SLOT(setValue(QVariant)));
        return valueEditor;
	}
);

对于具有多行或者行为较为复杂的编辑器控件,可以通过派生IPropertyTypeCustomization来扩展属性编辑器,它提供两个虚函数:

class IPropertyTypeCustomization :public  QEnableSharedFromThis<IPropertyTypeCustomization>
{
public:
    // 用于装配当前属性行的编辑器
	virtual void customizeHeaderRow(QPropertyHandle* inPropertyHandle, QQuickDetailsViewRowBuilder* inBuilder);
    
    // 用于扩展当前属性行的子项
	virtual void customizeChildren(QPropertyHandle* inPropertyHandle, QQuickDetailsViewLayoutBuilder* inBuilder);
};

之后使用如下接口进行注册:

QQuickDetailsViewManager::Get()->registerPropertyTypeCustomization<QCustomType, PropertyTypeCustomization_CustomType>();

TODO

  • 撤销重做
  • 容器操作
  • 扩展元信息