问题
I have C++ class inherited from QAbstractTableModel with next functions overriden:
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 has 3 columns, first is readonly, last is editable, so this is flags() method implementation:
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;
}
}
In QML part model is displayed fine, but i have no idea how i can edit model data for 2 and 3 columns in TableView. I've tried to write column delegate:
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
}
}
]
}
but i don't know how to set new data to the model in commit() function correctly. Or may be there are another right way to implement table in QML with editable columns and C++ model?
回答1:
I've found one solution:
- add property to the delegate:
property var cppModel
- set this property in column definition:
TableViewColumn {
role: "u"
title: qsTr("u(t)")
width: initialStateTableView.width / 3
delegate: EditableDelegate {
cppModel: DataSetService.currentDataSet ? DataSetService.currentDataSet.initialStateModel : null
}
}
- implement new method in C++ model:
Q_INVOKABLE bool setData(int row, int column, const QVariant& data) noexcept;
which calls default setData method
- and call it from commit() function in delegate:
function commit() {
cppModel.setData(styleData.row, styleData.column, text)
item.state = "labelMode"
}
But i think this is big ugly hack and if anybody knows more elegant solution, please share it...
回答2:
Besides the roleNames()
and data()
, the editable models must reimplement the setData()
function to save changes to existing data. The following version of the method checks if the given model index is valid and the role is equal to Qt::EditRole
, before executing the actual update. Depending on the model you can/must also call the parent class version of the function:
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;
}
It should be noted that unlike the C++ item views, such as QListView
or QTableView
, the setData()
method must be explicitly invoked from QML whenever appropriate.
来源:https://stackoverflow.com/questions/27332298/qml-tableview-qabstracttablemodel-how-edit-model-data-from-qml