提问人:Letynn C 提问时间:11/17/2023 更新时间:11/19/2023 访问量:44
多个QTableWidget的共享选择
Shared selection for several QTableWidgets
问:
我正在使用Qt 5.6.1。有几个 QTableWidget 表,理论上它们代表一个表 - 它们位于紧密的位置,并且行上的数据是相互关联的,但它们应该呈现为单独的小部件。它们的选择标志是 SelectRows 和 ExtendedSelection mod。我怎样才能为他们做一个一般的选择?假设您选择了第一个表的几行,并在其他表中选择了相同的行。应相应地删除所选内容。表具有不同的列数。
我尝试以这种方式处理来自 selectionModel 表的信号:selectionChanged
void wSpisokActive::selectionChangedMain(const QItemSelection &selected, const QItemSelection &deselected)
{
permission_to_changed_main_ = false; // flag to exit a similar slot in another table
if (permission_to_changed_monitoring_) { // select row
QModelIndexList selected_list = selected.indexes();
for (QModelIndex model_index: selected_list) {
ui->tbMonitoring->selectRow(model_index.row());
}
QModelIndexList deselected_list = deselected.indexes();
int last_row = -1;
for (QModelIndex model_index: deselected_list) { // deselect row
if (last_row == model_index.row()) continue;
last_row = model_index.row();
for (int i = 0; i < ui->tbMonitoring->columnCount(); ++i) {
ui->tbMonitoring->selectionModel()->select(ui->tbMonitoring->model()->index(last_row, i), QItemSelectionModel::Deselect);
}
}
}
permission_to_changed_main_ = true;
}
但是这样,通过 Ctrl 进行选择的处理方式会不正确。此外,在选择几行时,只有最后一行会突出显示 - 我尝试在选择行之前和之后进行设置。但这无济于事。ui->tbMonitoring->setSelectionMode(QAbstractItemView::MultiSelection);
ui->tbMonitoring->setSelectionMode(QAbstractItemView::ExtendedSelection);
答:
正如本帮助页面中所解释的(我的重点):
有关视图中所选项的信息存储在 QItemSelectionModel 类的实例中。这将维护单个模型中项的模型索引,并且独立于任何视图。由于一个模型上可以有多个视图,因此可以在视图之间共享选择,从而允许应用程序以一致的方式显示多个视图。
您感兴趣的方法成对出现:
selectionModel(
) /setSelectionModel(QItemSelectionModel*)
对于最后一个,请花一分钟时间仔细阅读文档的内容,即:请注意,如果在此函数之后调用 setModel(),则给定的 selectionModel 将被视图创建的 selectionModel 替换。
如果不再需要旧的选择模型,则由应用程序删除 [...]
生成的代码如下所示(假设这是在您的主线程上):
auto widgetModel = myTableWidget->model();
auto widgetSelModel = myTableWidget->selectionModel();
for (auto view : { myTableView1, myTableView2, myTableView3 }) {
view->setModel(widgetModel);
delete view->selectionModel();
view->setSelectionModel(widgetSelModel);
}
编辑:关于QTBUG-49966,@musicamante在评论中指出。
为了减少追逐:是的,每个视图 1 个选择模型(更确切地说,视图的标题视图的 1 个选择模型)将保留在内存中,直到视图及其标题被删除。
但是,如果您只执行我上面介绍的内容,则每个视图只会“泄漏”1个选择模型(这应该是一个非常小的数字),当您删除视图时,这些模型将被删除。
如果要实现一个窗口,其中调用了任意次数(例如,请参阅注释中 @musicamante 描述的场景),则可以执行以下几项操作作为缓解措施:setModel
要限制内存泄漏的生存期,请执行以下操作:
- AFAICT,Qt创建的所有选择模型都有一个父集。
如果确保删除小部件(确保在关闭窗口时清除所有内容的最简单方法是调用 ),则这些未使用的选择模型不会比视图更长久。myWindow->setAttribute(Qt::WA_DeleteOnClose);
如果你从不删除视图/小部件,那么内存泄漏就在你身上(你永远不会删除你创建的对象),而不是因为Qt创建的未使用的选择模型。
- 切勿自行创建选择模型,至少在不设置其父模型的情况下。我希望这是显而易见的,但永远不要打电话。
只要所有选择模型都具有视图作为其父视图,它们就会随视图一起删除。mySelectionModel->setParent(nullptr);
- AFAICT,Qt创建的所有选择模型都有一个父集。
若要限制内存泄漏的大小:必须确保每个视图不要多次调用:
setModel()
- 如果您的模型支持重置,则使用这种可能性。
QSqlTableModel
示例:不应通过创建新模型来替换现有模型来更改加载的SQL表。相反,请执行以下操作:
myExistingSqlTableModel->setTable(newlySelectedTable); myExistingSqlTableModel->select();
- 如果您确实必须更改模型(例如,因为模型不支持重置,或者因为新模型与现有模型的类型不同),由于
QIdentityProxyModel
,您仍然有一条出路。
代理模型的目的不应该是这个,但它在这里派上用场。可以在视图上更改模型(至少,这是它的视觉外观),而无需调用 .
它是通过执行以下操作来初始化的:setModel
QIdentityProxyModel* proxyModel = new QIdentityProxyModel(myView); proxyModel->setSourceModel(myModel); myView->setModel(proxyModel);
然后,可以将新模型附加到视图:
if (auto proxyModel = dynamic_cast<QAbstractProxyModel*>(myView->model()); proxyModel) { if (proxyModel->sourceModel()) delete proxyModel->sourceModel(); proxyModel->setSourceModel(myNewModel); }
瞧!不再需要在同一视图上多次调用。
setModel
- 如果您的模型支持重置,则使用这种可能性。
与此相关的是,如果我能提出一个快速(可选)的建议:
- 有经验的Qt开发人员倾向于偏爱,而不是同行。
虽然是初学者的首选课程,简化了很多所需的工作,但它对灵活性设置了如此有限的限制,以至于缺点远远大于优点。QListView
QTableView
QTreeView
QxxxxxWidget
QTableWidget
- 有经验的Qt开发人员也倾向于避免(注意,所有类都使用自己的内部独立模型)。
如果您的应用程序已经具有一些内部结构来存储屏幕上显示的数据,则将其映射到 的自定义子类(而不是将其复制到独立模型(如 )中通常更有效。QStandardItemModel
QxxxxxWidget
QAbstractItemModel
QStandardItemModel
你越早习惯于创建自己的模型类,你的生活就会变得越轻松。
如果您使用的是表格,则可以使用 QAbstractTableModel
开始您的学习之旅。它应该足够容易作为起点,并且通常与 相比更容易进行子类化。QAbstractItemModel
以上内容适用于您当前的代码,因此请随意忽略此建议。
评论
setModel()
setModel()
setSelectionModel()
QAbstractItemView::setModel
QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
setModel(nullptr);
new QItemSelectionModel()
setModel()
QTableView.setModel()
setModel()
评论
SelectRows
setColumnHidden()