How to Emit signals from javascript to qml

13,047

Solution 1

Neither Alex's nore Raja's solutions really answer the question. Alex's consists in calling directly from the javascript code the QML slot method, and Raja's consist in setting the value of a property of a QML object from the Javascript code. Both approaches negate the main advantage of the signal/slot mechanism which is that the signalling object does not need to know of the slot.

An approach closer to the spirit of the signal/slot mechanism is described in this blog post (not mine). It consists, within the javascript file, of creating a QML object (via the Qt.createQmlObject() function) the sole function of which is to contain the javascript's object signals. Signals are emitted from javascript through calling the internal QML objects signal (e.g. internalQmlObject.signalName()), and the javascript object signal can be connected in QML to QML slots with the usual connect mechanism via javascriptObject.internalQmlObject.signalName.connect(receiver.slotName).

An example adapted from the blog post is below:

javascript_object.js:

var internalQmlObject = Qt.createQmlObject('import QtQuick 2.0; QtObject { signal someSignal(int value) }', Qt.application, 'InternalQmlObject');

function doSomething() {
    internalQmlObject.someSignal(42);
}

test.qml:

import QtQuick 2.0
import 'javascript_object.js' as JavascriptObject

Rectangle {

    Rectangle {
        id: someComponent

        function someSlot(v) {
            console.log("Signal received " + v);
        }
    }

    Component.onCompleted: {
        JavascriptObject.internalQmlObject.someSignal.connect(someComponent.someSlot);
        JavascriptObject.doSomething();
    }
}

On execution it gives the following:

% qmlscene test.qml
Signal received 42

Solution 2

Thank you, @RajaVarma.

I found solution for myself.

In qml-file: create element Item (my loginItem) which contains function that plays the role of slot. For example (I need to know when handle login event):

import "scripts/auth.js" as Auth
...
Item {
   id: loginItem

   // Send himself to javascript module named Auth
   Component.onCompleted: {
      Auth.setLoginItem(loginItem);
   }

   // "Slot" function
   function logged() {
      console.debug("Login successfully");
      // Do something
      ...
   }
}

In js-file: create receiver for loginItem and use it.

var loginItem;

function setLoginItem(tempLoginItem) {
    loginItem = tempLoginItem;
}

...
   // Emit "signal"
   loginItem.logged();
...

Solution 3

Well, it's very hacky to call signals from a real JS file. But there's a better option, IMHO, used it myself instead. Create your own class.

MyClass.qml

import QtQuick 2.0

QtObject
{
    property var myVariable
    function myFunction() { console.log("emitting signal"); mySignal() }
    signal mySignal
}

This way you can easily achieve the needed encapsulation. And you can even nicely connect to the object.

Then you can do whatever you want with it: create a singleton from it, create a global object, instantiate it.

Share:
13,047
aleks_misyuk
Author by

aleks_misyuk

Updated on June 09, 2022

Comments

  • aleks_misyuk
    aleks_misyuk almost 2 years

    I want to emit signal from javascript-file and receive it in qml-file (To find when time-consuming operation will finished).

    How can I do it?

  • Kamil Klimek
    Kamil Klimek over 12 years
    not related to question but it is "logged in" not "logined" ;)
  • aleks_misyuk
    aleks_misyuk over 12 years
    I'm sorry for my English. I promise to go on language course this month.
  • aleks_misyuk
    aleks_misyuk over 10 years
    I'm agree. Good solution.