【问题标题】:Progress bar implementation in QML to show progress of a loop in C++QML 中的进度条实现以显示 C++ 中循环的进度
【发布时间】:2018-11-13 12:06:45
【问题描述】:

我的 QML UI 与我的 C++ 代码一起使用。我需要展示其进度的循环是用 C++ 开发的,如下所示:

for(unsigned int j = 0; j < Count; ++j) {
    // Do stuff
}

在我的 QML 代码中,我需要这样的进度条:

ProgressBar {
    value: j  // Should come from C++ loop
              // It is "j" on C++ loop
    from: 0   // C++ loop starts out with 0
    to: Count // C++ loop ends with "Count"
}

我不知道我的 C++ 循环和我的 QML 进度条需要如何相互链接。我找不到任何相关示例。谁能给我一个提示。


我的 C++ 和 QML 之间的通信是通过像这样使用Q_PROPERTY 完成的,但我不知道如何使用它:

Q_PROPERTY(float j READ j WRITE setJ NOTIFY jChanged)

【问题讨论】:

标签: c++ qt qml


【解决方案1】:

这很容易!让我们一步一步来。

  1. 您的 C++ 类应该扩展 QObject 并在内部使用 Q_OBJECT 宏。例如,我称之为Worker

    class Worker : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(float progress READ progress NOTIFY progressChanged)
    public:
        Q_INVOKABLE void start() {
            // start the worker thread in which your loop spins
        }
        float progress(); // progress getter
    signals:
        void progressChanged(float progress);
    };
    
  2. 启动后台线程并定义自己的progressChanged 信号。

    for(unsigned int j = 0; j < Count; ++j) {
        // Do stuff
        emit progressChanged(/*current progress*/);
    }
    
  3. 将后台线程的progressChanged 连接到主线程活动对象WorkerprogressChanged 信号(排队连接)。需要此步骤将信号从后台线程中继到 QML。

  4. 将 C++ 类链接到 QML:

    int main(int argc, char *argv[]) {
        QGuiApplication app(argc, argv);
    
        QQuickView view;
        Worker w;
        view.engine()->rootContext()->setContextProperty("worker", &w);
        view.setSource(QUrl::fromLocalFile("MyItem.qml"));
        view.show();
    
        return app.exec();
    }
    
  5. 在QML端监听信号:

    ProgressBar {
        id: prg
        from: 0   // C++ loop starts out with 0
        to: Count // C++ loop ends with "Count"
    
        Connections {
            target: worker
            onProgressChanged: prg.value = progress;
        }
    }
    

【讨论】:

  • 你测试了吗?因为看起来这个解决方案会阻塞主线程,所以在所有工作完成之前GUI不会更新。而且 QML 不能直接连接到其他线程中的对象,任何排队的连接都必须在 C++ 端处理。所以至少,它需要一个非阻塞工作者。
  • @dtech 在start 方法中,我注释说应该运行一个工作线程,其中应该发出进度信号。同样你是对的,需要一个额外的连接来连接主线程的progressChanged到后台的线程progressChanged
  • 参见stackoverflow.com/questions/53280700/…stackoverflow.com/questions/32952474/…,后者甚至可以在不阻塞主线程的情况下通过分片工作实现。
  • @dtech 我认为启动后台线程是一个更好的解决方案,可以将工作碎片化并定期阻塞主线程。
  • 真的看情况了,阻塞主线程也没什么不好,只要不超过50ms。有许多任务,第二个线程是矫枉过正的。非阻塞工作者也可以在纯 QML 中实现,除了异常有限的工作者脚本之外,您不能真正使用辅助线程。针对不同用例的不同解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多