qt的绘图效率问题

_png 2018-02-26 04:50:34
目前开发了一个仪表程序,从网口读到数据后刷新仪表界面,然后仪表类会调用paintEvent方法进行窗口重绘。
问题是:当刷新速度达到ms级或者长时间运行时程序会变得非常卡顿,查看程序Cpu占用率达到35%
因为是实时数据,所以网口过来的数据基本都得显示出来,所以无法修改刷新频率,请教大家有没有成熟的解决办法。
...全文
4393 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
licoba 2018-08-21
  • 打赏
  • 举报
回复
引用 30 楼 amwha 的回复:
是不是用drawline这个函数来画点?这个函数好像比较耗时,我也卡在这个问题上了。
请问你有找到什么解决办法吗
licoba 2018-08-21
  • 打赏
  • 举报
回复
引用 4 楼 four_p 的回复:
[quote=引用 2 楼 jianwen0529 的回复:] [quote=引用 1 楼 jianwen0529 的回复:] 肯定能修改刷新频率:50毫秒跟5毫米肉眼看起来有何不同。 你非要进行限制刷新频率,那只能在绘图的数计算量着手了! 1:把不经常变动的部分先求解封装在绘制列表中(OpenGL下的概念,QT就不清楚了) 当绘图直接调用这些绘制列表(已经计算好)进行绘制,剩下的经常变动的就实时交由接口计算绘制 2:你自己定义模型,把数据先简化,减少CPU准备绘制数据的计算时间 3:多线程
4:GPU并行求解[/quote] 实际效果是界面刷新频率越高,卡顿现象出现的越快,相反设置秒及刷新,但长时间运行后依然会出现这种卡顿。 1、因为是仪表程序,其实计算并不复杂,就是简单的计算然后交由QT绘制图形界面,当有数据更新时调用update(),此时会触发QT的PaintEvent方法对窗口进行重绘,这个时候有两个现象,一个就是程序cpu占用率高,另一个就是程序变得卡顿 2、数据分为仪表数据和文本数据,仪表数据用于更新仪表界面,文本数据直接用于更新Label,程序基本没有任何复杂的计算,就是仪表界面绘制拖慢了程序。 3、如2,绘制操作在PaintEvent函数内完成,此函数为系统函数。 4、试过双缓存,将整个仪表先存储于图片缓存下来,再将图片一次性更新到界面,但是图像的质量大打折扣,长时间运行依然会有卡顿[/quote] 我碰到的问题跟你说的很相似!! 请问你有没有找到一些解决办法?
amwha 2018-07-26
  • 打赏
  • 举报
回复
是不是用drawline这个函数来画点?这个函数好像比较耗时,我也卡在这个问题上了。
_png 2018-03-01
  • 打赏
  • 举报
回复
引用 26 楼 zhao4zhong1 的回复:
检查是否GDI对象资源泄漏的办法之一: 在任务管理器 进程 详细信息 查看 选择列 里面选择:GDI对象 让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有GDI对象的资源泄漏!
感谢您的回答
赵4老师 2018-02-28
  • 打赏
  • 举报
回复
有GDI对象泄露吗?
有点贪玩 2018-02-28
  • 打赏
  • 举报
回复
检查一下是否在paintEvent()中调用了update()方法,这样会造成大量的内存泄漏。
幻夢之葉 2018-02-28
  • 打赏
  • 举报
回复
前期不卡后期卡,感觉跟绘图频率没关系了!是不是绘制数据叠加了?
_png 2018-02-28
  • 打赏
  • 举报
回复
引用 17 楼 zhao4zhong1 的回复:
不听老人言,吃亏在眼前。 BTW:你是生成的Release版吗?
不是没有听,出现这个问题,我第一时间就检查了有没有内存泄漏,绘制的逻辑如16楼所示,仅仅涉及到Painter的操作。我把数据刷新的逻辑屏蔽掉就没问题,数据刷新里核心逻辑就是绘制仪表界面,更新其数据,Debug版本和Release版本都尝试过,都有这个问题。
赵4老师 2018-02-28
  • 打赏
  • 举报
