QDataWidgetMapper only updates first index to QSqlRelationalTableModel - c++

I have a problem regarding parts of the QT framework. I am using QT 5.0.2 and am developing on Windows at the moment.
In my application I have a Tableview set up with a QSqlRelationalTableModel. Next to it I have a text field and 3 combo boxes connected to the relational table model. The widgets are mapped to the model using QDataWidgetMapper as follows:
mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->setItemDelegate(new QSqlRelationalDelegate(this));
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
mapper->addMapping(ui->courseComboBox, model->fieldIndex("course_shortcode"));
mapper->addMapping(ui->subjectComboBox, model->fieldIndex("subject_name"));
mapper->addMapping(ui->lecturerComboBox, model->fieldIndex("lecturer_name"));
mapper->addMapping(ui->themesTextEdit, model->fieldIndex("event_themes"));
As you see the SubmitPolicy is set to manual submit. Under the widgets i have a buttonbox containing a save and a reset button.
When the save button gets clicked, I do this:
qDebug() << this->mapper->submit();
qDebug() << model->lastError().text();
This will create the following output:
true
" "
Which means the submit was successful and there was no error reported.
Nevertheless only the first field gets updated in the model. All the other widgets reset their value to the value from the original model (because the model emits datachanged, which the mapper connected itself to, I guess).
I tried removing one or 2 of the mappings and always onl the field whichs mapping gets added first will be updated.
If I change the submitPolicy to autoSubmit the mapper does its work as intended. But I really need to have those reset and apply buttons and not have the data get submitted on change.
This seems like an occurrence of QTBug 1086 but that bug got fixed and I cant reproduce the problem from the bug report from the code there either.
I hope you can help me.

I edited my answer because I misunderstood the documentation and, after receiving a good explanation, I finally got the correct way to obtain the desired result.
You should simply modify the model edit strategy using QSqlTableModel::setEditStrategy() and change it to QSqlTableModel::OnRowChange.
This is needed in order to avoid the modifications to be sent to the underlying DB after every single column modification, something that would produce an update of the mapped widgets contents after the very first column change.

Related

Qt Quick, SQLITE - how to bind multiple views to one model / (multiple models with one db)

I'm struggling with following scenario:
I have one QML with a ListView containing all the students in SQL db
I also have another QML file which contains a Page with details of any selected student.
When user clicks on one of the entries in the list he's being moved (using StackView) to the second QML with all the details.
On the details page the user is able to modify the data and save it. The problem is that after doing that, the list is not being refreshed (e.g. when user adds a new student there is no new entry on the list).
The reason behind this is that when I open the DetailsPage, I'm delibarately creating a new model with access to the same table in SQL. When I then submit the changes, the new model gets updated but not the old one (the one connected with the list). So when I come back to the list it still holds the old data.
Now I'm looking for a way to fix it, I have some ideas but I'm not sure which of them is the best solution (maybe none):
one thing I tried was to reuse the very same model across multiple views. It didn't really work since in the DetailsPage I need to see only these rows that match the selected student. So I would need to filter it, but how? By setting a model property (I've seen that in one of the tutorials)? How would I reset it later back to the initial state?
Another idea is to create a different model for the DetailsPage and after submiting changes (possibly while popping the page from the StackView), notify the previous model about the changes and force it to emit the dataChanged signal. But again - I don't really know how to do it.
At the moment the model in StudentList is declared like that:
SqlDb {
id: sqlModel
onDataChanged: {
console.log("TROLO")
}
}
So there nothing inside it really. When opening the DetailsPage, I need to specify the name to filter the results so it looks like that:
Layout.fillHeight: true
SqlDb {
id: sql_model
name: studentName
onDataChanged: {
console.log("TRALA")
}
}
When submiting changes I got "TRALA" printed but not "TROLO".
I was mostly using this official Qt tutorial
https://doc.qt.io/qt-5/qtquickcontrols2-chattutorial-example.html

QTableView displays column headers, but no data?

