Please nominate your Qt Champions for 2021!

How to retain the selection when altering the query of a QSqlQueryModel?

  • I want to show a list of items in a QTableView. The user selects one by clicking on a row (SingleSelection, SelectRows).

    I use QSqlQueryModel as a model to select the items from a database. In order to sort them when the user clicks on a column header I have overridden QAbstractItemModel::sort() and reset the query with setQuery(). My problem is that this removes the selection from the view.

    What is the best way to restore the selection or even better not to lose it in the first place?

  • A QSortFilterProxyModel between your model and the view: let it handle the sorting.

  • Simple answer: "you can't"! QSqlQueryModel is "read-only".

    There is a possible way but It could be impractical:

    storing the current selection (into a QModelIndex, using currentIndex())

    call "setQuery()"

    iterate over the indexes

    compare it to the stored QModelIndex

    select the row if they are the same.

  • Won't work. QModelIndex is not meant to be stored. They are only valid for a very short time. Your setQuery will certainly invalidate them.

    I'd iterate over the selected items, and get a database index for them. Then, after re-setting the query, iterate over all the items in the model until you have found the database ID's you stored before the reset.

  • When I let QSortFilterProxyModel do the sorting I get this behaviour:

    It appears that only 256 items are shown in the QTableView. When clicking on a row header only these items get sorted. When I scroll down to the last item the next chunk of data is filled into the view and sorted accordingly. Is there something I could do to get all data sorted?

    There are actually two problems related to my initial approach (to sort the data with setQuery()):

    1. Noticing when the selection gets lost without compromising encapsulation. There appears to be no signal when loosing the selection.
    2. As you pointed out: to find the apropriate model index one would have to iterate through the model.

  • The 256 rows are the QSqlQueryModel lazy loading getting in the way.

    Obviously no good if you have 10 million rows but for a thousand or so:
    while (model->canFetchMore())

    will fully load the base model and QSortFilterProxyModel will work as you expect.

    Since you know when your code is handling a sort change you could stash the data Andre suggests then. You do get a modelAboutToBeReset() signal that I'd expect you will see when you reset the underlying query but I think it is too late to stash the data: worth checking though.

    You can use QAbstractItemModel::match() to find the selected item again.

Log in to reply