How to update values in a custom model after editing
-
I am trying to implement something similar to the example http://doc.qt.io/qt-5/qtsql-querymodel-example.html
In this example, a custom model is created based off QSqlQueryModel that makes some columns editable. After data is edited by the user the model runs a query to update the database with the new value, and then refreshes the model so that the user can see it has been updated.
What I would like to do is - Instead of running a query to update the data in a database, I would like to update the data ONLY in the model (and leave the database as is). How can I update my model within the setData function?
Here is my implementation, I would like to update column 0 with whatever data the user entered, so that is persists in the model.
bool MyModel::setData(const QModelIndex &index, const QVariant &value, int /* role */) { if (index.column() != 0) return false; bool ok = false; if (index.column() == 0) { ok = setQtyToShip(index, value.toString()); } return ok; } bool MyModel::setQtyToShip(const QModelIndex &index, const QString &value) { // TODO: Update the cell at index with the data the user entered. return true; }
-
How looks your data() function? Where does it get it's values from?
-
Yes, you must reimplement data() when you want to display your custom values.
-
Yes, you must reimplement data() when you want to display your custom values.
@Christian-Ehrlicher What should I reimplement it with?
-
Since you want to show custom data, you should remember it when set via setData() and return this value in data() for the requested cell. If you have no custom data, simply call the base class to retrieve it from the database.
-
Since you want to show custom data, you should remember it when set via setData() and return this value in data() for the requested cell. If you have no custom data, simply call the base class to retrieve it from the database.
@Christian-Ehrlicher Just to make sure I understand... What I would like to do is:
- Retrieve info from a db, and populate that into a table.
- Allow the user to edit values in a particular column.
- If a user makes changes to that column, save the change value in the model to be accessed later (not saved in the DB).
So to do this I should:
- Not actually modify the value already stored in the model.
- Create a member variable in my model, specifically to hold changed values. (Possibly a QMap<int, int> where the 1stint is the row#, and the 2nd int is my user changed value as it happens to be an int in this case)?
- In my re-implemented setData() function, I would add a value to the QMap with the row# and new value modified by the user.
- in my re-implemented data() function, I would recall a value from my member QMap (if it exists), or the data in the model if it does not.
Is that what you mean?
-
This is the way I would do it, yes.
-
This is the way I would do it, yes.
@Christian-Ehrlicher So I have added the following to my header file:
private: QMap<int, int> m_myMap;
And re-implemented the following:
bool MyModel::setData(const QModelIndex &index, const QVariant &value, int /* role */) { // Only "Qty To Ship" (column 0) is editable. if (index.column() != 0) return false; bool ok = false; if (index.column() == 0) { ok = m_myMap[index.row()] = value.toInt(); } return ok; } QVariant MyModel::data(const QModelIndex &item, int role) { if( item.column() - 1 == 0) // I'm not sure why item.column() returns 1. For now I am just subtracting 1 so that it runs the following: { QVariant v = m_myMap[item.row()]; return v; } else { return itemData(item).value(0); } }
I can see that my QMap<int, int> is storing the value from the cell for each row, and data() is returning a QVariant - but I still do not see the value shown in my table view. What am I missing from my ::data() function?
-
@Christian-Ehrlicher So I have added the following to my header file:
private: QMap<int, int> m_myMap;
And re-implemented the following:
bool MyModel::setData(const QModelIndex &index, const QVariant &value, int /* role */) { // Only "Qty To Ship" (column 0) is editable. if (index.column() != 0) return false; bool ok = false; if (index.column() == 0) { ok = m_myMap[index.row()] = value.toInt(); } return ok; } QVariant MyModel::data(const QModelIndex &item, int role) { if( item.column() - 1 == 0) // I'm not sure why item.column() returns 1. For now I am just subtracting 1 so that it runs the following: { QVariant v = m_myMap[item.row()]; return v; } else { return itemData(item).value(0); } }
I can see that my QMap<int, int> is storing the value from the cell for each row, and data() is returning a QVariant - but I still do not see the value shown in my table view. What am I missing from my ::data() function?
-
I don't understand your "problem" comment in your code. You need to sort out consistent column numbers.
QModelIndex::column()
will have the same value for the same cell in bothdata()
&setData()
, you seem to be accessing the wrong column. -
You're always setting/returning your data value in
setData()
/data()
regardless ofrole
. You cannot afford to do that. You need to examine the role and call the base implementation ofsetData()
/data()
in those cases not setting/requesting the actual data value.
I would guess one or other (or both) of the above is going to stop you seeing anything meaningful in your attached
QTableView
. -