I can't figure out why my QTableView won't display any data. I've searched all other questions about this problem and it seems the problem is usually someone trying to create the model on the stack and letting it go out of scope...
I am creating the model on the heap so this is not the problem, yet I still get no data in the View. The column headers from my sql table are shown correctly. What could be wrong with this code?
// db is my database wrapper and database returns a reference to the database
QSqlTableModel *tradeHistoryModel = new QSqlTableModel(this, db->database());
// table_tradeHistory is my QTableView created elsewhere
table_tradeHistory->setModel(tradeHistoryModel);
tradeHistoryModel->setTable("mytrades");
tradeHistoryModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
if (!tradeHistoryModel->select())
{
// err is just a handy macro for displaying fancy error output
// the call to select does NOT return false so this never gets called
err("model select failed!");
}
// debug is another macro, the output shows 200 rows (which is correct)
debug(QString("Got %1 rows..").arg(tradeHistoryModel->rowCount()));
So there is no error shown because select() returns true, and the debug output shows the model selected all 200 rows, but still no data appears in the View...
Thanks for any help!
Edit: This must have been a Qt or Qt Designer bug... I went back into designer and "morphed" the QTableView into a QTreeView, then switched it back and now all of a sudden it is showing the data... I did not change any of the code when I did this... wtf? If it is a bug I'm not sure I can reproduce it again...
The problem might be the tradeHistoryModel->select(). I don't
think it is selected properly. Try to call it separately, not on a IF statement. Also check the compatibility of the data, the data on the db and that on the QTableView. I had a similar problem with QDate and I managed to solve it after modifying the format it was displayed on the QTableView. The problem was PostgreSQL and Qt uses different date format.
To be sure it has nothing to do with this problem try
model->setFilter(filter);
model->select();
or
modelsql->removeColumn(0);
to remove a column that might contain this problem. Good luck!
Thanks for the post. The same thing happened to me, and morphing the QTableView into a QTreeView and then back to a QTableView also fixed it for me. When I compared before and after, the original bad ui had the section <attribute name="verticalHeaderDefaultSectionSize"><number>0</number></attribute>. Maybe that made the header expand to the entire space of the view, and with no space to show rows of data, Qt had no reason to request data from the model.
I started with a QTableWidget but later switched to a QTableView to implement batching through canFetchMore/fetchMore, so maybe this problem is something left over from the QTableWidget.

Adding items to tableView QT

i need i little help here. I'm creating a application through QtCreator (C++). It's basically a single view application that the user input two line edits, click return than the data from both fields goes to a table view. Here is my problem, i have no idea how to make it work (show the data typed and update the tableView every time the user presses return, i never used tableView before (QT)). I'm not even using database, it's not necessary. And i'm saving the data in a struct.
Any help?
Sorry about my english, thanks in advance!!!!!

Qt Views [not] updating upon underlying structure of the model changes

I have encountered an issue that is most likely WAD but I still need to solve. I originally thought it was a problem with my custom models but it is in fact present with Qt native model classes as well.
Consider this little program: https://drive.google.com/file/d/0B9MLVHQaeHKxeFBSYzVGVF9sQ0U/edit?usp=sharing
It is just fresh Qt GUI app with 2 QTreeViews and two sets of buttons for inserting/removing rows and columns on each view. The underlying models are QStandardItemModel in one view and QIdentityProxyModel in the other. The navigation is accomplished by clicking on the models – the index is stored and then used by the buttons.
Try inserting/removing rows and columns and you will notice that the views do not update right after the underlying data structure will have changed. Rather they will be updated after you hover over them. And that is the problem because in my other project I have incoming network data that updates the model data that is being displayed to user via standard Qt views. Therefore I need the views to be updated after the data changed and NOT when user hovers over them which he may not do as he may not be aware of the change.
You may notice there is the updateViews() function where I have tried to force-update the views. Neither update() nor repaint() changed anything. The former probably correctly as the documentation says but the repaint should as I understand it cause the widgets to get repainted… Is there any other way to force-update the views?
Also, the reason why I set up the proxy model is that in my project the proxies are heavily used and therefore I need to cause the view-update via them rather than via external slot/function call as is the case in the example given. But if need be this could work as a work-around as well.
Thanks!
EDIT: Problem is manifesting with columns manipulation only it seems. See detail in comments below.

Keep the selection after filtering a QTableView with a QSortFilterProxyModel

I created a QTableView linked to a QSortFilterProxyModel linked to another model.
Under the QTableView (in the GUI) there is a QLineEdit used for "searching" an element in the view.
My idea is to write in the QLineEdit what I'm looking for and let the view show only the matched elements. After filtering, I want to select the concerned item and then clean the QLineEdit for returning at the complete view.
Everything works but the selected item that will be filtered will also lose the selection because of the invalidation.
How can I solve this problem?
Why don't you remember the selected rows before the filtering and then just restore it when you're done with filtering.
You could use the QItemSelectionModel directly I'd imagine.
Use QItemSelectionModel::selectedRows() before filtering and select rows after filtering using QItemSelectionModel::select().
I know this thread is very old, but I thought I'd leave the comment for anybody else facing a similar problem.
From what you wrote it looks like the problem is in the QTableView loosing selection when you're cleaning your QLineEdit content. If you're starting your 'search' routine in the line edit's editingFinished() or textChanged() signals you can disconnect from them before changing the QLineEdit and then reconnect back again. Or use a boolean flag and don't change filtering when it's on. It would be much easier to answer your question if you would post up a simplified version of your code with the problem you're having.