TimerEvent 在 Windows 和 Mac 上的速度不同

TimerEvent has different speed on Windows and Mac

我的 QT 应用程序依赖于 TimerEvent (startTimer/killTimer) 来为 GUI 组件设置动画。然而,最近我在我的 Mac 笔记本电脑上编译并 运行 我的应用程序(与我开发时使用的 Windows 台式计算机相反),发现现在一切看起来 run/update 速度只有平时的一半。

应用程序没有滞后,只是更新频率不如原来那么频繁。我应该怎么做才能保证所有平台上应用程序的时序一致?

或者,我应该为临时计时器事件使用不同的功能吗?我宁愿不这样做,因为 TimerEvent 将更新周期集成到小部件中非常方便,但如果它们提供一致的计时,我会很感兴趣。

(上下文的基本示例代码):

// Once MyObject is created, counts to 20. 
// The time taken is noticeably different on each platform though.

class MyObject: public QObject {

public:
  MyObject() {
    timerId = startTimer(60);
  }

protected:
  void timerEvent(QTimerEvent* event) {
    qDebug() << (counter++);
    if(counter == 20) {
       killTimer(timerId);
    }
    Object::timerEvent(event);
  }

private:
  int timerId = -1, counter = 0;
}

您可能会遇到准确性方面的问题。 QTimer's accuracy varies on different platforms:

Note that QTimer's accuracy depends on the underlying operating system and hardware. The timerType argument allows you to customize the accuracy of the timer. See Qt::TimerType for information on the different timer types. Most platforms support an accuracy of 20 milliseconds; some provide more. If Qt is unable to deliver the requested number of timer events, it will silently discard some.

您可以尝试将 Qt::PreciseTimer 传递给 startTimer(默认为 Qt::CoarseTimer),但另外我建议检查当前时间戳与某个开始时间或上一个时间戳的时间戳打钩。这将允许您调整处理定时器事件之间不同时间量的方式。这与 how time steps are sometimes handled in games.

没有什么不同

例如:

class MyObject: public QObject {

public:
  MyObject() {
    timerId = startTimer(60, Qt::PreciseTimer);
    startTime = std::chrono::steady_clock::now();
  }

protected:
  void timerEvent(QTimerEvent* event) {
    qDebug() << (counter++);
    if(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - startTime) / 60 >= 20) {
       killTimer(timerId);
    }
    Object::timerEvent(event);
  }

private:
  int timerId = -1, counter = 0;
  std::chrono::steady_clock::time_point startTime;
}

另一个使用 QElapsedTimer 的例子:

class MyObject: public QObject {

public:
  MyObject() {
    timerId = startTimer(60, Qt::PreciseTimer);
    elapsedTimer.start();
  }

protected:
  void timerEvent(QTimerEvent* event) {
    qDebug() << (counter++);
    if(elapsedTimer.elapsed() / 60 >= 20) {
       killTimer(timerId);
    }
    Object::timerEvent(event);
  }

private:
  int timerId = -1, counter = 0;
  QElapsedTimer elapsedTimer;
}