我有一个带有自定义模型的列表视图。该模型允许我将文本添加到列表的底部(使用"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
的子类,所以它应该工作;mEvents
是QQueue
)的剪切:
// 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似乎有效。如果已经存在,我还添加了自动"滚动到底"(即,如果一直滚动到底,视图要么固定在特定项目上,要么坚持到最新项目)。