qt中如何同步应用程序和显示器的刷新率?

How to sync the refresh rate of the application and the monitor in qt?

我写了一个小的 c++/qt 应用程序,它在实际光标位置上绘制了一个自制的光标。为了最大限度地减少实际光标位置和绘制光标位置偏移的延迟,我的 QWidget 会尽可能快地更新自身。

部分构造函数:

QTimer *Timer = new QTimer(this);
connect(Timer, SIGNAL(timeout()), this, SLOT(update()));
Timer->start();

绘画事件:

void Widget::paintEvent(QPaintEvent* event) {
    auto t1 = std::chrono::high_resolution_clock::now();
    std::cerr << "Duration Cycle: " << std::chrono::duration_cast<std::chrono::milliseconds>(t1 - LastT1).count() << std::endl;
    LastT1 = t1;

    // Draw Cursor
    POINT LpPoint;
    GetCursorPos(&LpPoint);
    QPoint CursorPos(LpPoint.x, LpPoint.y);
    CursorPos = mapFromGlobal(CursorPos);
    QPainter Painter(this);
    Painter.drawEllipse(CursorPos, 20, 20);

    std::cerr << "Duration Paintevent: " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - t1).count() << std::endl;

}

现在我有两个问题:

  1. 绘画事件的持续时间约为一毫秒。一个周期的持续时间在 10 到 15 毫秒之间。与此同时,Qt 做了什么?更多信息: update() 和 repaint() 之间没有区别,如果我将计时器设置为固定整数,则没有区别,例如Timer->start(2);。降低显示器的分辨率会缩短循环持续时间。

  2. 我使用的是 60 Hz 显示器,所以我真的不需要更高的刷新率,如果我能够将更新与显示器的刷新率同步的话。那可能吗?我对此做了一些研究,但我发现没有什么真正有用的。

我希望我没有遗漏一些基本的东西。如果有任何意见,我将不胜感激。

The duration of one cycle is between 10 and 15 milliseconds. What does Qt do in the meantime?

很可能它在休眠,and/or 还倾向于 Qt 事件循环负责的其他业务。请注意,在 Windows 上,进程的计时器默认为具有 10 毫秒粒度的低分辨率机制(因此,如果您希望 Windows 进程能够一次休眠少于 10 毫秒,您我想在程序开始时调用 timeBeginPeriod(1))。

sync the update with the refresh rate of the monitor. Is that possible?

原则上这是可能的,但 Qt 的 QWidget API 并不是真正为该级别的控制而设计的(QWidgets 不是 gaming/multimedia API 而更多的是 classic 桌面应用程序 GUI,因此它更侧重于获取正确的内容,而不是保证最紧凑的时间)。如果你可以切换到使用 QML instead of the older QWidgets API, QML has for syncing-to-monitor-refresh. Another possibility would be to draw your graphics via OpenGL, inside a QOpenGLWindow; QOpenGLWindow class 也有一定的同步刷新率的能力(请参阅其 frameSwapped() 信号的文档)。

顺便说一下,将输出写入 stdout (a.k.a. std::cout) and/or stderr (a.k.a std::cerr ) 可能会非常慢,并且通过在您发布的程序中这样做,您可能会大大偏离您的计时测量。更好的方法是收集计时数据,但只是将其存储在某种数据结构中,直到完成测量,然后仅在最后(例如,当您退出程序时)打印出测量值,以便打印值不影响值的准确性。