开发者

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 开发者_如何学JAVAthis?

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.

Efficiently updating a QTableView at high speed


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.


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).


Cache the background image (cell background image, status and name) to the model as a QPixmap. Redraw that pixmap only when the status or the name are changed. In the common case you will only need to draw the cached QPixmap and the sensor value on top of that.

Edit:

Add fullRepaintNeeded flag to your data class. When status or name is changed, fullRepaintNeeded is set to true.

When the delegate is painting the item, the delegate first checks the item's fullRepaintNeeded flag. If fullRepaintNeeded is true, then a new QPixmap is created and everything is painted to that QPixmap which is finally painted to the tableview. The QPixmap is then cached to the model (which means to your data class) with model's setData-function (but dataChanged is not called). fullRepaintNeeded is now set to false.

But if fullRepaintNeeded is false in the delegate's paint function, a previously cached QPixmap is asked from the model, drawn to the tableview and the finally sensor value is drawn on top of that.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