You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt Quick+C++中如何放置可重复调用的update与fixedUpdate函数?

在Qt Quick QML中实现循环调用update()和fixedUpdate()的方案

Qt Quick基于Qt事件循环运行,不需要手动编写while循环,你可以通过以下方式实现两类函数的重复调用:

1. 每帧触发的update()(通用更新)

利用Window的frameSwapped信号,该信号会在每一帧渲染完成后触发,刚好对应你原C++代码中每次循环调用的update()。

2. 固定时间间隔的fixedUpdate()(物理处理)

使用QML的Timer组件,设置固定的时间间隔并开启重复触发,用来模拟固定步长的物理更新逻辑。


方案一:C++后端 + QML调用(适合复杂逻辑)

如果你的update()和fixedUpdate()是C++实现的函数,需要先将它们暴露给QML:

C++ Engine类实现

#include <QObject>
#include <QElapsedTimer>

class Engine : public QObject
{
    Q_OBJECT
    Q_PROPERTY(float deltaTime READ deltaTime NOTIFY deltaTimeChanged)
public:
    explicit Engine(QObject *parent = nullptr) : QObject(parent) {
        timer.start();
    }

    // 标记为可被QML调用
    Q_INVOKABLE void update() {
        // 计算帧间隔时间(秒)
        m_deltaTime = timer.elapsed() / 1000.0f;
        timer.restart();
        // 你的通用更新逻辑写在这里
        emit deltaTimeChanged();
    }

    Q_INVOKABLE void fixedUpdate() {
        // 你的物理处理逻辑写在这里
    }

    float deltaTime() const { return m_deltaTime; }

signals:
    void deltaTimeChanged();

private:
    QElapsedTimer timer;
    float m_deltaTime = 0.0f;
};

注册C++类到QML(main.cpp)

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "engine.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    // 注册Engine类到QML的MyEngine模块
    qmlRegisterType<Engine>("MyEngine", 1, 0, "Engine");

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

    return app.exec();
}

QML调用逻辑(main.qml)

import QtQuick 2.15
import QtQuick.Window 2.15
import MyEngine 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Loop Example")

    // 实例化C++的Engine对象
    Engine {
        id: gameEngine
    }

    // 监听帧交换信号,每帧调用update()
    Connections {
        target: window
        function onFrameSwapped() {
            gameEngine.update();
        }
    }

    // 固定间隔调用fixedUpdate(),这里设为16ms(约60次/秒)
    Timer {
        interval: 16
        running: true
        repeat: true
        onTriggered: {
            gameEngine.fixedUpdate();
        }
    }

    // 可选:显示帧间隔时间
    Text {
        text: "Delta Time: " + gameEngine.deltaTime.toFixed(3)
        anchors.top: parent.top
        anchors.left: parent.left
        anchors.margins: 10
        font.pixelSize: 16
    }
}

方案二:纯QML实现(适合简单逻辑)

如果逻辑不需要C++处理,直接在QML中定义函数并调用:

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Pure QML Loop")

    // 定义通用更新函数
    function update() {
        // 你的每帧更新逻辑
        console.log("Frame updated");
    }

    // 定义物理更新函数
    function fixedUpdate() {
        // 你的固定间隔处理逻辑
        console.log("Fixed update triggered");
    }

    // 每帧触发update()
    Connections {
        target: window
        function onFrameSwapped() {
            update();
        }
    }

    // 固定间隔触发fixedUpdate()
    Timer {
        interval: 16
        running: true
        repeat: true
        onTriggered: fixedUpdate()
    }
}

关键说明

  • frameSwapped信号的触发时机和渲染帧率一致,适合处理和画面同步的逻辑(比如角色动画、相机跟随)。
  • Timer的interval可以根据需求调整,比如物理模拟常用16ms(60次/秒)或33ms(30次/秒),保证处理步长稳定。
  • 如果你需要更精确的时间控制,也可以在C++中使用QTimer来触发fixedUpdate(),效果和QML的Timer一致。

内容的提问来源于stack exchange,提问作者skrovno_CZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:07:46