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

时间:2015-12-12 06:26:02

标签: c++ qt

我有一个带有自定义模型的列表视图。该模型允许我将文本添加到列表的底部(使用'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));
}

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

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

这是我目前的做法,似乎效果很好:

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似乎可行。 如果已经存在,我还添加了自动“滚动到底部”(即,视图要么固定在特定项目上,要么在最后滚动到底部时粘贴到最新项目。)