保持在QTableView中选择行

时间:2016-07-18 09:46:30

标签: qt qt4

我正在开发一个程序来查看和编辑文件中的记录。它具有显示所有记录的QTableView,用于搜索记录的QLineEdit以及显示所选记录详细信息的一些标签:

record viewer

有一个QAbstractTableModel类来保存数据,一个QSortFilterProxyModel类可以帮助过滤QTableView中的行。

搜索和过滤工作正常。在搜索框中键入文本会立即过滤记录列表。但有两件事我无法开展工作:

  1. 如果列表不为空,我想要一个项目被选中/当前总是
  2. 在搜索框中输入
  3. 时,必须将所选/当前项目置于视图中

    例如,当我输入“tesla”时,列表将为空,因为没有项匹配。但是当我退回到“te”时,“Forester”会匹配,我希望它被选中。第二个例子:当(在启动程序之后)我输入“f”时,列表缩小到8个项目并选择“Pacifica”。当我删除“f”时,仍然选择了Pacifica但不再位于列表的可见部分。

    我已在Pastie上发布了完整的源代码,以下是一些(希望)相关的摘要。

    void MainWindow::on_lineEditSearch_textChanged(const QString & text)
    {
        itemProxy->setFilterFixedString(text);
    
        updateStatusBar();
    }
    
    void MainWindow::currentRowChangedSlot(QModelIndex const & current, QModelIndex const & /*previous*/)
    {
        Car * car = 0;
    
        if (current.isValid())
        {
            QModelIndex sibling = current.sibling(current.row(), COLUMN_THIS);
            QVariant variant = itemProxy->data(sibling);
            car = static_cast<Car *> (variant.value<void *> ());
        }
    
        updateCarMake(car);
        updateCarModel(car);
    }
    
    MainWindow::MainWindow(QWidget * parent, CarItemModel * itemModel, CarSortFilterProxyModel * itemProxy) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        this->itemModel = itemModel;
        this->itemProxy = itemProxy;
    
        ui->setupUi(this);
        setupStatusBar();
    
        ui->tableView->setModel(itemProxy);
    
        ui->tableView->setColumnHidden(COLUMN_THIS, true);
    
        QItemSelectionModel * selectionModel = ui->tableView->selectionModel();
    
        connect(selectionModel, SIGNAL(currentRowChanged(QModelIndex const &, QModelIndex const &)),
                this, SLOT(currentRowChangedSlot(QModelIndex const &, QModelIndex const &)));
    
        connect(selectionModel, SIGNAL(selectionChanged(QItemSelection const &, QItemSelection const &)),
                this, SLOT(selectionChangedSlot(QItemSelection const &, QItemSelection const &)));
    
        ui->tableView->selectRow(0);
    
        ui->lineEditSearch->setFocus();
    
        updateStatusBar();
    }
    
    <widget class="QTableView" name="tableView">
     <property name="verticalScrollBarPolicy">
      <enum>Qt::ScrollBarAlwaysOn</enum>
     </property>
     <property name="selectionMode">
      <enum>QAbstractItemView::SingleSelection</enum>
     </property>
     <property name="selectionBehavior">
      <enum>QAbstractItemView::SelectRows</enum>
     </property>
    </widget>
    

    所以,我的问题是:我怎样才能确保总是选择一个项目并且在列表的可见部分(除非用户正在滚动)?

2 个答案:

答案 0 :(得分:1)

这是我做的

  • 始终选择一个项目,
  • 在搜索时显示所选项目

解决方案甚至有点过分了,因为当从无可见项目转到某些可见项目时,将选择最近选择的项目,而不是仅选择第一项。

首先,我向QModelIndex lastModelIndex;类添加了MainWindow个私有成员,并将其设置在SelectionChanged广告位中。请注意,模型索引是存储的,而不是代理索引。

void MainWindow::selectionChangedSlot(QItemSelection const & selected, QItemSelection const & /*deselected*/)
{
    if (selected.count() > 0)
    {
        QModelIndex index = selected.indexes().first();
        QModelIndex modelIndex = itemProxy->mapToSource(index);

        lastModelIndex = modelIndex;
    }
}

接下来,我添加了两种方法:ensureSelected() ...

void MainWindow::ensureSelected(QItemSelectionModel * selectionModel, int const proxyCount)
{
    if (selectionModel->hasSelection())
    {
        // an item is currently selected - don't have to do anything
    }
    else if (proxyCount == 1)
    {
        // no item is currently selected, but there is exactly one item in the list - select it
        QModelIndex proxyIndex = itemProxy->index(0, 0);

        selectionModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);
    }
    else if (proxyCount > 1)
    {
        // no item is currently selected, but there are several items in the list

        QModelIndex proxyIndex; // !isValid

        if (lastModelIndex.isValid())
        {
            // there's a most recently selected item - compute its index in the list
            proxyIndex = itemProxy->mapFromSource(lastModelIndex);
        }

        if (proxyIndex.isValid())
        {
            // the most recently selected item is in the list - select it
            proxyIndex =  proxyIndex.sibling(proxyIndex.row(), COLUMN_THIS);
        }
        else
        {
            // there's no most recently selected item or it is no longer in the list - select the first item
            proxyIndex = itemProxy->index(0, 0);
        }

        selectionModel->setCurrentIndex(proxyIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);
    }
    else
    {
        // There are no items in the list - cannot select anything.
    }
}

...和ensureVisible()

void MainWindow::ensureVisible(QItemSelectionModel * selectionModel)
{
    if (selectionModel->hasSelection())
    {
        const QModelIndex index = ui->tableView->currentIndex();

        ui->tableView->scrollTo(index);
        ui->tableView->selectRow(index.row());
        ui->tableView->scrollTo(index);
    }
}

看起来很奇怪,我必须两次调用scrollTo(),否则tableView将不会滚动。

这些新方法从on_lineEditSearch_textChanged()调用,如下所示:

void MainWindow::on_lineEditSearch_textChanged(const QString & text)
{
    itemProxy->setFilterFixedString(text);

    QItemSelectionModel * selectionModel = ui->tableView->selectionModel();

    int modelCount = itemModel->rowCount(); // number of items in the model
    int proxyCount = itemProxy->rowCount(); // number of items in tableview

    ensureSelected(selectionModel, proxyCount);

    ensureVisible(selectionModel);

    updateStatusBar();
}

请在Pastie上找到更新完整的源代码。

答案 1 :(得分:0)

处理选择更改信号并将其连接到您的自定义插槽:

 QSortFilterProxyModel *model = new QSortFilterProxyModel(this);
    ui->tableView->setModel(model);
    connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection)));

每次,您的表格更改当前选择,应用程序应选择模型中的第一个项目:

void MainWindow::selectionChanged(QItemSelection selected, QItemSelection deselected) {
    // Use this 
    const int rows = ui->tableView->selectionModel()->selectedRows().size();
    // or 
    const int rowCount = selected.size();

    // Lets select the first item if there are some items availables
    if (rowCount < 1) {
        const int availableItems  = ui->tableView->model()->rowCount();
        if (availableItems > 0) {
            const QModelIndex index = ui->tableView->model()->index(0,0);
            ui->tableView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
        }
    }

}

通过这种方式,您应该至少选择一个项目。