Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently updating a QTableView at high speed

I'm using a QTableView with a subclass of QItemDelegate to control the look and feel of the tableview's cells.

Each cell displays the name and status of a of an externally connected device, and as many as 100 devices may be connected at once.

The name and type of each device is essentially static, updating very rarely (perhaps once an hour), but each cell needs to display a real time value of the device's input, which I currently poll for every 50 milliseconds. This value is displayed as a basic bar graph drawn by the painter provided to the Delegate::paint() method by the TableView.

The problem with updating my model 20 times per second is that the entire table is redrawn each time, which is highly inefficient. Limiting the paint method to only drawing the bar graph shows that the majority of CPU time is dedicated to drawing the name, status and associated image on each cell, rather than the graph.

What I need to find is a way to update the graph for each cell regularly without redrawing the cell, but I can't work out how to do it.

What is the most efficient way of achieving this?

Edit: Image attached to help.

Image represents 10 sensors in a QTableView. The Number, Name and Status are virtually static, almost never updating. The bar graph next to the 'Sensor Value' text updates every 50ms. I only want to paint this bar, rather than the text, status and the cell background. The status lights and background are complex images, so take much more CPU time than simply drawing and filling a rect.

alt text

like image 682
Dani Avatar asked Sep 22 '10 14:09

Dani


2 Answers

since your QTableView inherits QWidget, you can call the following on it:

setUpdatesEnabled(false);
changeAllYourData();
setUpdatesEnabled(true);

When setUpdatesEnabled is false, any paint() or update() call on it has no effect. So, you could stop it from updating, change all your data and then reenable it, possibly by manually calling paint() or update() manually on it, I'm not sure about this part.

Here is the doc for the setUpdatesEnabled method.

QWidget updatesEnabled

Hope this helps.

EDIT after comment from user:

You could implement your own setUpdatesEnabled(bool) for your QItemDelegate subclass (since it does not inherit QWidget and does not have one) by testing a flag before executing your original paint() or update(). After that, you could specify for every cell (or row or column) of your QTableView if they must be updated or repainted.

By doing this, you could stop your other cells (delegates) from repainting, unless you change the setUpdatesEnabled flag you created manually, but keep the updates on your cells containing a graph.

I must say I never tested this or anything like this, so I hope it works the way I think it does.

Best of luck

EDIT after edit from user:

Following my previous comment, instead of setting a flag for every cell (I thought your graph was in a separate cell), you could set a flag for every delegate to paint only your graph or the whole image.

Hope this helps,

EDIT:

I stumbled upon a new feature in Qt 4.7 (I do not know if it's possible for you to use it, but it could solve some of your problems.) The feature is QStaticText. It is a class that allows you to cache text (font and effects) and paint them faster. See the link here.

Hope it could solve your problem.

like image 56
Live Avatar answered Sep 23 '22 06:09

Live


It's rare that I suggest this path rather than delegates, but it appears in your situation it might be worth it. I'd consider making my own view, which is aware enough to only update the portions of the screen that need to be updated. A view widget like this is obviously a bit more special-purpose than would usually be the case, but if you really need the efficiency, it's one way to go.

Other things to consider if you need a small boost in efficiency are making sure you only mark the rows changed that actually change (if the sensor values don't change that often, and are only polled that often) or consider adding a hysteresis value between which it isn't actually redrawn (if the sensor values don't change quickly enough to negate this).

like image 25
Caleb Huitt - cjhuitt Avatar answered Sep 25 '22 06:09

Caleb Huitt - cjhuitt