【问题标题】:Javascript waiting in QMLJavascript 在 QML 中等待
【发布时间】:2017-03-05 11:17:42
【问题描述】:

我在QML中有两个javascript函数fun1fun2,想要一个接一个(fun2)执行(fun1)完成,更准确地说,我如何启动fun2()之后ImageReader 中的 fun1 已完成。 ImageReader是通过继承QImageProvider用C++编写的函数,如下:

function fun1(){
    ImageReader.magic(photo);
}
function fun2(){
    myImg.source = ""; 
    myImg.source = "image://ImageReader";
}
fun1();
fun2();

使用场景是我想用C++处理一张图片,处理完成后,通过QML Image项显示出来。

【问题讨论】:

  • 那么你的问题是什么?你不是已经按照你提供的代码在func1()之后执行func2()了吗?
  • 我建议一个接一个地打电话给他们。例如像代码here。是什么让你觉得他们不是一个接一个被处决?
  • 我认为你的问题是,fun1() 只启动了在另一个线程中异步执行的方法ImageReader.magic(photo)。所以你的问题应该是:我如何在ImageReader 完成他的魔法之后开始fun2() 因为fun1() 可能在此之前完成。所以fun2()fun1() 完成之后立即执行,但在ImageReader.magic(photo) 完成之前执行。
  • 或遵循Loader 和其他QML 组件的模式,并在ImageReader 中包含属性status。这与属性statusChanged 一起提供
  • 据我所知QQuickImageProvider 不继承自QObject,因此使用信号将需要更改继承。但我同意@derM,这是做你想做的事的好方法。另一种方法是将指向“下一个”函数的指针传递给 C++ 对象(在您的情况下为 ImageReader)。请参阅this 问题的答案以了解更多信息。

标签: qml qt5


【解决方案1】:

好的,我只是想为那些将寻找相同解决方案的人总结一下。

至少有两种方法可以做到这一点:

  • 任务完成后从 C++ 对象发出信号。
  • 将 JS 函数传递给 C++,任务完成后将调用该函数。

测试 C++ 对象声明:

class MyItem : public QObject
{
    Q_OBJECT

public:
    MyItem(QObject *parent = 0);
    Q_INVOKABLE void someAsyncFunc();
    Q_INVOKABLE void someAnotherAsyncFunc(QJSValue value);

signals:
    void someAsyncFuncFinished();
};

测试 C++ 对象实现:

MyItem::MyItem(QObject *parent) :
QObject(parent) {}

void MyItem::someAsyncFunc()
{
    // do some work here
    emit someAsyncFuncFinished();
}

void MyItem::someAnotherAsyncFunc(QJSValue value) {
    // do some work here
    if (value.isCallable()) {
        value.call();
    }
}

将自定义项注册为单例:

static QObject *my_singleton_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)
    static MyItem *item = nullptr;
    if(!item)
        item = new MyItem();
    return item;
}

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

    qmlRegisterSingletonType<MyItem>("Qt.MyTest", 1, 0, "MyItem", my_singleton_provider);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

还有 QML 文件来测试它:

1.任务完成时触发信号

Item {
    id: testItem

    function func1()
    {
        console.log("func1 executing...")
        MyItem.someAsyncFuncFinished.connect(func2);
        MyItem.someAsyncFunc();
    }

    function func2()
    {
        console.log("func2 executing...")
    }

    Component.onCompleted: func1();
}

2.将 JS 函数传递给 C++:

Item {
    id: testItem

    function func1()
    {
        console.log("func1 executing...")
        MyItem.someAnotherAsyncFunc(func2);
    }

    function func2()
    {
        console.log("func2 executing...")
    }

    Component.onCompleted: func1();
}

【讨论】:

    【解决方案2】:

    基本上你有两种方法来解决这个问题

    1. 让异步进程通知它正在完成
    2. 投票结果的可用性

    我不推荐第二种方法,尤其是在声明式环境中,所以让我们进一步研究选项一。

    对于 C++ 和 QML/JavaScript 之间的通知,您基本上有两个选择

    1. 使用QObject 信号机制
    2. 将 JavaScript 回调传递给 C++ 并从那里调用

    Qt 的异步 QML API 通常使用前者完成,但如果您更喜欢后者,请查看 QJSValue 作为用于回调参数的 C++ 数据类型。

    【讨论】:

      【解决方案3】:

      我对 QML 了解不多,我认为在普通的 JavaScript 中你的代码应该可以工作。但如果它不按顺序调用,我可以建议你这种丑陋的方式:

      function fun1() {
          ImageReader.magic(photo);
          return 1;
      }
      function fun2(wait){
          if(wait==1)
          {
              myImg.source = ""; 
              myImg.source = "image://ImageReader";
          }
      }
      fun2(fun1());
      

      【讨论】:

      • 谢谢。但它仍然不起作用。 ImageReader.magic(photo);是C++继承QImageProvider编写的函数,处理图像需要较长时间并回馈给QML。
      猜你喜欢
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 2010-11-30
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多