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++ 项目视图(例如 QListView
或 QTableView
)不同,必须在适当的时候从 QML 显式调用 setData()
方法。
【讨论】:
以上是关于QML TableView + QAbstractTableModel - 如何从 QML 编辑模型数据?的主要内容,如果未能解决你的问题,请参考以下文章
QML TableView + QAbstractTableModel - 如何从 QML 编辑模型数据?