QTreeView:如何中止选择更改

Posted

技术标签:

【中文标题】QTreeView:如何中止选择更改【英文标题】:QTreeView: how to abort selection change 【发布时间】:2018-05-07 16:13:25 【问题描述】:

我的小部件中有一个QTreeView。在视图中选择一个项目时,我有 一个信号处理程序,用于更新详细信息窗口中的一系列信息小部件 关于所选项目。然后,用户可以编辑项目详细信息并提交 变回模型。

如果此选择更改时详细信息视图中的数据已被编辑 发生时,我会在替换数据之前向用户显示一个确认对话框 选择新项目时。如果用户取消,我想设置选择 树恢复到原来的样子。

我的插槽是这样连接的:

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

在我的插槽中,代码结构如下:

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);
    

但是,将当前索引设置回之前好像并没有 影响 TreeView;它仍然将新选择的项目显示为选中,并且 界面变得不连贯,因为详细信息中显示的项目是 不是树中选择的那个。

预期的行为是重新选择先前选择的项目,就好像没有 完全做出了新的选择。

【问题讨论】:

【参考方案1】:

显然QTreeView 在调用currentChanged 插槽时忽略了选择模型的任何更新。

这里的解决方案是将插槽称为QueuedConnection,因此connect 行将如下所示:

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

这将确保选择模型的选择更改不会直接发生在插槽调用中。

【讨论】:

它不能做很多其他事情:毕竟,你的插槽代码正在运行。但真正发生的是你被编写伪同步代码咬了。对话处理程序属于一个插槽!如果你这样做了,你就永远不会遇到这个问题。 你能运行一个非同步的模态对话框吗? 是的,你可以。模态只是 UI 的一种特殊状态,它不会改变它的异步行为。像运行伪同步代码这样的特殊技巧只是把问题扫到了地毯下。

以上是关于QTreeView:如何中止选择更改的主要内容,如果未能解决你的问题,请参考以下文章

QTableWidget 作为 QTreeView 中的子级

如何配置 QTreeView 以在使用箭头键移动时保留多项选择

在 PySide 的 QTreeView 中更改时如何获取项目的先前名称

Qt QTreeView - 当条件不满足时恢复到以前的选择

更改 QTreeView 中的某些数据

调用 QItemSelectionModel::select 后如何重绘 QTreeView?