1

请运行以下代码(我使用的是 Qt 5.9):

QTableWidget* tableWidget = new QTableWidget(2, 2, nullptr);
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
connect(tableWidget->selectionModel(), &QItemSelectionModel::selectionChanged,
   [&](const QItemSelection& selected, const QItemSelection& deselected) 
   { qDebug() << "selected =" << selected << endl << "deselected =" << deselected; });
tableWidget->show();
QTimer::singleShot(10000, [=](){ tableWidget->removeRow(0); });

在 10 秒内,选择两行中的第一行。您将看到调试输出。它将显示您单击选择了第 0 行。然后,10 秒后,第 0 行被自动删除。调试输出现在显示第 1 行被选中,第 0 行被取消选中。

后者对我没有任何意义。删除第 0 行时,我希望之后会选择“新”第 0 行。此外,视觉选择的行仍然是第 0 行,而第 1 行根本不存在。

自定义模型和通用视图也会发生这种情况,并通过指向不存在的行使我的应用程序崩溃。

这是期望的行为吗?我的误解在哪里?

4

1 回答 1

0

在删除选定行之前更改它是非常有意义的。做相反的事情可能会导致读取悬空数据,例如,如果 UI 在模型更改时刷新但视图包含过时的索引。

考虑两次删除第 0 行:第二次很明显,必须在删除表中的最后一行之前更改选择(在这种情况下取​​消选择)以避免将无效索引作为所选行。

您可以使用以下修改后的示例来查看模型何时实际更新。

auto tableWidget = new QTableWidget(2, 2, nullptr);
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);

connect(tableWidget->selectionModel(), &QItemSelectionModel::selectionChanged,
[&](const QItemSelection& selected, const QItemSelection& deselected) 
{ qDebug() << "selected =" << selected << endl << "deselected =" << deselected; });

connect(tableWidget->model(), &QAbstractItemModel::rowsRemoved, [&](const QModelIndex &, int first, int last)
{ qDebug() << "first row removed =" << first << endl << "last row removed =" << last; });

tableWidget->show();

QTimer::singleShot(10000, [=](){ tableWidget->removeRow(0); });
QTimer::singleShot(15000, [=](){ tableWidget->removeRow(0); }); // remove twice

解决方法

主要问题是,正如您在评论中指出的那样,您不能依赖信号信息:QModelIndex如果执行了删除,这些信息可能有效也可能无效。您可以跟踪所有更改,但这会让人筋疲力尽。

相反,您可以尝试延迟选择信号,以便在处理它时模型已更新,您可以信任来自选择模型的信息。诀窍是使用计时器:处理超时事件的函数将在事件循环的下一次迭代中执行(即使超时时间为 0),而模型和小部件在当前迭代中更新:

connect(tableWidget->selectionModel(), &QItemSelectionModel::selectionChanged,
[&](const QItemSelection&, const QItemSelection&) {
  QTimer::singleShot(0, [&]() {
    qDebug() << "selected =" << tableWidget->selectionModel()->selectedIndexes() << endl;
  });
});
于 2017-06-23T14:51:47.140 回答