C++ 高效地高速更新QTableView

C++ 高效地高速更新QTableView,c++,model-view-controller,user-interface,qt,performance,C++,Model View Controller,User Interface,Qt,Performance,我使用QItemDelegate子类的QTableView来控制tableview单元格的外观 每个单元格显示外部连接设备的名称和状态,一次可以连接多达100个设备 每个设备的名称和类型基本上是静态的,很少更新(可能每小时更新一次),但每个单元格需要显示设备输入的实时值,我目前每50毫秒轮询一次。该值显示为由画师绘制的基本条形图,画师通过TableView提供给Delegate::paint()方法 每秒更新我的模型20次的问题是每次都会重新绘制整个表,这是非常低效的。将绘制方法限制为仅绘制条形

我使用QItemDelegate子类的QTableView来控制tableview单元格的外观

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

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

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

我需要找到一种方法来定期更新每个单元格的图表,而不必重新绘制单元格,但我不知道该怎么做

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

编辑:图像附加到帮助。

图为QTableView中的10个传感器。号码、姓名和状态实际上是静态的,几乎从不更新。“传感器值”文本旁边的条形图每50毫秒更新一次。我只想画这个条,而不是文本、状态和单元格背景。状态灯和背景是复杂的图像,因此比简单地绘制和填充矩形要花费更多的CPU时间


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

setUpdatesEnabled(false);
changeAllYourData();
setUpdatesEnabled(true);
当setUpdatesEnabled为false时,对其进行的任何paint()或update()调用均无效。所以,您可以停止它的更新,更改所有数据,然后重新启用它,可能是通过手动对其调用paint()或update(),我不确定这部分

下面是setUpdatesEnabled方法的文档

希望这有帮助

用户评论后编辑:

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

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

我必须说我从来没有测试过这个或类似的东西,所以我希望它能像我想的那样工作

祝你好运

从用户处编辑后编辑:

在我前面的评论之后,您可以为每个代理设置一个标志,以仅绘制图形或整个图像,而不是为每个单元格设置标志(我认为您的图形位于单独的单元格中)

希望这有帮助

编辑:

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


希望它能解决您的问题。

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

编辑:

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

当代理绘制项目时,代理首先检查项目的FullRepaitRequired标志。如果FullRepaitRequired为true,则创建一个新的QPixmap,并将所有内容绘制到最终绘制到tableview的QPixmap。然后使用模型的setData函数将QPixmap缓存到模型(这对您的数据类来说意味着)中(但不调用dataChanged)。FullRepaitRequired现在设置为false


但是,如果代理的paint函数中FullRepaitRequired为false,则会从模型中请求一个先前缓存的QPixmap,并将其绘制到tableview,最后的传感器值将绘制在该值之上。

我很少建议使用此路径而不是代理,但在您的情况下,它似乎是值得的。我会考虑自己的观点,只需要更新需要更新的屏幕的部分即可。像这样的视图小部件显然比通常情况下更具特殊用途,但如果您真的需要效率,这是一种方法


<> P>其他需要考虑的事项,如果你需要一个小的效率提高,确保你只标记改变的行,实际上改变(如果传感器值不经常改变,而且只轮询经常)或考虑添加一个迟滞值,在其间它实际上没有重新绘制。(如果传感器值的变化速度不够快,无法消除此影响).

状态是否需要与其他所有部件位于同一个窗口小部件中?我的第一个想法是将同一型号的ListView粘贴在它旁边。是的,不幸的是,它是这样。每个设备都有许多参数需要位于图表旁边。我确实想过要有两个视图,可能是重叠的,但这似乎是一种非常混乱的实现方式我已经这样做了,所以我每秒只更新模型20次,而不是更新20个设备,但这并不能解决这个问题,除了图形,我还绘制了背景图像、名称字符串、状态字符串和其他各种displays本身的更新速度要低得多。是吗