当前位置: 首页 > article >正文

[旧日谈]关于Qt的刷新事件频率,以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。

[旧日谈]关于Qt的刷新事件频率,以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。

最近在开发的时候,发现一个依赖事件来刷新渲染的控件会导致程序很容易异常和崩溃。

当程序在运行的时候,其实软件本身的负载并不高,所以在Demo下运行一切良好(良好吗?),但是时装到实际项目下,就发现程序异常崩溃。

后面经过几轮排查,我们发现由这个控件造成的,因为控件的刷新频率太高了。

先来说说这个控件。这个控件的操作实际上依赖了Qt的moveEvent,当鼠标按下之后,然后鼠标移动会触发moveEvent,则这个控件会跟随鼠标移动。这个控件在移动了之后,一下子数据就多到把整个数据流顶爆了。

请添加图片描述

我一开始并没有想过这个问题,因为我想的是我这边渲染没问题,框架上的事情按理说就不用我关心了。但是在我的测试和开发中,我发现事情远没有这么简单。

函数计时

为什么要提到函数计时,因为这里控件的操作我需要做一个计时操作,来检测到底是哪里耗时过多。

我这里的界面并不是只管自己发布数据,而是连着很多个控件一起刷新,这就导致了一个问题。我发现其实我在其他控件上进行移动和检查花费的事件更多更频繁。

至于我是如何发现的,我这里分享一个RAII型的计时器,用于计算一个函数从开始到结束的总时间


class TimeCounter {
public:
	TimeCounter(const QString& FunctionName) {
		if (PublicVar::ins().blnCountingTimeMode) {
			qDebug() << "Function Begin at : " << FunctionName;
			this->functionName = FunctionName;
			timer.start();
		}
	};
	~TimeCounter() {
		if (PublicVar::ins().blnCountingTimeMode) {
			qDebug() << " Function " << this->functionName << "time used with :" << timer.elapsed() << "milliseconds.";
		}
	}
private:
	QElapsedTimer timer;
	QString functionName;
};

使用范例:

void function(){
    TimeCounter timer(__FUNCTION__);
    QThread::msleep(10);
}

刷新率?

既然我这个函数是依赖moveEvent来刷新界面的,也就是说我这个函数调用的频率是严格与moveEvent的刷新频率同步的。但是moveEvent的刷新率是多少?这个问题我完全没有考虑过。

显然,这个moveEvent的刷新率应该是大于60的,因为我在60hz的屏幕上完全感受不到卡顿。但那具体是多高?

moveEvent的刷新频率与鼠标的刷新率有关

是的,你没看错,moveEvent的刷新频率与鼠标的刷新率有关。在这里我可以做一个函数,来对moveEvent的刷新率进行一个简单的测算。

QtWidgetsApplication3.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication3.h"
#include "qtimer.h"
class QtWidgetsApplication3 : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication3(QWidget *parent = nullptr);
    ~QtWidgetsApplication3();
    QTimer* timer;
protected:
	void moveEvent(QMoveEvent* event) override;
private:
    size_t m_moveEventCount = 0;
    void onTimerTimeout();
    Ui::QtWidgetsApplication3Class ui;
};

QtWidgetsApplication3.cpp


#include "QtWidgetsApplication3.h"

QtWidgetsApplication3::QtWidgetsApplication3(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    this->timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &QtWidgetsApplication3::onTimerTimeout);
    timer->start(1000); // 每1000毫秒(1秒)触发一次
}

QtWidgetsApplication3::~QtWidgetsApplication3()
{}
#include "qdebug.h"
void QtWidgetsApplication3::moveEvent(QMoveEvent * event)
{
    QMainWindow::moveEvent(event); // 确保调用基类的 moveEvent 函数

    // 递增计数器
    m_moveEventCount++;
}

void QtWidgetsApplication3::onTimerTimeout()
{
    // 打印 moveEvent 每秒触发的次数
    qDebug() << "moveEvent count per second:" << m_moveEventCount;

    // 重置计数器
    m_moveEventCount = 0;
}


测试结果:

1.鼠标回报率125hz

刷新率大概在126times/s

2.鼠标回报率250hz

刷新率大概在250times/s

3.鼠标回报率500hz

刷新率大概在400tick/s

4. 鼠标回报率1000hz

刷新率大概在400tick/s,最高可以到700tick/s

这个负载完全把我吓了一跳,因为我这里实际上根本用不到这么高的刷新率,对于一般的产品来说,30-60hz 的刷新率已经可以让整个产品看起来堪称流畅了,特别是这种性能关键而且和很多控件连带的地方。

结论

如果控件是依赖moveEvent来刷新界面的,那么这个控件的刷新频率就会依赖鼠标的刷新频率。如果那个地方的控件移动对后台进行的操作比较耗时,数据量比较大的时候,或者这个控件连带着很多空间一起操作的时候,可能会需要考虑到鼠标分辨率的影响。


http://www.kler.cn/news/354696.html

相关文章:

  • 关于FFmpeg【使用方法、常见问题、解决方案等】
  • jmeter 对 dubbo 接口测试是怎么实现的?有哪几个步骤
  • 我谈结构自相似性SSIM——实质度量的是什么?
  • JavaScript 小技巧和诀窍:助你写出更简洁高效的代码
  • Scale Decoupled Distillation 论文中SPP发生了什么
  • 一款AutoXJS现代化美观的日志模块AxpLogger
  • k8s-配置网络策略 NetworkPolicy
  • docker/docker-compose里面Command和entrypoint的关系
  • 股票Tick数据如何获取做量化交易
  • springboot如何接入阿里云短信
  • Vue 3 中的状态管理:深入探讨 Vuex 和 Pinia 的比较与最佳实践
  • 初识git · 有关模型
  • 【C语言】数据类型
  • 实用篇:如何让Win11右键默认显示更多呢
  • STM32 独立看门狗和窗口看门狗区别
  • Python进阶知识
  • 智能平台或系统中的归因、根因分析案例集锦
  • 使用python实现图书管理系统
  • Unity动画系统
  • 外包干了3周,技术退步太明显了。。。。。