Skip to content

Italink/QDetailsView

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QDetailsView

中文用户?点我查看中文介绍

Inspired by the details view of Unreal Engine, QDetailsView leverages Qt's reflection system to easily build property editors for qobject.

Its core features are:

  • Create type-based control editors that automatically organize the editor layout according to the reflection structure of the object.
  • Utilize QML GPU rendering and control management based on the preview view.

Usage

It is extremely easy to use—simply declare the meta-properties of a QObject using Q_PROPERTY(...):

class QCustomObject : public QObject {
    Q_OBJECT
    Q_PROPERTY(int Int READ getInt WRITE setInt)
    Q_PROPERTY(float Float READ getFloat WRITE setFloat)   
    ...
};
QCustomObject obj;
QDetailsView view;
view.setObject(&obj);
view.show();

You will get the following result:

image-20250826114654194

Customization

About QPropertyHandle

QPropertyHandle serves as the unified entry point for QDetailsView to manipulate properties. It is typically constructed via the following interface:

static QPropertyHandle* QPropertyHandle::FindOrCreate(
    QObject* inParent,      // Parent object that manages the lifecycle of the PropertyHandle
    QMetaType inType,       // Meta-type of the property
    QString inPropertyPath, // Path field of the property
    Getter inGetter,        // Getter function for the property
    Setter inSetter         // Setter function for the property
); 		

To ensure that changes to property values are detected by DetailsView, all value modifications must use the interface provided by PropertyHandle:

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

When creating a QPropertyHandle, you must specify a parent—the handle will be attached to the parent as a child object. Thus, its lifecycle is tied to the parent object. To clean it up, call:

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

Custom Enum

For enum types, they must be defined within a class and declared using Q_ENUM(...):

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

Custom Type Editor

For custom types that do not inherit from QObject, you first need to declare the type using the macro Q_DECLARE_METATYPE(...) during definition.

For specific types that require only a single editor control, you can directly register the type editor using the following interface:

QQuickDetailsViewManager::Get()->registerTypeEditor(
    metaType,
    [](QPropertyHandle* handle, QQuickItem* parent) -> QQuickItem* {
        // Implementation of the editor creation logic
    }
);

The source code directory QQuickDetailsViewBasicTypeEditor.cpp contains many reference examples, such as the editor for 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;
    }
);

For editor controls that span multiple rows or have complex behaviors, you can extend the property editor by deriving from IPropertyTypeCustomization. This class provides two virtual functions:

class IPropertyTypeCustomization : public QEnableSharedFromThis<IPropertyTypeCustomization>
{
public:
    // Used to assemble the editor for the current property row
    virtual void customizeHeaderRow(QPropertyHandle* inPropertyHandle, QQuickDetailsViewRowBuilder* inBuilder);
    
    // Used to extend child items for the current property row
    virtual void customizeChildren(QPropertyHandle* inPropertyHandle, QQuickDetailsViewLayoutBuilder* inBuilder);
};

After implementing the derived class, register it using the following interface:

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

TODO

  • Undo/redo
  • Container operations
  • Extended meta-data support

About

Qt Object Property Editor

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published