QML TableView + QAbstractTableModel - 如何从 QML 编辑模型数据?

Posted

技术标签:

【中文标题】QML TableView + QAbstractTableModel - 如何从 QML 编辑模型数据?【英文标题】:QML TableView + QAbstractTableModel - how edit model data from QML? 【发布时间】:2014-12-06 13:40:38 【问题描述】:

我有从 QAbstractTableModel 继承的 C++ 类,并覆盖了下一个函数:

virtual QHash<int, QByteArray> roleNames() const noexcept override;
virtual Qt::ItemFlags flags(const QModelIndex& index) const noexcept override;

virtual int rowCount(const QModelIndex& parent = QModelIndex()) const noexcept override;
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const noexcept override;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const noexcept override;

virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) noexcept override;
virtual bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) noexcept override;
virtual bool setData(const QModelIndex& index, const QVariant& data, int role = Qt::EditRole) noexcept override;

model有3列,第一个是只读的,最后一个是可编辑的,所以这是flags()方法的实现:

Qt::ItemFlags ObjectInitialStateModel::flags(const QModelIndex& index) const noexcept

    if (index.column() == 0)
    
        return Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
    
    else
    
        return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren;
    

在 QML 部分模型显示正常,但我不知道如何在 TableView 中编辑 2 和 3 列的模型数据。我试过写列委托:

Item 
    id: item
    state: "labelMode"

    Text 
        id: textLabel
        text: styleData.value
        anchors.fill: parent
        renderType: Text.NativeRendering
    

    TextField 
        id: textField
        text: styleData.value
        anchors.fill: parent

        Keys.onEnterPressed: commit()
        Keys.onReturnPressed: commit()
        Keys.onEscapePressed: rollback()

        function commit() 
            item.state = "labelMode"
        

        function rollback() 
            item.state = "labelMode"
        
    

    MouseArea 
        id: mouseArea
        anchors.fill: parent
        onDoubleClicked: item.state = "editMode"
    

    states: [
        State 
            name: "labelMode"
            PropertyChanges 
                target: textLabel
                visible: true
            
            PropertyChanges 
                target: mouseArea
                visible: true
            
            PropertyChanges 
                target: textField
                visible: false
            
        ,

        State 
            name: "editMode"
            PropertyChanges 
                target: textLabel
                visible: false
            
            PropertyChanges 
                target: mouseArea
                visible: false
            
            PropertyChanges 
                target: textField
                visible: true
                focus: true
            
        
    ]

但我不知道如何在 commit() 函数中正确地为模型设置新数据。 或者可能有另一种在 QML 中使用可编辑列和 C++ 模型实现表的正确方法?

【问题讨论】:

【参考方案1】:

我找到了一种解决方案:

    为委托添加属性:

property var cppModel

    在列定义中设置此属性:

TableViewColumn 
    role: "u"
    title: qsTr("u(t)")
    width: initialStateTableView.width / 3
    delegate: EditableDelegate 
        cppModel: DataSetService.currentDataSet ? DataSetService.currentDataSet.initialStateModel : null
    


    在 C++ 模型中实现新方法:

Q_INVOKABLE bool setData(int row, int column, const QVariant& data) noexcept;

调用默认的setData方法

    并从委托中的 commit() 函数中调用它:

function commit() 
    cppModel.setData(styleData.row, styleData.column, text)
    item.state = "labelMode"


但我认为这是丑陋的黑客,如果有人知道更优雅的解决方案,请分享...

【讨论】:

不是很漂亮,是的。如果 TableView 像 ListView 一样工作(我从未尝试过),您可以写入 styleData.value:styleData.value = text。这应该会导致在模型宽度中调用 setData() 正确的索引集。 安东:2年了。任何想法更优雅的解决方案? 在遇到 QML 问题一段时间后,我已切换到 PyQt 和经典小部件。【参考方案2】:

除了roleNames()data(),可编辑模型必须重新实现setData() 函数以保存对现有数据的更改。该方法的以下版本在执行实际更新之前检查给定模型索引是否有效并且角色是否等于Qt::EditRole。根据模型,您可以/必须还调用函数的父类版本:

bool EditableModel::setData(const QModelIndex &item, const QVariant &value, int role)
  
      if (item.isValid() && role == Qt::EditRole) 
          // update logic
          emit dataChanged(item, item);
          return true;
      
      return false;

  

需要注意的是,与 C++ 项目视图(例如 QListViewQTableView)不同,必须在适当的时候从 QML 显式调用 setData() 方法。

【讨论】:

以上是关于QML TableView + QAbstractTableModel - 如何从 QML 编辑模型数据?的主要内容,如果未能解决你的问题,请参考以下文章

QML TableView + QAbstractTableModel - 如何从 QML 编辑模型数据?

QML:如何在 TreeView 和 TableView 禁用边框?

QML TableView 模型静默失败?

QML:只有一行可见 TableView 与行和项目委托

TableView在按钮上滚动单击Qml

tableview中的QML排序非常缓慢