回复
检查是否GDI对象资源泄漏的办法之一: 在任务管理器 进程 详细信息 查看 选择列 里面选择:GDI对象 让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有GDI对象的资源泄漏!
_png 2018-02-28
  • 打赏
  • 举报
回复
引用 22 楼 zhao4zhong1 的回复:
有GDI对象泄露吗?
仪表之一源码如下,界面总共9个不同的仪表,基本绘制流程一致,当数据更新时(每1s)调用updateValue方法刷新仪表数据

Battery::Battery(QWidget *parent) : QWidget(parent),
    m_value(0)
{
    tempPix= new QPixmap(size());
    QPainter *painter=new QPainter;
    painter->begin(tempPix);
    painter->setRenderHint(QPainter::Antialiasing,true);
    drawBackground(painter);
    painter->end();
    setAutoFillBackground(true);
    QPalette pale(this->palette());
    pale.setBrush(QPalette::Background,QBrush(*tempPix));
    setPalette(pale);
}

Battery::~Battery()
{

}

void Battery::paintEvent(QPaintEvent *){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);
    drawNumberic(&painter);
}

void Battery::drawBackground(QPainter* painter){
    painter->save();
    QPen pen(Qt::white);
    pen.setWidth(1);
    painter->setPen(pen);
    painter->drawRect(0,0,20,10);
    pen.setWidth(3);
    painter->drawLine(21,3,21,7);
    painter->restore();
}

void Battery::drawNumberic(QPainter* painter){
    painter->save();
    if(m_value>=0.5){
        painter->setPen(QColor("#34EF8D"));
        painter->setBrush(QColor("#34EF8D"));
    }else if(m_value>=0.3){
        painter->setPen(QColor("#EA9646"));
        painter->setBrush(QColor("#EA9646"));
    }else{
        painter->setPen(QColor("#FF0005"));
        painter->setBrush(QColor("#FF0005"));
    }
    painter->drawRect(2,2,16*m_value,6);
    painter->restore();
}
void Battery::updateValue(double value){
    m_value=value;
    update();
}
_png 2018-02-28
  • 打赏
  • 举报
回复
引用 21 楼 qq981091829 的回复:
检查一下是否在paintEvent()中调用了update()方法,这样会造成大量的内存泄漏。
rePaint方法是强制刷新一次,update()是累计按需刷新,rePaint嵌套会造成死循环,update会采取自动优化策略。没有在paintEvent中嵌套update()
_png 2018-02-28
  • 打赏
  • 举报
回复
引用 20 楼 jianwen0529 的回复:
前期不卡后期卡,感觉跟绘图频率没关系了!是不是绘制数据叠加了?
绘图区域都是先擦除再绘制,绘制默认采取双缓冲机制
狐狸小十 2018-02-27
  • 打赏
  • 举报
