How to make the scrollbar of a QListView report its correct value after a model update?

StackOverflow https://stackoverflow.com/questions/9733735

  •  24-05-2021
  •  | 
  •  

Domanda

I'm trying to set the value of a QListView scrollbar immediately after updating its model. The problem is that the scrollbar is not properly setup at that time so its maximum value is not correct. It means that when I set the value, it will never go above this (incorrect) maximum. If I add some qDebug statements in other places, I can see that the maximum is correct again after some time.

I suppose that I need to somehow force an update of the scrollbar or the view but I tried various things - updateGeometry, repaint, update, setFlow, etc. without any success.

Any suggestion on what I could do? Below is my current code:

int previousScrollValue = cardList_->verticalScrollBar()->value();

qDebug() << "Before" << previousScrollValue;

CardListModel* model = new CardListModel(deck->id());
cardList_->setModel(model); 
cardList_->verticalScrollBar()->setValue(previousScrollValue);

qDebug() << "After" << cardList_->verticalScrollBar()->value(); // Wrong value
qDebug() << "Max" << cardList_->verticalScrollBar()->maximum(); // Wrong value
È stato utile?

Soluzione 3

After lots of trial and error, I've finally found out what was causing this issue:

I had the QListView layout mode set to Batched with a size of 2x2. I'm not sure why I had this set, but I guess it's meant to make the display smoother by rendering batches of items instead of everything in one go. The problem (I guess) is that it messes up with the scrollbar, which continuously gets updated as batches are being rendered, and it only gets in a stable state (with a proper maximum and value) when everything is rendered. Only then does it make sense to call setValue on it (but there's no way to know when all the items have been rendered).

So, the fix was simple - I just set back the layoutMode to SinglePass and now the scrollbar works as expected (and the display is not noticeably slower). No need to save and restore the scrollbar value either, it works as is.

Altri suggerimenti

I think that updateGeometries is the function you need to call. If you check the implementation of the scrollToBottom function you will see that this is the function that is called:

void QAbstractItemView::scrollToBottom()
{
    Q_D(QAbstractItemView);
    if (d->delayedPendingLayout) {
        d->executePostedLayout();
        updateGeometries();
    }
    verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}

The difference with the updateGeometry is that the geometries of the child widgets of the view will be updated.

If that doesn't work you could do:

cardList_->scrollToBottom();
qDebug() << "Max" << cardList_->verticalScrollBar()->maximum();

Did you try to put a QCoreApplication::processEvents() after the setModel? I.e.:

CardListModel* model = new CardListModel(deck->id());
cardList_->setModel(model); 
QCoreApplication::processEvents();
cardList_->verticalScrollBar()->setValue(previousScrollValue);

qDebug() << "After" << cardList_->verticalScrollBar()->value(); // Wrong value
qDebug() << "Max" << cardList_->verticalScrollBar()->maximum(); // Wrong value

I suspect updating the scrollbar values only happen in the event loop.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top