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

时间:2014-12-06 13:40:39

标签: c++ qt qml qt5 qtquick2

我有从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;

模型有3列,第一列是readonly,last是可编辑的,所以这是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 ++模型实现表的正确方法?

2 个答案:

答案 0 :(得分:2)

我找到了一个解决方案:

  1. 向委托添加属性:

  2. property var cppModel
    

    1. 在列定义中设置此属性:

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

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

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

        调用默认的setData方法

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

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

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

答案 1 :(得分:1)

除了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()方法。