2
votes

I have a QTreeView in my widget. When an item is selected in the view, I have a signal handler that updates a series of information widgets in a detail window about the selected item. The user can then edit the item details and commit the changes back to the model.

If the data in the details view has been edited when this selection change happens, I present a confirmation dialog to the user before replacing the data when a new item is selected. If the user cancels, I want to set the selection of the tree back to what it was before.

I have my slot connected like so:

auto selection_model = treeview->selectionModel();
connect(
    selection_model, &QItemSelectionModel::currentChanged,
    this, &Editor::on_tree_selection_changed
)

Inside my slot, the code is structured as follows:

void on_tree_selection_changed(QModelIndex const& index, QModelIndex const& previous)
{
    if(not confirm_editor_discard()) 
    { 
        // user does not want to override current edits
        log.trace("cancel item selection change");
        using SF = QItemSelectionModel::SelectionFlags;
        auto sm = treeview->selectionModel();
        sm->setCurrentIndex(previous, SF::SelectCurrent | SF::Rows);
    }
    else
    {
        // user wants to discard, so update the details view.
        log.trace("discard pending edits");
        set_details_from_model(index);
    }
}

However, the setting of the current index back to the previous does not seem to affect the TreeView; it still displays the newly selected item as selected, and the interface becomes non-coherent since the item displayed in the details is not the one shown as selected in the tree.

The intended behaviour is to re-select the previously selected item, as if no new selection was made at all.

1

1 Answers

1
votes

Apparently the QTreeView ignores any updates from the selection model while the currentChanged slot is being called.

The solution here was to call the slot as a QueuedConnection, so the connect line would look like this:

connect(
    selection_model, &QItemSelectionModel::currentChanged,
    this, &Editor::on_tree_selection_changed,
    Qt::QueuedConnection // <-- connection must be queued. 
)

This will ensure that the change in selection of the selection model will not happen directly inside a slot call.