Search code examples
c++qtqabstractitemviewqitemselectionmodel

Locking selection in QTableView/QTreeView


Is it possible to "lock" selection in QAbstractView?

I have a form with:

  • A list of objects I can edit (QTableView).
    Objects are stored in a database, the list shows their ID.
  • A New button, whose effect is to append an empty row I can edit to create a new ID and enable controls in the rest of the form.
  • An Edit button whose effect is to enable the edition of the rest of the form, but leaves the ID non editable.
  • Everything is driven by a state machine. There are parallel states but for the sake of this question, only transition between a Viewing state and an Editing state is relevant. Clicking either button enters the Editing state, which means testing if I am in the Editing state provides no information about whether I clicked on New or on Edit.

I am trying to lock the selection when entering the Editing state.
I cannot simply disable the view because I need to edit new IDs, I cannot connect a slot to the selectionChanged signal to restore the selection because of side effects (calls to the database + focus going all over the place), and if possible, I wish to avoid having to call QAbstractItemView::setSelectionModel (it is reset by QAbstractItemView::setModel, see below) and wish to drive this behavior thanks only to the Viewing and Editing states.

I have tried to use, but to no avail:

  • QAbstractItemModel::flags (the best I can do is prevent selecting another item but not clearing the selection.)
  • QAbstractItemView::selectionMode
  • QItemSelectionModel::select, with QItemSelectionModel::SelectionFlag::NoUpdate (The description of this enum value made me think it could block the next selection change but that is not the case).
  • Subclassing QItemSelectionModel (@chehrlic's comment below) to override all the virtual public slots.
    While it does work (a property can be used to stop the selection from changing), it is a pain that QAbstractItemView::setModel creates a new model. It does work now but I do not see any easy way to prevent the code from breaking after accumulating code changes over the span of several years.

Did I miss any existing property to achieve this? And if I did not, how can I implement a property to lock the selection but no have any other effect on my view?

At this point, the last item in the above list of things I tried does do the job but it has a downside I am trying to avoid.

This is similar to this question except it was for a now old version of Qt and the answer is not very satisfying anyway.


Solution

  • After a long time and no answer from the community, the best solution I can come up with is:

    1. Subclassing QItemSelectionModel to:
      • Create a private attribute bool selectionLocked; that drives when changes of selection must be disallowed.
      • Override all the virtual public slots so that, when selectionLocked == true, they immediately return.
    2. Using a QIdentityProxyModel as was explained in that answer (in the section discussing QTBUG-49966) to cope with selection models being created every time setModel(...) is called on the view.
      If for any reason, I need to change the model attached to a view, I can do it calling QAbstractProxyModel::setSourceModel instead of QAbstractItemView::setModel, thus ensure the selection model never gets inadvertently reset.

    This is not the full future-proof solution I was envisioning (this does not protect the application against someone adding a call to setModel in the future) but it will do for me.