QListView:当从顶部删除项目时,如何自动滚动视图并保持视图中正确项目的当前选择



我有一个带有自定义模型的列表视图。该模型允许我将文本添加到列表的底部(使用"addText(const QString&)"),并从列表的顶部删除项目(使用"removeItemsFromTop(int _iCount)")。

向视图中添加文本并将模型大小保持在某个最大值以下(比如"MAX_LIST_size"),同时始终保持视图的最佳方式是什么(即,删除项目时,当前选择和视图中的项目不应更改)。

解决方案最好是一个函数,我可以在任何使用自定义模型的地方使用它。

我看过QListView上的indexAt(…)、scrollTo(…),currentIndex(…)和setCurrentIndex(。

到目前为止,我有(自动滚动视图)

// add items here ...
// cleanup
QModelIndex indexViewTop = listView->indexAt(QPoint(8, 8));
if (listModel->rowCount() > MAX_SIZE)
{
    int iRemoveCount = (listModel->rowCount() - MAX_SIZE) + MAX_SIZE/10;
    listModel->clearTextFromFront(iRemoveCount);
    listView->scrollTo(indexViewTop.sibling(indexViewTop.row() - iRemoveCount, 0), QAbstractItemView::PositionAtTop);
}

这应该是在删除项目时滚动列表视图以保持视图的一致性,但indexAt(…)总是返回无效索引。

为了保持选择的一致性,我尝试了:

// add items her ...
// cleanup
if (listModel->rowCount() > MAX_SIZE)
{
  int iCurrentViewIndex = listView->currentIndex().row();
  int iRemoveCount = (listModel->rowCount() - MAX_SIZE) + MAX_SIZE/10;
  listModel->clearTextFromFront(iRemoveCount);
  listView->setCurrentIndex(listModel->index(iCurrentViewIndex - iRemoveCount, 0));
}

这似乎奏效了,但我仍然坚持自动滚动。

我做了一个类似队列的表模型实现。我认为QAbstractItemModel类似。最好的方法是使用QQueue来存储数据。

现在,这是对QAbstractTableModel(它是QAbstractItemModel的子类,所以它应该工作;mEventsQQueue)的剪切:

// custom table for inserting events
void EventPreviewTableModel::insertEvent(const DeviceEvent &event) {
    beginInsertRows(QModelIndex(), 0, 0);
    mEvents.enqueue(event);
    endInsertRows();
    if (mEvents.size() > SIZE) {
      beginRemoveRows(QModelIndex(), mEvents.size(), mEvents.size());
      mEvents.dequeue();
      endRemoveRows();
    }
}

并且还覆盖data()rowCount()以提供正确的数据。

对于第二部分,为您想要选择的项目使用ItemIsSelected标志是通过以下方式完成的:Qt::ItemFlags QAbstractItemModel::flags(const QModelIndex & index)

这是我目前的方法,它似乎运行良好:

void addTitlesToList(Model *model, QListView *view, std::vector<Object*> &items)
{
    QScrollBar *pVerticalScrollBar = view->verticalScrollBar();
    bool bScrolledToBottom = pVerticalScrollBar->value() == pVerticalScrollBar->maximum();
    QModelIndex indexViewTop = view->indexAt(QPoint(8, 8));
    // add to model
    model->pushItems(items);
    // cleanup if model gets too big
    if (model->rowCount() > model->maxListSize())
    {
        int iCurrentViewIndex = view->currentIndex().row();
        int iRemoveCount = (int)(model->rowCount() - model->maxListSize()) + (int)model->maxListSize()/10;
        model->removeItemsFromFront(iRemoveCount);
        // scrolls to maintain view on items
        if (bScrolledToBottom == false)
        {
            _pView->scrollTo(indexViewTop.sibling(indexViewTop.row() - iRemoveCount, 0), QAbstractItemView::PositionAtTop);
        }
        // maintain selection
        if (iCurrentViewIndex >= iRemoveCount)
        {
            view->setCurrentIndex(_pModel->index(iCurrentViewIndex - iRemoveCount, 0));
        }
        else
        {
            view->setCurrentIndex(QModelIndex());
        }
    }
    // move scroll bar to keep new items in view (if scrolled to the bottom)
    if (bScrolledToBottom == true)
    {
        view->scrollToBottom();
    }
}

我使用indexAt(QPoint(...))时遇到的一个问题是,我在将项目添加到列表后调用它,这似乎导致它总是返回一个无效索引。在向模型中添加任何内容之前调用indexAt似乎有效。如果已经存在,我还添加了自动"滚动到底"(即,如果一直滚动到底,视图要么固定在特定项目上,要么坚持到最新项目)。

相关内容

最新更新