使用QT做HMI开发,因为GPU或者CPU的资源有限,为了得到更流畅的交互效果,局部刷新的方法是大家都一直寻找的解决方案,限制部分的刷新帧率,把资源更多的留给实时性要求高的。
Qt5以后的版本,都推荐使用GPU去渲染,提高渲染的效果,即使用scene graph这个机制去渲染。 使用Qt的Scene Graph来开发应用,要点是批量渲染。这是由OpenGL的特性决定的,因为通过OpenGL,将以往CPU串行的部分并行化,从而大大提升渲染效率,再加上OpenGL本质上是一个巨大的状态机,在进行批量渲染的时候,可以有效地减少OpenGL状态切换所带来的性能开销,同时OpenGL预留的一些状态,需要开发者有基本的认知,由于OpenGL是一个开放的标准,因此考虑到兼容性,其采用了C/S架构。C端即CPU部分,S端对应GPU。在顶点和纹理数据从C端传入S端之前,会在C端形成一个缓冲区(一说缓存),我们常说的VBO、FBO和PBO就是这一类缓冲区。正确地设置缓冲区的数量和大小,可以为应用程序的性能提升带来很大的帮助。但是它采用的是整屏刷新的策略,这时候就很让人头疼了,背景百年不变,又是这么大一张图,还每一帧都去刷新,这个效率的话就可想而知。所以一直也都在找相关的接口,能否达到想要的目的。
后来,发现QQuickItem有一个Flag的属性。如下:
flags QQuickItem::Flags
This enum type is used to specify various item properties.
Constant Value Description
QQuickItem::ItemClipsChildrenToShape 0x01 Indicates this item should visually clip its children so that they are rendered only within the boundaries of this item.
QQuickItem::ItemAcceptsInputMethod 0x02 Indicates the item supports text input methods.
QQuickItem::ItemIsFocusScope 0x04 Indicates the item is a focus scope. See Keyboard Focus in Qt Quick for more information.
QQuickItem::ItemHasContents 0x08 Indicates the item has visual content and should be rendered by the scene graph.
QQuickItem::ItemAcceptsDrops 0x10 Indicates the item accepts drag and drop events.
void QQuickItem::setFlag(Flag flag, bool enabled = true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disabled.
These provide various hints for the item; for example, the ItemClipsChildrenToShape flag indicates that all children of this item should be clipped to fit within the item area.
于是写了测试代码:
#include
#include
#include
#include
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView myview;
myview.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickItem* item = myview.rootObject();
QQuickItem* testItem = item->findChild("txt");
testItem->setFlag(QQuickItem::ItemHasContents,false);
myview.show();
return app.exec();
}
QML文件:
import QtQuick 2.5
Item {
width: 640
height: 480
Text {
id: txt
objectName: "txt"
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
我们可以看到神马都没了,虽然不去渲染了,但是并没有在buffer区cache住这段图像。但是这个东西和设置这个item的visible有啥区别呢?有必要去重复这个东西嘛?然后我进行了各种尝试,最后发现一个使用的用处,如下:
将上面的QML修改一下,如下:
import QtQuick 2.5
Item {
width: 640
height: 480
Text {
id: txt
objectName: "txt"
text: qsTr("Hello World")
anchors.centerIn: parent
Rectangle{
id: testRect
objectName: "testRect"
width: 20
height: 20
color: "red"
}
}
}
这个时候的测试结果会是啥呢?是否是和设置txt控件的visible属性一样呢?会整个界面都是空白吗?
测试结果如下:
结果只有txt控件没有显示,而它的子控件还是显示的。这点的用处可能就在某些情况下,可以设置单单设置某个节点不显示。
但是Qt提供这个flag真的是出于这个目的吗?后来在帮助文档上面找到了一些线索。
我在关于QQuickItem这边的帮助文档没有找到相关的描述,于是我去找QGraphicsItem 是否有相关的属性,从而会有说明呢?
结果功夫不负有心人,真的被我找到了,QGraphicsItem果然也有和QQuickItem相对应的属性,描述如下:
QGraphicsItem::ItemHasNoContents 0x400 The item does not paint anything (i.e., calling paint() on the item has no effect). You should set this flag on items that do not need to be painted to ensure that Graphics View avoids unnecessary painting preparations. This flag was introduced in Qt 4.6.
至于我为什么会去查找QGraphicsItem,是由于QT的scene graph渲染引擎和graphics view的渲染引擎除了底层的渲染的区别较大,但是上层提供的接口还是有很多类似之处,而且graphics view的渲染引擎是较为成熟了,所以相关的资料也会较为齐全。
总结:这个flag 的属性并没有预期的那样得到我想要的结果,没有达到局部渲染的效果,但是还是有收获的,了解了Flag QQuickItem::ItemHasContents 属性,而且也为接下来寻找局部渲染找到了一条思路,可去参考 graphics view 这边是否有方法解决,scene graph 这边是否会有对应的方法呢?
这篇文章没有解决问题,所以也只就是抛砖引玉了,大家如果有找到方法欢迎不吝赐教,后面我找到方法或者有其他的尝试我会继续加载照片文章~~