External process from Qml



  • Hi everyone,
    is it possible to call an external process from qml ?


  • Moderators

    @Naveen_D

    is it possible to call an external process from qml ?

    Not directly but you can create a C++ component and expose it to QML and make it execute the external processes



  • @p3c0 thanks for the reply...
    yea i am doing the same now... i am using a C++ class and Qprocess to start another process....the new process gives me a string (it is a command said in live microphone) which i pass it through signal back to the qml...but what is happening is..when i call the c++ function from qml, the control doesn't wait until the function is over, it continues to print some debug statements, which i have given after that function call


  • Moderators

    @Naveen_D Can you post the C++ code ?



  • @p3c0 ya sure.
    here is the c++ code

    #include "ProcessWidget.h"
    
    ProcessWidget::ProcessWidget(QWidget *parent)
        : QWidget(parent)
    {
    }
    
    void ProcessWidget::vStartProcess()
    {
        qDebug()<<"entered the function"<<endl;
        const QString program = QStringLiteral("/home/ubuntu/Documents/Sample_Examples_Qt_Qml/VoiceRecognition/VoiceRecognition");
        myProcess = new QProcess;
    
        connect(myProcess,SIGNAL(readyReadStandardError()),this,SLOT(vEndProcess()));
        connect(myProcess,SIGNAL(finished(int)),myProcess,SLOT(deleteLater()));
        myProcess->start(program);
        qDebug()<<"process started waiting for output"<<endl;
        connect(this,&ProcessWidget::destroyed,myProcess,&QProcess::kill);
    
    }
    
    void ProcessWidget::vEndProcess()
    {
        const QString processOut = QString::fromLatin1(myProcess->readAllStandardError());
        qDebug()<<"output>>>>"<<processOut<<endl;
        const QRegularExpression regXp("Received Command:s*(.+)");
        const auto regXpMatch = regXp.match(processOut);
        if(regXpMatch.hasMatch()){
            qDebug() << "Output of regular exp is: "<< regXpMatch.captured(1);
            signalData= regXpMatch.captured(1);
            qDebug()<<"signal data is >>"<<signalData<<endl;
            emit playmusicsignal(signalData);
        }
    }
    
    
    
    ProcessWidget::~ProcessWidget()
    {
    
    }
    

  • Moderators

    @Naveen_D As per doc:

    Note: Processes are started asynchronously, which means the started() and errorOccurred() signals may be delayed. Call waitForStarted() to make sure the process has started (or has failed to start) and those signals have been emitted.

    Try static execute instead.



  • @p3c0 Sir i used execute instead of start but...i am not able to pass the output which i got from the new process, back to qml...what may be the problem ?
    my code

    #include "ProcessWidget.h"
    
    ProcessWidget::ProcessWidget(QWidget *parent)
        : QWidget(parent)
    {
    }
    
    void ProcessWidget::vStartProcess()
    {
        qDebug()<<"entered the function"<<endl;
        const QString program = QStringLiteral("/home/ubuntu/Documents/Sample_Examples_Qt_Qml/VoiceRecognition/VoiceRecognition");
        myProcess = new QProcess;
    
        connect(myProcess,SIGNAL(readyReadStandardError()),this,SLOT(vEndProcess()));
        connect(myProcess,SIGNAL(finished(int)),myProcess,SLOT(deleteLater()));
        connect(this,&ProcessWidget::destroyed,myProcess,&QProcess::kill);
        myProcess->execute(program);
    //    myProcess->waitForStarted(30000);
        qDebug()<<"process started waiting for output"<<endl;
    
    }
    
    void ProcessWidget::vEndProcess()
    {
        const QString processOut = QString::fromLatin1(myProcess->readAllStandardError());
        qDebug()<<"output>>>>"<<processOut<<endl;
        const QRegularExpression regXp("Received Command:s*(.+)");
        const auto regXpMatch = regXp.match(processOut);
        if(regXpMatch.hasMatch()){
            qDebug() << "Output of regular exp is: "<< regXpMatch.captured(1);
            signalData= regXpMatch.captured(1);
            qDebug()<<"signal data is >>"<<signalData<<endl;
            emit playmusicsignal(signalData);
        }
    }
    
    ProcessWidget::~ProcessWidget()
    {
    
    }
    

    in the above code, i didn't get any debug statements in console from vEndProcess function


  • Moderators

    @Naveen_D Are you sure you want readyReadStandardError or readAllStandardOutput instead ?



  • @p3c0

    Are you sure you want readyReadStandardError or readAllStandardOutput instead ?

    even when i use readAllStandardOutput i am not able to send the output through signal.



  • Maybe I'm being silly here but since you are running what looks like the Hello Speak Example why do you start it as a separate process rather than a separate thread?



  • @VRonin Sir i am not aware of threads...i am learning it from begining...for time being i am using separate process to get the required output.





  • @VRonin thanks for the link sir..i will go through it...but can i know what i need to do with the process thing to get the required output.?



  • That's because you block the event loop that you need to read. Use

    void ProcessWidget::vStartProcess()
    {
        qDebug()<<"entered the function"<<endl;
        const QString program = QStringLiteral("/home/ubuntu/Documents/Sample_Examples_Qt_Qml/VoiceRecognition/VoiceRecognition");
        myProcess = new QProcess;
    QEventLoop blockLoop;
        connect(myProcess,SIGNAL(readyReadStandardError()),this,SLOT(vEndProcess()));
        connect(myProcess,SIGNAL(finished(int)),myProcess,SLOT(deleteLater()));
    connect(myProcess,SIGNAL(finished(int)),&blockLoop,SLOT(quit()));
        connect(this,&ProcessWidget::destroyed,myProcess,&QProcess::kill);
        myProcess->start(program);
        qDebug()<<"process started waiting for output"<<endl;
    blockLoop.exec();
    }
    


  • @VRonin Sir if i use the EventLoop it is not returning control...it will be in continuous loop like if i give input through live microphone it will wait for next input like that



  • @Naveen_D said in External process from Qml:

    but what is happening is..when i call the c++ function from qml, the control doesn't wait until the function is over, it continues to print some debug statements, which i have given after that function call

    @Naveen_D said in External process from Qml:

    if i use the EventLoop it is not returning control

    I'm not sure I understand what you want to achieve. Do you want the process to act synchronously (loop until process is over) or asynchronously (return control almost immediately to the main app)?



  • @VRonin the scenario is..when i call the c++ function from qml it should start the process...through which i get the output and will pass the output through a signal back to qml. till the process is not completed it should not return back to main app(i.e Qml app).
    Now i am getting the output to my console but i am not able to send it as shown in the above code.


  • Moderators

    @Naveen_D Why should it not return? What you are trying to do is not how Qt apps should work. You should use signals/slots: you start the process, connect signals/slots and as soon as there is input from the process you handle it in the slot.



  • @jsulm Sorry sir i didn't get...is the above code wrong which i have posted ? or what changes i need to do ?

    One more doubt..how to compare a string in Qml...like in Qt we do (str=="some string")


  • Moderators

    @Naveen_D ProcessWidget::vStartProcess is currently blocking, why? Why not just start the process, connect signals/slots and return from ProcessWidget::vStartProcess ?

    void ProcessWidget::vStartProcess()
    {
        qDebug()<<"entered the function"<<endl;
        const QString program = QStringLiteral("/home/ubuntu/Documents/Sample_Examples_Qt_Qml/VoiceRecognition/VoiceRecognition");
        myProcess = new QProcess;
        connect(myProcess,SIGNAL(readyReadStandardError()),this,SLOT(vEndProcess()));
        connect(myProcess,SIGNAL(readyReadStandardOutput()),this,SLOT(processStandardOutput()));
        connect(myProcess,SIGNAL(finished(int)),myProcess,SLOT(deleteLater()));
        connect(this,&ProcessWidget::destroyed,myProcess,&QProcess::kill);
        myProcess->start(program);
    }
    

    processStandardOutput() will be called as soon as the process is writing something to standard output.



  • @jsulm Yes i got that...
    i want to know how to compare string s in Qml...
    the string which i am passing through the signal...i want to compare that in qml and next give functionality for that...

    i used the following code but didn't get...

    onPlaymusicsignal: {
                        console.log("Recorded Voice :" + recordedString)
                        var receivedString = recordedString
                        console.log(receivedString)
                        if(receivedString == "GOTO MUSIC")
                        {
                            console.log("play music")
                        }
                        else
                        {
                            console.log("please try again")
                        }
                    }
    

    even though the received string is GOTO MUSIC its printing in the console as please try again.




  • Moderators

    @Naveen_D I'm not JavaScript expert (what QML basically is), but as far as I know you can use === instead of ==
    If there maybe a new line at the end of receivedString ?



  • @jsulm @VRonin i just tried with that... i don't know do i need to use javascript for this or wat...i simply tried once with that code...
    Is it necessary to javascript to do this...because in Qt i use to do it using == so i thought here it will be the same...


  • Moderators

    @Naveen_D QML is JavaScript.
    Did you check the link provided by @VRonin ?



  • @jsulm ya i checked...after checking that code only i used var in the code as shown above...but i didn't get that clearly so posted this in forum.


  • Moderators

    @Naveen_D

    if(receivedString.localeCompare("GOTO MUSIC") == 0)
    {
        console.log("play music")
    }
    else
    {
        console.log("please try again")
    }
    


  • @jsulm
    i tried with both the codes...its going to else part.

    onPlaymusicsignal: {
                        console.log("Recorded Voice :" + recordedString)
                        var receivedString = recordedString
                        console.log(receivedString)
                        if(receivedString.localeCompare("GOTO MUSIC") == 0)
                        {
                            console.log("play music")
                            musicScreen.visible= true
                        }
                        else
                        {
                            console.log("please try again")
                        }
    
    onPlaymusicsignal: {
                        console.log("Recorded Voice :" + recordedString)
                        var receivedString = recordedString
                        var GotoMusicString = new String("GOTO MUSIC")
                        console.log(receivedString)
                        if(receivedString.localeCompare(GotoMusicString) == 0)
                        {
                            console.log("play music")
                            musicScreen.visible= true
                        }
                        else
                        {
                            console.log("please try again")
                        }
                    }
    

  • Moderators

    @Naveen_D Maybe receivedString contains a new line character at the end?



  • @jsulm this is the output i am getting from the started process and the same output i am sending through the signal to qml

    output>>>> "\n<<< please speak >>> \n\n \n\n"

    output>>>> "Received Command: "GOTO MUSIC"\n"

    Output of regular exp is: ""GOTO MUSIC""
    signal data is >> ""GOTO MUSIC""

    qml: Recorded Voice :"GOTO MUSIC"
    qml: "GOTO MUSIC"
    qml: please try again


  • Moderators

    @Naveen_D It look like your string is not "GOTO MUSIC" but ""GOTO MUSIC""
    You have " at the beginning and end of the string as part of the string.


  • Moderators

    @Naveen_D To remove those " do:

    var receivedString = recordedString.slice(1, -1)
    


  • @jsulm yes that " was the part of that string...i got the output thanks...
    one more doubt...is there any other method...because i have lot of commands like GOTO MUSIC for which i need to give functionality.


  • Moderators

    @Naveen_D The easiest way would be to fix your process so it does not put the recognized strings inside "".
    If this is not possible then you need to change the way you're parsing the output of that process, so your regular exceptions do not match "


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.