同步可排序QTableWidgets的选择

时间:2018-01-04 11:14:45

标签: c++ qt qtablewidget qtablewidgetitem qmodelindex

我有两个QTableWidgets,具有相同的行数和列数。现在,一个表中的每个选择都应该自动更新另一个表中的选择,反之亦然。

以下代码正常,但有一个例外:

#include <QApplication>
#include <QTableWidget>
#include <QHBoxLayout>
#include <functional>

QTableWidget* create() {
    auto table = new QTableWidget;
    table->setSortingEnabled(true);
    table->setRowCount(20);
    table->setColumnCount(1);
    for (auto i = 0; i < 20; i++) {
        {
            auto item = new QTableWidgetItem(QString("%1").arg(i+1));
            table->setItem(i, 1, item);
        }
    }
    return table;
}
int main(int argc, char** args) {
    QApplication app(argc, args);

    QTableWidget* table1 = create();
    QTableWidget* table2 = create();
    auto frame = new QFrame;
    frame->setLayout(new QHBoxLayout);
    frame->layout()->addWidget(table1);
    frame->layout()->addWidget(table2);
    frame->show();
    auto func = [&](QTableWidget* senderTable, QTableWidget* receiverTable) {
        const QSignalBlocker blocker(receiverTable);
        receiverTable->selectionModel()->clearSelection();
        for (auto item : senderTable->selectedItems()) {
            receiverTable->item(item->row(), item->column())->setSelected(true);
        }
    };

    QObject::connect(table2, &QTableWidget::itemSelectionChanged, std::bind(func, table2, table1));
    QObject::connect(table1, &QTableWidget::itemSelectionChanged, std::bind(func, table1, table2));
    app.exec();
}

如果我对一列进行排序,则会发生异常。在这种情况下,在另一个表中选择wrong项。

Wrong selection occurred if sorting is enabled.

换句话说,选择同步的行为应该与所选的排序无关。我的表格的内容只是一些例子。

实现理想行为的最简单方法是什么?

1 个答案:

答案 0 :(得分:0)

我修改了您的示例,使其按预期工作。我们的想法是,我们不应该依赖于物品&#39;行和列,而是在每个项目中存储一些唯一标识符,而不是按行和列执行查找,而不是按行和列执行查找,具体取决于排序顺序。

所以,这是代码,它演示了我所说的内容:

#include <QApplication>
#include <QTableWidget>
#include <QHBoxLayout>
#include <functional>
#include <assert.h>

QTableWidget* create()
{
  auto table = new QTableWidget;
  table->setSortingEnabled(true);
  table->setRowCount(20);
  table->setColumnCount(1);
  for (auto i = 0; i < 20; i++) {
    auto item = new QTableWidgetItem(QString("%1").arg(i + 1));
    item->setData(Qt::UserRole, i); // It can be any kind of unique identifier.
    table->setItem(i, 1, item);
  }
  return table;
}

int main(int argc, char** args)
{
  QApplication app(argc, args);

  QTableWidget* table1 = create();
  QTableWidget* table2 = create();
  auto frame = new QFrame;
  frame->setLayout(new QHBoxLayout);
  frame->layout()->addWidget(table1);
  frame->layout()->addWidget(table2);
  frame->show();
  auto func = [&](QTableWidget* senderTable, QTableWidget* receiverTable) {
    const QSignalBlocker blocker(receiverTable);
    receiverTable->selectionModel()->clearSelection();
    auto model = receiverTable->model();
    for (auto item : senderTable->selectedItems()) {
      // Find the item with the same identifier.
      auto found = model->match(model->index(0, 0), Qt::UserRole, item->data(Qt::UserRole));
      assert(!found.empty());
      auto idx = found.first();
      receiverTable->item(idx.row(), idx.column())->setSelected(true);
    }
  };

  QObject::connect(table2, &QTableWidget::itemSelectionChanged, std::bind(func, table2, table1));
  QObject::connect(table1, &QTableWidget::itemSelectionChanged, std::bind(func, table1, table2));
  app.exec();
}