回复
引用 7 楼 four_p 的回复:
[quote=引用 6 楼 qq_31709097 的回复:] 画个仪表,即使用gdi也用不了多长时间,可以把固定的内容先绘制到一个背景里,用的时候再一次性画上去,如果有叠盖关系,就加个图层 你的问题应该是流程没设计好,一定要优先处理系统消息,在空闲期渲染,消息阻塞了,就越来越卡了
你说的把固定内容绘制到一个固定的背景里是一个很好的思路! 因为是自定义仪表,所以实现的时候我就是用的qt自带的painter绘制的,封装成widget。界面上共有9个仪表,数据是每秒刷新一次,也就是每秒钟画9个仪表。qt窗口的绘制必须在PaintEvent方法中执行,而在这个方法中基本没有复杂的计算,因此我判断是绘制图形界面太消耗cpu资源,因为painter图形绘制是依赖的cpu。[/quote] 先画到背景里,只是一个小优化,不是决定性的,一个个画也慢不到哪去 如果是win32,是这样的思路 while() { if(系统消息) { //处理系统消息 }else { if(新数据) Draw(); }} QT我没用过,MFC里有自定义的OnKickIdle,就是负责在空闲期渲染,QT肯定也有 然后在响应函数里绘制
赵4老师 2018-02-27
  • 打赏
  • 举报
回复
检查是否资源泄漏的办法之一: 在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象 让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资源泄漏! 搜“GDI泄露检测”
_png 2018-02-27
  • 打赏
  • 举报
回复
引用 6 楼 qq_31709097 的回复:
画个仪表,即使用gdi也用不了多长时间,可以把固定的内容先绘制到一个背景里,用的时候再一次性画上去,如果有叠盖关系,就加个图层 你的问题应该是流程没设计好,一定要优先处理系统消息,在空闲期渲染,消息阻塞了,就越来越卡了
你说的把固定内容绘制到一个固定的背景里是一个很好的思路! 因为是自定义仪表,所以实现的时候我就是用的qt自带的painter绘制的,封装成widget。界面上共有9个仪表,数据是每秒刷新一次,也就是每秒钟画9个仪表。qt窗口的绘制必须在PaintEvent方法中执行,而在这个方法中基本没有复杂的计算,因此我判断是绘制图形界面太消耗cpu资源,因为painter图形绘制是依赖的cpu。
狐狸小十 2018-02-27
  • 打赏
  • 举报
回复
画个仪表,即使用gdi也用不了多长时间,可以把固定的内容先绘制到一个背景里,用的时候再一次性画上去,如果有叠盖关系,就加个图层 你的问题应该是流程没设计好,一定要优先处理系统消息,在空闲期渲染,消息阻塞了,就越来越卡了
_png 2018-02-27
  • 打赏
  • 举报
回复
引用 3 楼 goldenhawking 的回复:
仪表程序可以参考 QGraphicsView架构。这个架构会自动判断绘制的区域。 有兴趣看看 http://blog.csdn.net/goldenhawking/article/details/78817426
因为qt的绘制操作都在PaintEvent中完成,所以每次绘制的流程就是先擦除再绘制,减小绘制区域确实能够优化程序,仪表盘程序实时刷新的也就是指针的位置,但就目前我观察到的,当刷新频率过快时减少绘制区域并不能完全避免这种卡顿的现象。
_png 2018-02-27
  • 打赏
  • 举报
回复
引用 2 楼 jianwen0529 的回复:
[quote=引用 1 楼 jianwen0529 的回复:] 肯定能修改刷新频率:50毫秒跟5毫米肉眼看起来有何不同。 你非要进行限制刷新频率,那只能在绘图的数计算量着手了! 1:把不经常变动的部分先求解封装在绘制列表中(OpenGL下的概念,QT就不清楚了) 当绘图直接调用这些绘制列表(已经计算好)进行绘制,剩下的经常变动的就实时交由接口计算绘制 2:你自己定义模型,把数据先简化,减少CPU准备绘制数据的计算时间 3:多线程
4:GPU并行求解[/quote] 实际效果是界面刷新频率越高,卡顿现象出现的越快,相反设置秒及刷新,但长时间运行后依然会出现这种卡顿。 1、因为是仪表程序,其实计算并不复杂,就是简单的计算然后交由QT绘制图形界面,当有数据更新时调用update(),此时会触发QT的PaintEvent方法对窗口进行重绘,这个时候有两个现象,一个就是程序cpu占用率高,另一个就是程序变得卡顿 2、数据分为仪表数据和文本数据,仪表数据用于更新仪表界面,文本数据直接用于更新Label,程序基本没有任何复杂的计算,就是仪表界面绘制拖慢了程序。 3、如2,绘制操作在PaintEvent函数内完成,此函数为系统函数。 4、试过双缓存,将整个仪表先存储于图片缓存下来,再将图片一次性更新到界面,但是图像的质量大打折扣,长时间运行依然会有卡顿
cattpon 2018-02-27
  • 打赏
  • 举报
回复
引用 16 楼 four_p 的回复:
PaintEvent绘制逻辑如图所示 https://img-bbs.csdn.net/upload/201802/27/1519717000_891049.png 在 drawBackground(painter); drawScale(painter); drawScaleNum(painter); drawNumberic(painter); 方法内部,仅仅调用QPainter的setPen(),setBrush和drawLine()等绘图操作,如图所示 并不涉及到内存泄漏的问题
感谢细心回复~
加载更多回复(11)

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