簡體   English   中英

如何使用基於字段值選擇的異構委托制作 QtQuick TableView / TreeView

[英]how to make QtQuick TableView / TreeView with heterogeneous delegate chosen based on field value

如何使用根據另一個單元格的值選擇的單元格委托制作 TableView 或 TreeView?

我們的想法是制作一個類似於此的屬性編輯器:

截屏

我嘗試了此處列出的各種方法: https://doc.qt.io/qt-5/qml-qt-labs-qmlmodels-tablemodel.ZFC35FDC70D5FC69A73E7DB1063A822C

但是DelegateChooser只能選擇基於列或基於角色值。 這些都不適用於上述用例。

model 可能是這樣的:

model: TableModel {
    TableModelColumn { display: "name" }
    TableModelColumn { display: "value" }
    rows: [
        {
            name: "Name",
            type: "string",
            value: "Alfred"
        },
        {
            name: "Amount",
            type: "float",
            value: 3.75
        },
        {
            name: "Enabled",
            type: "bool",
            value: true
        },
        {
            name: "Count",
            type: "int",
            value: 2
        },
        {
            name: "Color",
            type: "color",
            value: "#3300ff"
        }
    ]
}

顯示一個 2 列表視圖,其中第二列中的委托是根據type的值選擇的。

即使選擇名稱角色(這是一個次優的解決方案,因為每種類型會有很多屬性,並且每個DelegateChoice應該匹配多個名稱)也不起作用:

delegate: DelegateChooser {
    role: "name"
    DelegateChoice {
        roleValue: "Enabled"
        delegate: CheckBox {
            checked: model.display
            onToggled: model.display = checked
        }
    }
    DelegateChoice {
        roleValue: "Count"
        delegate: SpinBox {
            value: model.display
            onValueModified: model.display = value
        }
    }
    DelegateChoice {
        delegate: TextField {
            text: model.display
            selectByMouse: true
            implicitWidth: 140
            onAccepted: model.display = text
        }
    }
}

正如 TableModel 文檔中所說:

由於 Qt 中的 model 操作是通過行和列索引完成的,並且由於 object 鍵是無序的,因此必須通過 TableModelColumn 指定每一列。 這允許將 Qt 的內置角色映射到每一行 object 中的任何屬性...

所以,我有使用內置角色的工作解決方案:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import Qt.labs.qmlmodels 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Properties table")

    TableView {
        anchors.fill: parent

        model: TableModel {
            TableModelColumn {
                display: "name"
                decoration: function() { return "";}
            }
            TableModelColumn {
                display: "value"
                decoration: "type"
            }
            rows: [
                {
                    name: "Name",
                    type: "string",
                    value: "Alfred"
                },
                {
                    name: "Enabled",
                    type: "bool",
                    value: true
                },
                {
                    name: "Count",
                    type: "int",
                    value: 2
                }
            ]
        }

        delegate: DelegateChooser {
            role: "decoration"
            DelegateChoice {
                roleValue: "string"
                delegate: TextField {
                    text: model.display
                    selectByMouse: true
                }
            }
            DelegateChoice {
                roleValue: "int"
                delegate: SpinBox {
                    value: model.display
                }
            }
            DelegateChoice {
                roleValue: "bool"
                delegate: CheckBox {
                    checked: model.display
                }
            }
            DelegateChoice {
                delegate: Rectangle {
                    color: "beige"
                    implicitWidth: textLabel.width + 10
                    implicitHeight: textLabel.height
                    Text {
                        id: textLabel
                        anchors.centerIn: parent
                        text: model.display
                    }
                }
            }
        }
    }
}

但是,我認為更好的解決方案是定義從 QAbstractTableModel 繼承的自定義 PropertiesTableModel:

properties_table_model.hpp:

#pragma once

#include <QAbstractTableModel>

class PropertiesTableModel : public QAbstractTableModel
{    
    Q_OBJECT

public:
    enum PropertyType {
        String,
        Integer,
        Boolean
    };
    Q_ENUM(PropertyType)

    struct Property {
        QString name;
        QVariant value;
        PropertyType type;
    };

    enum CustomRoles {
        NameRole = Qt::UserRole + 1,
        ValueRole,
        TypeRole
    };

    PropertiesTableModel(QObject *parent = nullptr) {
        m_properties.append({"String prop", "StringProperty", PropertyType::String});
        m_properties.append({"Int prop", 55, PropertyType::Integer});
        m_properties.append({"Bool prop", true, PropertyType::Boolean});
    }

    int rowCount(const QModelIndex & = QModelIndex()) const override
    {
        return m_properties.size();
    }

    int columnCount(const QModelIndex & = QModelIndex()) const override
    {
        return 2;
    }

    QVariant data(const QModelIndex &index, int role) const override
    {
        auto& property = m_properties.at(index.row());
        switch (role) {
            case CustomRoles::NameRole:
                return property.name;
            case CustomRoles::TypeRole:
                if (index.column() > 0)
                    return property.type;
                else
                    return -1;
            case CustomRoles::ValueRole:
                return property.value;
            default:
                break;
        }

        return QVariant();
    }

    QHash<int, QByteArray> roleNames() const override
    {
        QHash<int, QByteArray> roles;
        roles[NameRole] = "name";
        roles[ValueRole] = "value";
        roles[TypeRole] = "type";
        return roles;
    }
private:
    QVector<Property> m_properties;
};

,並像這樣使用它:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.14
import Qt.labs.qmlmodels 1.0

import MyLib 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Properties table")

    TableView {
        anchors.fill: parent

        model: PropertiesModel {}

        delegate: DelegateChooser {
            role: "type"
            DelegateChoice {
                roleValue: PropertiesModel.String
                delegate: TextField {
                    text: model.value
                    selectByMouse: true
                }
            }
            DelegateChoice {
                roleValue: PropertiesModel.Integer
                delegate: SpinBox {
                    value: model.value
                }
            }
            DelegateChoice {
                roleValue: PropertiesModel.Boolean
                delegate: CheckBox {
                    checked: model.value
                }
            }
            DelegateChoice {
                delegate: Rectangle {
                    color: "beige"
                    implicitWidth: textLabel.width + 10
                    implicitHeight: textLabel.height
                    Text {
                        id: textLabel
                        anchors.centerIn: parent
                        text: model.name
                    }
                }
            }
        }
    }
}

PS。 記得注冊:

qmlRegisterType<PropertiesTableModel>("MyLib", 1, 0, "PropertiesModel");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM