高效地更新QTableView

时间:2010-09-22 14:10:09

标签: c++ model-view-controller user-interface qt performance

我正在使用带有QItemDelegate子类的QTableView来控制tableview单元格的外观。

每个单元格显示外部连接设备的名称和状态,并且可以同时连接多达100个设备。

每个设备的名称和类型基本上是静态的,很少更新(可能每小时一次),但每个单元需要显示设备输入的实时值,我目前每50毫秒轮询一次。此值显示为由TableView提供给Delegate :: paint()方法的画家绘制的基本条形图。

每秒更新我的模型20次的问题是每次重绘整个表,这是非常低效的。将绘制方法限制为仅绘制条形图表明,大部分CPU时间专用于在每个单元格而不是图形上绘制名称,状态和关联图像。

我需要找到一种方法来定期更新每个单元格的图形,而无需重新绘制单元格,但我无法弄清楚如何操作。

实现这一目标的最有效方法是什么?

编辑:附加到帮助的图片。

Image代表QTableView中的10个传感器。数字,名称和状态几乎是静态的,几乎从不更新。 “传感器值”文本旁边的条形图每50ms更新一次。我只想绘制这个条,而不是文本,状态和单元格背景。状态指示灯和背景是复杂的图像,因此比简单地绘制和填充矩形需要更多的CPU时间。

alt text

3 个答案:

答案 0 :(得分:6)

由于您的QTableView继承了QWidget,您可以在其上调用以下内容:

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

当setUpdatesEnabled为false时,对它的任何paint()或update()调用都不起作用。所以,您可以阻止它更新,更改所有数据,然后重新启用它,可能手动调用paint()或update(),我不确定这部分。

以下是setUpdatesEnabled方法的文档。

QWidget updatesEnabled

希望这有帮助。

用户评论后编辑:

您可以通过在执行原始paint()或update()之前测试标志,为QItemDelegate子类实现自己的setUpdatesEnabled(bool)(因为它不继承QWidget而没有继承QWidget)。 之后,您可以为QTableView的每个单元格(或行或列)指定是否必须更新或重新绘制它们。

通过这样做,您可以阻止其他单元格(委托)重新绘制,除非您更改手动创建的setUpdatesEnabled标记,但保留包含图形的单元格的更新。

我必须说我从来没有测试过这个或类似的东西,所以我希望它能按照我认为的方式运行。

祝你好运

从用户编辑后编辑:

按照我之前的评论,不是为每个单元格设置一个标记(我认为你的图形在一个单独的单元格中),你可以为每个委托设置一个标记,只绘制你的图形或整个图像。

希望这有帮助,

修改

我偶然发现了Qt 4.7中的一个新功能(我不知道你是否可以使用它,但它可以解决你的一些问题。) 该功能是QStaticText。它是一个允许您缓存文本(字体和效果)并更快地绘制它们的类。请参阅链接here

希望它能解决你的问题。

答案 1 :(得分:2)

我很少建议这条道路而不是委托,但在您的情况下,它似乎值得。我会考虑制作自己的视图,它足够了解仅更新需要更新的屏幕部分。像这样的视图小部件显然比通常的情况更具特殊性,但如果你真的需要效率,那么这是一种方法。

如果需要小幅提升效率,需要考虑的其他事项是确保只标记实际更改的更改行(如果传感器值不经常更改,并且仅经常轮询)或考虑添加它之间没有实际重绘的滞后值(如果传感器值没有足够快地改变以否定这一点)。

答案 2 :(得分:1)

将背景图像(单元格背景图像,状态和名称)作为QPixmap缓存到模型中。仅在状态或名称更改时重绘该pixmap。在常见情况下,您只需要绘制缓存的QPixmap和传感器值。

修改

将fullRepaintNeeded标志添加到数据类。更改状态或名称时,fullRepaintNeeded设置为true。

当委托绘制项目时,委托首先检查项目的fullRepaintNeeded标志。如果fullRepaintNeeded为true,则创建一个新的QPixmap,并将所有内容绘制到最终绘制到tableview的QPixmap。然后使用模型的setData-function将QPixmap缓存到模型(对于您的数据类)(但不调用dataChanged)。 fullRepaintNeeded现在设置为false。

但是如果委托的绘图函数中的fullRepaintNeeded为false,则会从模型中询问先前缓存的QPixmap,并将其绘制到tableview中,并在其上绘制最终的传感器值。