如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView

Posted

技术标签:

【中文标题】如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView【英文标题】:how to make QtQuick TableView / TreeView with heterogeneous delegate chosen based on field value 【发布时间】:2020-04-08 14:51:30 【问题描述】:

如何根据另一个单元格的值选择单元格委托的 TableView 或 TreeView?

这个想法是做一个类似于这样的属性编辑器:

我尝试了这里列出的各种方法:https://doc.qt.io/qt-5/qml-qt-labs-qmlmodels-tablemodel.html

但是DelegateChooser只能选择基于列或者基于roleValue。这些都不适用于上述用例。

模型可能是这样的:

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 的值选择的。

即使选择 name 角色(这是一个次优的解决方案,因为每种类型会有很多属性,并且每个 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
        
    

【问题讨论】:

你有没有在这方面取得进展?我被困在同一件事上,而且解决方法感觉非常混乱(回到旧的加载器模式)。 不行,我没有找到好的解决方案,所以我推迟了这个项目。 【参考方案1】:

正如TableModel中所说的documentation:

由于 Qt 中的模型操作是通过行和列索引完成的,并且由于对象键是无序的,因此必须通过 TableModelColumn 指定每一列。这允许将 Qt 的内置角色映射到每个行对象中的任何属性...

所以,我有使用内置角色的可行解决方案:

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");

【讨论】:

以上是关于如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView的主要内容,如果未能解决你的问题,请参考以下文章

基于Spark的异构分布式深度学习平台

一种基于结构信息检索文档的思路(html,pdf,html,xml,doc,ppt,这样的异构文档应该如何检索呢?)

一种基于结构信息检索文档的思路(html,pdf,html,xml,doc,ppt,这样的异构文档应该如何检索呢?)

基于GA遗传算法的异构网络垂直切换优化算法的matlab仿真

基于模糊神经网络的异构网络环境下垂直切换算法的matlab仿真与分析

基于随机接入代价的异构网络速率分配算法研究