【问题标题】:QML TableView + QAbstractTableModel - how edit model data from QML?QML TableView + QAbstractTableModel - 如何从 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++ 模型实现表的正确方法?

【问题讨论】:

    标签: c++ qt qml qt5 qtquick2


    【解决方案1】:

    我找到了一种解决方案:

    1. 为委托添加属性:

    property var cppModel
    

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

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

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

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

    调用默认的setData方法

    1. 并从委托中的 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() 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多