Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Scroll QTableView as soon as model changes



  • I have a QTableView subclass that displays a QStandardItemModel subclass, I want to scroll to a certain row as soon as the model updates.

    class OrderBook : public QStandardItemModel
    ...
    
    void OrderBook::updateModel() {
    	std::pair<double, double> minMax = getMinMaxPrice();
    	if (minMax.first == -1 && minMax.second == -1) {
    		setRowCount(0);
    		return;
    	}
    	int numRows = calculateNumRows(minMax.first, minMax.second);
    	setRowCount(numRows);
    	resetCells();
    	setPrices(minMax.second);
    	setOtherOrders(minMax.second);
    	setOwnOrders(minMax.second);
    
    	emit midPointChanged(calculateMidPoint());
    }
    
    class OrderBookView : public QTableView
    ...
    
    void OrderBookView::onMidPointChanged(double midPoint) {
    	//repaint();
    	size_t row = findClosestRow(midPoint);
    	QModelIndex index = model()->index(row, 0);
    	scrollTo(index, QAbstractItemView::ScrollHint::PositionAtCenter);
    }
    

    The slots and signals are connected and the slot is called, the model also has the correct row count, but after rows were added it does not scroll the first time. It will scroll the second time the model is updated, probably because the rows are already displayed at that point, only their values change.
    7b99880676109f26635c773b2524a272.png

    As you can see the ModelIndex is also valid. If I call repaint before scrolling, it works, but is it safe to do so? Are there better ways to do it?



  • @Herman-Nordberg
    This is purely a guess, may make no difference, but worth a try?

    You seem to be using setRowCount() to increase/decrease the number of rows. (Following talks about removing rows; applies just as much to inserting rows.) Normally we call removeRows(), and through that beginRemoveRows() and importantly the rowsAboutToBeRemoved() signal. I believe you will find views use that:

    Note: This function emits the rowsAboutToBeRemoved() signal which connected views (or proxies) must handle before the data is removed. Otherwise, the views may end up in an invalid state.

    Does it make any difference to your view behaviour if you (at least temporarily) go via removeRows(), even if just to test?



  • I have just tried it, but the behaviour is still the same.

    After adding first row
    1dacd7bdee96c8520b84392cf6dfa86e.png
    After adding more rows, the rows are diplayed, but it doesn't scroll
    da8d5ee1b42cda5fe2d6732058f3bdd4.png
    After adding another order the row cout stays the same, and it scrolls
    bfe296ce72f2fd9681a84cb03fcd59f0.png


  • Lifetime Qt Champion

    Hi,

    Did you check that the index returned by findClosestRow is indeed valid ?



  • @SGaist said in Scroll QTableView as soon as model changes:

    Hi,

    Did you check that the index returned by findClosestRow is indeed valid ?

    I have added a check now, yes it's valid.


  • Lifetime Qt Champion

    And is it the index you are expecting ?



  • Yes, the model at that point has 100 rows and the midpoint is row 50, which is also the row in the ModelIndex.


  • Lifetime Qt Champion

    For the sake of testing, can you use a queued connection ?



  • The same thing happens with a queued connection.


  • Lifetime Qt Champion

    Which version of Qt are you running ?


Log in to reply