QTimer 完成阻塞任务后不会立即触发

问题描述 投票:0回答:1

背景: 在我们的嵌入式QT应用程序(基于ARM处理器)中,有一个Qtimer每20ms就会超时。 更新用户界面对象是在该计时器的超时处理程序内完成的。

此外,我们还有一个计算量很大的任务,我将其替换为一个“for”循环,其中包含大约 3000 次迭代和打印语句,以便于理解。 我在此操作期间显示 BusyIndicator。

问题1: 当显示 BusyIndicator 时,设置为 20ms 的 Qtimer 每 40 秒以上就会超时。(无论如何,此时这不会引起任何问题,因为显示 BusyIndicator 时不会执行任何与 UI 相关的操作)。

问题2(实际问题): 一旦繁重的任务完成,BusyIndicator 就会被禁用。禁用 BusyIndicator 后触发的 Qtimer 第一次也需要 40 秒以上才超时,然后它会恢复并随后每 20 毫秒触发一次。 因此,一旦禁用 BusyIndicator 并显示任何有效页面,UI 将在 40 秒以上的时间内没有响应。

问题:

  1. 为什么 BusyIndicator 会影响 Qtimer 的超时值?
  2. 有没有办法让BusyIndicator不影响Qtimer超时值?
  3. 对于我面临的问题还有其他解决方案吗?

注: 我在 QtCreator 中创建了一个虚拟项目,并创建了一个基于演示桌面的应用程序(在 Windows 和 Ubuntu 中),具有相同的场景(即 QTimer 被阻塞的繁重任务中断了一段时间),我看不到任何问题(QTimer 立即触发)阻塞任务完成后)。请在下面找到模拟我的问题场景的演示应用程序的代码:

main.cpp

#include "main.h"

myClass *classPtr;
static int loopStart=0;

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    myClass classs;
    classPtr = &classs;

    return app.exec();
}

myClass::myClass(QObject *parent):
    QObject(parent)
{

    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &myClass::timerEvnt);
    timer->start(20);
}

void myClass::timerEvnt()
{
    myClass::looop();
    if(loopStart >= 5)
        qDebug()<<"timer continuation";
    loopStart++;
}

void myClass::looop()
{
    int j=0;
    if(loopStart == 5)
    {
        for(int i=0; i<300;i++)
        {
            qDebug()<<"iterations="<<i;
        }
        qDebug()<<"#####################for loop comp="<<j;
    }
}

main.h

#ifndef MAIN_H
#define MAIN_H
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
#include <QTimer>
#include <QQuickView>
#include <QElapsedTimer>

class myClass : public QObject
{
    Q_OBJECT
public:
    QTimer *timer;
    explicit myClass(QObject* parent = nullptr);
    void timerEvnt();
    void looop();
};

#endif // MAIN_H

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Rectangle {
        width: parent.width
        height: parent.height

        Text {
            id: displayText
            anchors.centerIn: parent
            text: "Initial Message"
            font.pixelSize: 20
        }
    }
}

提前致谢

qt qml qtimer busyindicator
1个回答
0
投票

考虑以下代码。在这里,无论平台如何(可以是 intel PC,可以是嵌入式 ARM 平台),我们保证

Timer
代码只会利用 QML 引擎的 50%,从而允许 QML 引擎赶上自己的事件。

如果您阅读代码,它将以 200 毫秒的间隔安排一次

Timer
,并且
onTriggered
的实现上限为 100 毫秒。因此,我们 50% 的时间都在回馈 QML 引擎。执行的迭代次数因平台而异,但是,我们保证此代码是跨平台友好的。

import QtQuick
import QtQuick.Controls
Page {
    property double calcPI: 4
    property int div: 1
    property int totalIter: 0
    Text {
        text: "%1 (%2 total iterations)".arg(calcPI.toString()).arg(totalIter)
    }
    Timer {
        interval: 200
        repeat: true
        running: true
        onTriggered: {
            let start = Date.now();
            while (Date.now() - start < 100)
                calcStep();
        }
    }
    function calcStep() {
        div += 2;
        calcPI -= 4 / div;
        div += 2;
        calcPI += 4 / div;
        totalIter++;
    }
}

您可以在线尝试此代码!

© www.soinside.com 2019 - 2024. All rights reserved.