Solved QAbstractTableModel and dataChanged
-
@Lachrymology
I will just say that there is a lot more code going on inQSqlQuery...
,QSqlTableModel
et al code that what you begin to show in yourQAbstractTableModel
attempt. Do whatever you like to learn, but consider using the supplied classes before too long....! -
@JonB
Jep, subclassing QSqlTableModel is easy and it works like expected. I've tried it now.Nevertheless - I don't get it .. the docs are saying the following:
"When subclassing QAbstractItemModel, at the very least you must implement index(), parent(), rowCount(), columnCount(), and data(). These functions are used in all read-only models, and form the basis of editable models."
Currently I've a read-only model. As shown above I've implemented these function, except index and parent.
But I'm not sure about:
"Models that provide interfaces to resizable data structures can provide implementations of insertRows(), removeRows(), insertColumns(),and removeColumns()."The "CAN" confuses me - do I have to or is it optional?
Furthermore I'm now working with: beginInsertRows/endInsertRows and beginInsertColumns/endInsertColumns
void SqlTableModel::setHeader( QStringList header ) { _header = header; beginInsertColumns( QModelIndex(), 0, _header.count() ); int c = 0; for( QString headStr : _header ) { qDebug() << "Inserted Column: " << insertColumn( c, QModelIndex() ); c++; } endInsertColumns(); } void SqlTableModel::setQuery( QString queryStr ) { _queryStr = queryStr; SQL::execQuery( queryStr ); QSqlQuery query = SQL::getLastQuery(); int row = 0; QSqlRecord rec = query.record(); int colCount = rec.count(); _data.clear(); beginInsertRows( QModelIndex(), 0, query.size() ); while( query.next() ) { SqlDataStruct stuc; for( int column = 0; column < colCount; column++ ) { stuc._data.insert( column, query.value( column ).toString() ); } _data.insert( row, stuc ); qDebug() << "Inserted Row: " << insertRow( row ); row++; } endInsertRows(); QModelIndex topLeft = index( 0, 0 ); QModelIndex bottomRight = index( row-1, colCount-1 ); qDebug() << topLeft.isValid(); qDebug() << bottomRight.isValid(); emit dataChanged( topLeft, bottomRight ); }
insertColumn and insertRow are both always false.
So, what I'm missing now?
layoutChanged, modelReset? -
@Lachrymology said in QAbstractTableModel and dataChanged:
So, what I'm missing now?
Why do you reimplement setQuery() at all? There is no need for it.
-
Uff ... I think it would be easier to have the SQL thingy removed first.
So okay, let us assume SQL stands here for Super Quarreler Laughter, which is a complex data structure needing a TableModel to be presented. Deal?
-
@Lachrymology said in QAbstractTableModel and dataChanged:
But I'm not sure about:
"Models that provide interfaces to resizable data structures can provide implementations of insertRows(), removeRows(), insertColumns(),and removeColumns()."
The "CAN" confuses me - do I have to or is it optional?Yes, you have to. Read e.g. https://doc.qt.io/qt-5/qabstractitemmodel.html#insertRows
Note: The base class implementation of this function does nothing and returns false.
On models that support this, inserts count rows into the model
The base does nothing but return
false
, so no insertion/deletion of rows or columns. If you have a mechanism for inserting rows into your data --- which you do --- then to make that available you must implement this, and the othervirtual
s you support.Also it concludes
If you implement your own model, you can reimplement this function if you want to support insertions. Alternatively, you can provide your own API for altering the data. In either case, you will need to call beginInsertRows() and endInsertRows() to notify other components that the model has changed.
-
@JonB
I'm confused.I have a data set/list.
Via the methods "rowCount" and "columnCount" the model provides how many rows/columns are expected.
Via "headerData" the model provides what the names of the head section are.
Via the method "data" the model is iterating over the rows and columns.
Within this it accesses the data set/list and provides it for each tupel.So far what my knowledge is, about why these are the major methods for read-only models.
If I'm using, like in the beginning, only these methods, nothing will be displayed/updated/inserted.
Ok the base of insertRow(s) returns false. In many examples this is mainly used to store external data within the internal data set/list without doing anything else than calling begin/endInsertRows. Same with insertColumn(s)
This is what I'm doing within "setQuery" and "setHeader".
If I'm looking at this example:
https://doc.qt.io/archives/4.6/itemviews-addressbook-tablemodel-cpp.htmlI don't see, what I'm missing to have my model working with the QTableView.
So again - why do I need exactly to implement such methods?
-
Found it on my own:
Within setQuery I missed calling "begin/endResetModel".
void SqlTableModel::setQuery( QString queryStr ) { _queryStr = queryStr; SQL::execQuery( queryStr ); QSqlQuery query = SQL::getLastQuery(); int row = 0; QSqlRecord rec = query.record(); int colCount = rec.count(); beginResetModel(); _data.clear(); beginInsertRows( QModelIndex(), 0, query.size() ); while( query.next() ) { SqlDataStruct stuc; for( int column = 0; column < colCount; column++ ) { stuc._data.insert( column, query.value( column ).toString() ); } _data.insert( row, stuc ); qDebug() << "Inserted Row: " << insertRow( row ); row++; } endInsertRows(); endResetModel(); QModelIndex topLeft = index( 0, 0 ); QModelIndex bottomRight = index( row-1, colCount-1 ); qDebug() << topLeft.isValid(); qDebug() << bottomRight.isValid(); emit dataChanged( topLeft, bottomRight ); }
-
I still don't understand why you implement your own setQuery() function...
/edit: and beginInsertRows()/endInsertRows() is not needed (and may kill something internally) since you already call being/endResetModel(). Cascading those calls is not supported (and not needed at all)
-
@Christian-Ehrlicher
Thanks for the hint. -
Despite the fact that this topic is rather old I wanted to clear things up for myself and maybe others as well. This is the first post that solved my problem.
The main point is that "read-only" models can still be updated by your code but they are "read-only" for the user. So there is no user interaction/manipulation of the data because the corresponding methods are not implemented in the model.
When you now update your internal data e.g. a list or a table or basically any crazy internal representation of your data, you have to notify the model that you did that which in turn notifies all interested views to update them as well.
And here is the problem in the documentation Qt 6 version of model/view concepts. It mentions "read-only" models but does not talk ab out the "beginXYZ" methods. When it does talk about those it is always in the context of insert/removeRow/Column which again is not what you need and want for "read-only" models.
What you need is the beginReset and endReset methods called from where you update your internal data. Or you have to somehow fiddle with the beginInsert.../endInsert... methods if you really want to.
So in short: When implementing models that are read-only from the user's perspective you still need to notify your model when you manipulate your internal data.
For @Lachrymology and me the following would have worked. Note that there is no need for any signals to be emitted and there is no nested rows/reset method. It simply tells the model that the data is going to be reset, then resets the data and in the end it lets the model know that the reset has finished. All signals are emitted internally and my view is updated like charme : - )
void MyReadOnlyModel::setMyInternalData(QList<int> data) { beginResetModel(); m_Data = data; endResetModel(); }
-
@JonB I've a tableview implemented with
QSqlQueryModel
, I have to override thesetData()
method, but I cannot find a way to refresh the view exceptsetQuery()
method. I just want to refresh a row not the whole view. The reason why I useQSqlQueryModel
is I have to fetch data from two tables. -
@ArthurPYQT
Does this have anything to do with the question you are asking in https://forum.qt.io/topic/126735/insertrow ? Don't know why you posting here and addressing me.You cannot just fetch one row from the database into the model and then expect the model to still show all rows. I don't know what this has to do with
setData()
.