Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. PyQt, JavaScript and WorkerScript

PyQt, JavaScript and WorkerScript

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
7 Posts 2 Posters 3.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JasonS
    wrote on last edited by JasonS
    #1

    I'm trying to work with WorkerScript that will call a class in Python, but the way I have it setup is giving me an error when I run it.

    Here is what I have so far:

    main.py

    import sys
    
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtQml import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtQuick import *
    
    class test(QObject):
    
        @pyqtSlot()
        def printStatus(self):
            print("hello from main.py")
    
    def main():
    
        app = QGuiApplication(sys.argv)
    
        engine = QQmlApplicationEngine()
    
        tryTest = test()
        engine.rootContext().setContextProperty('tryTest', tryTest)
    
        engine.load(QUrl("main.qml"))
        app.exec()
    
    if __name__ == "__main__":
        main()
    

    workerscript.js

    WorkerScript.onMessage = function() {
        prt()
    }
    
    function prt() {
        tryTest.printStatus();
    }
    

    Part of my QML file that sets up the WorkerScript

    Timer {
            id: timer1
            interval: 1000
            repeat: true
            running: true
    
            onTriggered: {
                worker.sendMessage();
            }
        }
    
        WorkerScript {
            id: worker
            source: "workerscript.js"
        }
    

    When I execute main.py my UI loads fine, but then when the WorkerScript calls my js file I get the following error message:

    workerscript.js:6: ReferenceError: tryTest is not defined

    I'm assuming it's because workerscript.js doesn't know about my main.py. When I import workerscript.js into my QML file and call the function without using the WorkerScript it executes just fine. Any idea what I am doing wrong? I am using PyQt5 and Python 3.

    ? 1 Reply Last reply
    0
    • J JasonS

      I'm trying to work with WorkerScript that will call a class in Python, but the way I have it setup is giving me an error when I run it.

      Here is what I have so far:

      main.py

      import sys
      
      from PyQt5.QtCore import *
      from PyQt5.QtGui import *
      from PyQt5.QtQml import *
      from PyQt5.QtWidgets import *
      from PyQt5.QtQuick import *
      
      class test(QObject):
      
          @pyqtSlot()
          def printStatus(self):
              print("hello from main.py")
      
      def main():
      
          app = QGuiApplication(sys.argv)
      
          engine = QQmlApplicationEngine()
      
          tryTest = test()
          engine.rootContext().setContextProperty('tryTest', tryTest)
      
          engine.load(QUrl("main.qml"))
          app.exec()
      
      if __name__ == "__main__":
          main()
      

      workerscript.js

      WorkerScript.onMessage = function() {
          prt()
      }
      
      function prt() {
          tryTest.printStatus();
      }
      

      Part of my QML file that sets up the WorkerScript

      Timer {
              id: timer1
              interval: 1000
              repeat: true
              running: true
      
              onTriggered: {
                  worker.sendMessage();
              }
          }
      
          WorkerScript {
              id: worker
              source: "workerscript.js"
          }
      

      When I execute main.py my UI loads fine, but then when the WorkerScript calls my js file I get the following error message:

      workerscript.js:6: ReferenceError: tryTest is not defined

      I'm assuming it's because workerscript.js doesn't know about my main.py. When I import workerscript.js into my QML file and call the function without using the WorkerScript it executes just fine. Any idea what I am doing wrong? I am using PyQt5 and Python 3.

      ? Offline
      ? Offline
      A Former User
      wrote on last edited by
      #2

      @JasonS Hi! The JS file is executed on its own thread and in its own context. Thus it can't access anything from your QML engine's context, including the context properties you set. The only way to interact with the WorkerScript is using sendMessage and the onMessage.

      J 1 Reply Last reply
      1
      • ? A Former User

        @JasonS Hi! The JS file is executed on its own thread and in its own context. Thus it can't access anything from your QML engine's context, including the context properties you set. The only way to interact with the WorkerScript is using sendMessage and the onMessage.

        J Offline
        J Offline
        JasonS
        wrote on last edited by
        #3

        @Wieland Hmm...I think I'm following you, but aren't I using sendMessage? I create the WorkerScript element as worker that has workerscript.js as the source file. In my onTriggered from my timer I do worker.sendMessage().

        Timer {
                id: timer1
                interval: 1000
                repeat: true
                running: true
        
                onTriggered: {
                    worker.sendMessage();
                }
            }
        
            WorkerScript {
                id: worker
                source: "workerscript.js"
            }
        

        Then what I'm trying to do is access my Python class from my JS file which is where I'm getting the error. It's not seeing the Python file even though the Python script is what loads the UI. Is this what you mean or are you saying what I am trying to do wont work? If it wont work do you have any suggestions on how I can access my class in the Python file using a different thread like the WorkerScript does? I need to interact with GPIO on my Raspberry PI which will take time based on the fact that I will be turning a motor on for an extended period of time. I don't want the GUI to lock up while this happens. I thought the WorkerScript would be perfect for this.

        1 Reply Last reply
        0
        • ? Offline
          ? Offline
          A Former User
          wrote on last edited by
          #4

          You're using tryTest in your JS file, but it's not available there. I guess what you actually want looks more like:

          workerscript.js

          WorkerScript.onMessage = function(message) {
              // compute something based on message
              var z = message.x + message.y
              // send result
              WorkerScript.sendMessage({x:message.x, y:message.y, z:z})
          }
          

          main.qml

          Timer {
                  id: timer
                  interval: 1000
                  repeat: true
                  running: true
          
                  property real x : 23
                  property real y : 42
          
                  onTriggered: worker.sendMessage({x:timer.x, y:timer.y});
              }
          
              WorkerScript {
                  id: worker
                  source: "workerscript.js"
                  onMessage: {
                        tryTest.printStatus(); // <- that's OK
                        console.log("z=x+y <=> "+ messageObject.z +"="+ messageObject.x +"+"+ messageObject.y )
                  }
              }
          
          J 1 Reply Last reply
          1
          • ? A Former User

            You're using tryTest in your JS file, but it's not available there. I guess what you actually want looks more like:

            workerscript.js

            WorkerScript.onMessage = function(message) {
                // compute something based on message
                var z = message.x + message.y
                // send result
                WorkerScript.sendMessage({x:message.x, y:message.y, z:z})
            }
            

            main.qml

            Timer {
                    id: timer
                    interval: 1000
                    repeat: true
                    running: true
            
                    property real x : 23
                    property real y : 42
            
                    onTriggered: worker.sendMessage({x:timer.x, y:timer.y});
                }
            
                WorkerScript {
                    id: worker
                    source: "workerscript.js"
                    onMessage: {
                          tryTest.printStatus(); // <- that's OK
                          console.log("z=x+y <=> "+ messageObject.z +"="+ messageObject.x +"+"+ messageObject.y )
                    }
                }
            
            J Offline
            J Offline
            JasonS
            wrote on last edited by
            #5

            @Wieland Ok, I see the issue now and what the script you provided is doing. Basically it looks like you could put anything in the workerscript.js sendMessage just so it triggers the onMessage in the QML, then since the Python is hooked up to the QML it knows about tryTest. Correct? I think I proved this by passing "" to sendMessage... WorkerScript.sendMessage("").

            Seems like a hokey way of doing it. Well, at least I know this works, but I think I'll look for a cleaner solution. I think I have a couple:

            https://wiki.qt.io/Updating-QML-content-from-Python-threads
            http://stackoverflow.com/questions/10650960/concurrent-programming-in-python-and-qt

            and this one gives multiple options:
            http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt

            If you have other ideas it would be super duper if you shared, otherwise I have some playing around to do.

            Thanks for all your help.

            ? 1 Reply Last reply
            0
            • ? Offline
              ? Offline
              A Former User
              wrote on last edited by
              #6

              Ah, sry, I was a bit out of it. Controlling your motor from a WorkerScript looks like a bad idea in general and I have doubts if it's even possible without some really dirty hacks. QtQuick is good for implementing GUIs but all business logic belongs in a C++ backend (or Python backend, if you like that better). QML is great for GUIs but its too limited to do any serious tasks beyond just that. Also JavaScript is really slow and I don't think you want to control real hardware with that.

              1 Reply Last reply
              1
              • J JasonS

                @Wieland Ok, I see the issue now and what the script you provided is doing. Basically it looks like you could put anything in the workerscript.js sendMessage just so it triggers the onMessage in the QML, then since the Python is hooked up to the QML it knows about tryTest. Correct? I think I proved this by passing "" to sendMessage... WorkerScript.sendMessage("").

                Seems like a hokey way of doing it. Well, at least I know this works, but I think I'll look for a cleaner solution. I think I have a couple:

                https://wiki.qt.io/Updating-QML-content-from-Python-threads
                http://stackoverflow.com/questions/10650960/concurrent-programming-in-python-and-qt

                and this one gives multiple options:
                http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt

                If you have other ideas it would be super duper if you shared, otherwise I have some playing around to do.

                Thanks for all your help.

                ? Offline
                ? Offline
                A Former User
                wrote on last edited by
                #7

                @JasonS said in PyQt, JavaScript and WorkerScript:

                Correct?

                Yes, that's how it works :) Also your idea of using an extra thread in Python to control the motor seems to be the best idea.

                1 Reply Last reply
                1

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved