c++ 多个QTableWidget的共享选择

tcbh2hod  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(103)

我使用的是Qt 5.6.1。QTableWidget有多个表,理论上它们代表一个表--它们位置很近,行上的数据是相互连接的,但它们应该作为单独的widget呈现。它们的选择标志是SelectList,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);。但是它没有帮助。

x0fgdtte

x0fgdtte1#

正如这个帮助页面所解释的(我的重点):
视图中所选项目的相关信息存储在QItemSelectionModel类的示例中。这将维护单个模型中项目的模型索引,并且独立于任何视图。由于模型上可能有许多视图,因此可以在视图之间共享选择,从而允许应用程序以一致的方式显示多个视图。
您感兴趣的方法成对出现:

  • model / setModel(QAbstractItemModel*)
  • 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在评论中指出。

开门见山:,每个视图有一个选择模型(更确切地说,视图的头视图有一个选择模型)将保留在内存中,直到视图沿着它的头一起被删除。
然而,如果你只做我上面提到的事情,那么每个视图只有一个选择模型“泄漏”(这应该是一个非常小的数字),当你删除视图时,它会被删除。
如果你正在实现一个setModel被调用任意次数的窗口(例如,请参阅@musicamante在评论中描述的场景),你可以做几件事作为缓解措施:

  • 要限制内存泄漏的生存期,请执行以下操作:
  • AFAICT,Qt创建的所有选择模型都有一个父集合。

如果你确保小部件被删除(确保在关闭窗口时清除所有内容的最简单方法是调用myWindow->setAttribute(Qt::WA_DeleteOnClose);),这些未使用的选择模型将不会比你的视图更持久。

  • 如果你从不删除视图/小部件,那么内存泄漏是你的责任(从不删除你创建的对象),而不是因为Qt创建的未使用的选择模型。
  • 永远不要自己创建选择模型,至少不要设置它的父模型。我希望它是显而易见的,但也不要调用mySelectionModel->setParent(nullptr);

只要所有的选择模型都有一个视图作为它们的父视图,它们就会和视图一起被删除。

  • 要限制内存泄漏的大小,请执行以下操作:

您必须确保每个视图调用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开发人员倾向于支持QListViewQTableViewQTreeView,而不是QxxxxxWidget

虽然QTableWidget是初学者的首选类,简化了许多必要的工作,但它对灵活性的限制远远超过了优点。

  • 经验丰富的Qt开发人员也倾向于避免QStandardItemModel(注意QxxxxxWidget类都使用自己的内部独立模型)。

如果您的应用程序已经有一些内部结构来存储屏幕上显示的数据,通常将其MapQAbstractItemModel的自定义子类中比将其复制QStandardItemModel等独立模型中更有效。
您越早习惯于创建自己的模型类,您的生活就越容易。
在你的例子中,你正在使用表,你可以从QAbstractTableModel开始你的学习之旅。它应该是一个足够容易访问的起点,一般来说,与QAbstractItemModel相比,它更容易子类化。

  • 以上内容将适用于您当前的代码,因此请随意忽略此建议 *。

相关问题