2010-09-22 180 views
7

我使用QTableView和QItemDelegate的子类来控制tableview单元格的外观。高效更新QTableView高速更新

每个单元格显示外部连接设备的名称和状态,一次最多可连接100个设备。

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

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

我需要找到的方法是定期更新每个单元格的图形而不重绘单元格,但我无法弄清楚如何去做。

达到此目的的最有效方法是什么?

编辑:图像附加帮助。

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

alt text

+0

该状态是否需要与其他所有内容位于相同的小部件中?我的第一个想法是在同一个模型旁边粘贴一个ListView。 – 2010-09-22 14:14:50

+0

是的,不幸的是它。每个设备都有一些参数需要放在图的旁边。我确实想过有两种观点,可能是重叠的,但它看起来像是一种非常混乱的方式来实现我想要的东西,并且使得改变模型,编辑等变得更加困难。 – Dani 2010-09-22 14:48:07

回答

6

因为你QTableView中继承了QWidget,你可以调用它的下面:

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

当setUpdatesEnabled是假的,任何油漆()或update()调用它没有任何效果。所以,你可以阻止它更新,改变你的所有数据,然后重新启用它,可能通过手动调用paint()或update()来实现,我不确定这部分。

以下是setUpdatesEnabled方法的文档。

QWidget updatesEnabled

希望这会有所帮助。从用户的评论后

编辑:

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

通过这样做,除非您更改手动创建的setUpdatesEnabled标志,而是在包含图形的单元格上保留更新,否则可以阻止其他单元(委托)进行重新绘制。

我必须说我从来没有测试过这个或其他类似的东西,所以我希望它能像我认为的那样工作。从用户编辑后

最好的运气

编辑:

按照我以前的评论,而不是设置标志,每一个细胞(我想你的图是在一个单独的单元格),你可以为每个代表设置一个标志,只绘制您的图形或整个图像。

希望这有助于

编辑:

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

希望它能解决您的问题。

+1

我实际上已经这样做了,所以我只更新模型每秒20次,而不是20×numberOfDevices,但它不能解决问题以及图形,我正在绘制背景图像,名称字符串,状态字符串以及各种其他显示器,这些显示器本身只会以低得多的速率更新。 – Dani 2010-09-22 14:45:58

+0

是你想单独写在单元格中的图表吗? – Live 2010-09-22 14:48:59

+0

不,它包含在其他信息中。我已将图像附加到原始问题以帮助可视化GUI。 – Dani 2010-09-22 15:02:50

1

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

编辑:

添加fullRepaintNeeded标志,以您的数据类。当状态或名称更改时,fullRepaintNeeded设置为true。

委托人在绘制物品时,委托人首先检查物品的fullRepaintNeeded标志。如果fullRepaintNeeded为true,则创建一个新的QPixmap,并将所有内容都绘制到最终绘制到tableview的QPixmap上。然后将QPixmap与模型的setData函数(但不调用dataChanged)缓存到模型(这意味着您的数据类)。 fullRepaintNeeded现在设置为false。

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

+0

太好了,没有想到这一点。 – Live 2010-09-22 16:10:18

+0

这就是我想要做的,但我该如何去做呢?只有一个绘画例程,并且只有一个dataChanged()插槽。理想情况下,我需要两个,但是我使用哪一个QPainter对象作为另一个? 我已经开始使用Live的标志方法实现这一点,我会看看它是如何实现的。 – Dani 2010-09-22 16:20:22

+0

我刚试过这个。绘图程序的工作原理与您所描述的完全相同,结果如下:设置标志时,单元格被清除,然后绘制图形。在更新其他值(或更改选择)时,它只有最多50ms,直到下一个图形更新,然后清除单元格并再次绘制条形图。 – Dani 2010-09-22 16:45:51

2

我很少会提出这条道路,而不是代表,但在您的情况下它可能是值得的。我会考虑制作我自己的视图,这足以让我们更新屏幕上需要更新的部分。像这样的视图小部件显然比通常情况下更具特殊用途,但如果您真的需要效率,那么这是一条可行的路。

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

+0

这是我去过的路线;创造我自己的观点。我已经采取了Roku的建议,并使用QGLWidget来处理渲染,因此我看到数百个设备的CPU使用率为3%,比以前更短的时间间隔刷新。 – Dani 2010-09-28 09:16:42

+0

@Dani晚会有点晚,但这个问题可以从你在这种方法中学到的东西中大大受益。 – UmNyobe 2016-03-08 10:47:43