2

What's the best way to get the list of the currently visible items displayed by a QTreeView? And is it possible to get notifications when it changes?

The data for my model can change asynchronously of the application (data comes from hardware registers). Refreshing that data can be slow, so I want to periodically refresh in a dedicated thread. I don't want to refresh all the items as it would be very inefficient, just the visible ones.

I am aware of this, but in my case the data changes asynchronously so I cannot refresh the items only when setData() is called.

Community
  • 1
  • 1
JPh
  • 536
  • 3
  • 20
  • You don't need to care about refreshing invisible items - the model view will do it when they appear in the view port when you scroll the view, for example. That's the beauty of model/view architecture. – vahancho Jan 13 '17 at 14:07
  • I need to refresh the data of the model, asynchronously of what happens in the view. To do so, I read from hardware registers which is slow - hence the dedicated thread (I cannot just read from the registers when data() is called as this is too slow). Since my model is quite large, I want to only refresh the data for those items that are currently visible. – JPh Jan 16 '17 at 08:58

1 Answers1

0

It might be easier to just ignore the view and focus on the model.

You can model it on a simple refresh-ahead cache: .data() returns the last known value, but also schedules an update. Since the view will call model.data(index)

  • when the index comes into view,
  • every time it changes (with dataChanged() signal) whilst the index is visible

This can form a loop to poll the visible items. And the view will stop calling .data() when the cell is not visible, terminating the loop. You should also take into account that data() can be called outside this loop, so nothing breaks.

Possible sequence

UI

  1. Cell comes into view
  2. View calls model.data(cell, Qt::DisplayRole):
    • add cell to set of scheduled indexes (if not already scheduled)
    • return old or default data
  3. Data updated asynchronously, emit dataChanged()
  4. Either cell is in view, and the view will call model.data() again - loop back to step 2, or the cell isn't visible and the sequence ends here.

Data Thread

  1. Every X ms update all scheduled indexes (clearing the set).

This will fulfill your requirement of continuously/asynchronously polling the visible model items.

Community
  • 1
  • 1
Joseph Ireland
  • 2,465
  • 13
  • 21
  • 1
    This could be a solution if the data was not asynchronous to the UI. My data updates asynchronously from the UI, and I still want to see those changes even if there's no user interaction with the UI, so I cannot rely on UI events to update my Qt model. – JPh Jan 16 '17 at 15:08
  • No, this will poll data that is visible to the UI every 50ms (+ read time), even with no interaction. It won't update the non-visible data, but thats what you asked for. – Joseph Ireland Jan 16 '17 at 16:53
  • edited to make it more clear why this solves your problem – Joseph Ireland Jan 17 '17 at 00:16
  • 1
    Having implemented this, it seems the view still calls my model's data() even when the index is not visible. the view seems to recalculate the height of the row (via QTreeViewPrivate::itemHeight()), regardless of whether it is visible or not. As a result, it calls my model's data() even when the item is not visible. – JPh Jan 17 '17 at 14:49
  • In addition, if the data has not changed at (3), I would not emit dataChanged(), which would stop the loop. If the data subsequently changes (and there's no iteration with the View), there's no mechanism to restart the loop. As a result I still need a polling thread iterating through all items, and still need the list of visible items. – JPh Jan 17 '17 at 14:49
  • you can use setUniformRowHeights so it only checks a single row for height. Also your model can emit dataChanged even if it doesnt change. – Joseph Ireland Jan 17 '17 at 17:58
  • 1
    I wasn't aware of the setUniformRowHeights(). You suggestion works; thank you! – JPh Jan 18 '17 at 17:22