【问题标题】:QT "Tick" widget loopQT“Tick”小部件循环
【发布时间】:2019-04-20 02:56:43
【问题描述】:

我正在尝试了解在帧时更新小部件的正确方法。 我要解决的具体问题是在标签上设置计时器的剩余时间。

我创建并启动了计时器

MainTimer = new QTimer(this);
MainTimer->setSingleShot(true);
MainTimer->start(5000);

在 QML 上,我有一个标签 UI_MainTimerLabel,我可以通过 ui->UI_MainTimerLabel->setNum(int) 访问它。

由于 QTimer 不提供OnTimerUpdate 信号或回调方法,我想我必须创建某种循环来读取计时器的值并将其设置为标签。

我应该通过 QThread 来做吗?

QThread::create([&]() {
    while(true)
    {
        ui->UI_RemainingTimer->setNum(MainTimer->remainingTime());
    }
})->start();

(注意:我知道这行不通,但这不是问题,因为我只是想理解这个概念)

我应该使用 0-timed QTimer 吗?

UpdateTimer = new QTimer(this);
//{binding the UpdateTimer end signal to a ui->UI_RemainingTimer->SetNum(MainTimer->RemainingTimer() function}
UpdateTimer->start(0);

我应该使用 QEventLoop(但我还没有完全理解它们的正确用法)吗?

我应该使用用户创建的可自我更新的“MyTimerLabel”小部件(在哪个虚拟覆盖方法中?)?

或者还有其他一些我无法理解的管理帧时间更新的正确方法吗? (不过,我试图获得一般正确的方法,而不是解决这个特定问题的方法)

提前致谢

【问题讨论】:

  • 为什么不能只使用QTimer::timeout 信号?
  • @G.M.你的意思是 MainTimer::timeout?它不是仅在 5000 毫秒后才被调用吗?我需要它来更新帧时间。或者你的意思是 0-timed-timer-method?
  • QTimer::timeout 我指的是与QTimer 类相关的信号。 frame-time 是什么意思?抱歉,但我对你想要达到的目标有点困惑。
  • 我的具体问题是如何在 QLabel 上显示 MainTimer 的剩余时间,但一般问题是如何在 main-loop-time 中更新小部件

标签: c++ qt loops qt5


【解决方案1】:

是否有必要随时更新 GUI?不,每帧每 30 毫秒更新一次,因此适当的做法是更新一半的时间,即 15 毫秒。因此,通过计算在 GUI 中显示的剩余时间,将第二个计时器设置为该时间段:

#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTimer main_timer;
    main_timer.setSingleShot(true);
    QTimer update_timer;
    QLabel label;
    label.setAlignment(Qt::AlignCenter);
    label.resize(640, 480);
    QObject::connect(&update_timer, &QTimer::timeout, [&main_timer, &update_timer, &label](){
        int rem = main_timer.remainingTime();
        if(rem <0){
            label.setNum(0);
            update_timer.stop();
        }
        else{
            label.setNum(rem);
        }
    });
    label.show();
    main_timer.start(5000);
    update_timer.start(15);
    return a.exec();
}

【讨论】:

  • 那么正确的(qt?)方式来更新一个“几乎在帧时间”的小部件是通过一个定时计时器?
  • @Mewster 您必须在必要时更新它,例如假设您每毫秒更新一次数字,但您的屏幕以 30Hz 即 33.33ms 重新绘制,因此您将修改它 30 次,但 Qt 只会绘制最后一个仅更新类的内部状态,但不一定要绘制。
  • 是否有任何不可知的方法可以从 QT 中了解应用程序的正确渲染时间,或者这不是一个可管理的情况?
  • @Mewster 因此,在这种特定情况下,您希望显示计时器的剩余时间,因此知道屏幕的更新率为 33ms,只需将其更新为更短的时间,因为视觉上我们的眼睛没那么快。所以我在 15 ms 使用第二个 QTimer,然后使用 Qt 形式通知我:通过一个信号,这个信号连接到一个函数,在这种情况下是一个 lambda 方法,并且在那个函数中我更新了 GUI,所以是的,这是Qt更新GUI的方式。
  • @Mewster 不,你真的不知道 Qt 更新了多长时间,因为你可以看到有延迟,例如屏幕绘制延迟,Qt 听 OS 时延迟事件,将这些数据传输到 Qt 组件的延迟,我们应用程序计算的另一个延迟。通常在应用程序中不需要精度,如果在 33.33 毫秒或 33.34 毫秒内绘制,则无关紧要。