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. Signal from c++ to QML with setContextProperty
Forum Updated to NodeBB v4.3 + New Features

Signal from c++ to QML with setContextProperty

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
12 Posts 4 Posters 2.6k Views 1 Watching
  • 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.
  • SGaistS Offline
    SGaistS Offline
    SGaist
    Lifetime Qt Champion
    wrote on last edited by
    #2

    Hi and welcome to devnet,

    From the looks of it, I would guess that your network request has finished before your GUI is shown.

    Since you're not using QNetworkAccessManager, I would suggest to implement a slot that starts the request on demand.

    By the way, there's no need to add Q_INVOKABLE to your signals. You don't call them from external objects.

    Interested in AI ? www.idiap.ch
    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

    1 Reply Last reply
    2
    • V Offline
      V Offline
      Vana
      wrote on last edited by
      #3

      I do not use QNetworkAccessManager, but only Qt as a Gui app. The backend use another framework.

      I already start a slot into Qml like this :
      Signin.qml

          Button {
              id: send
              x: 280
              y: 257
              width: 61
              height: 25
              text: qsTr("Connect")
              onClicked:{
                  http.start_request("myapi.com", "443", "/login", 11, "POST", "username=" + login.text + "password=" + password.text);
              }
          }
      

      I import this component (Signin.qml )into main.qml like this :

      
          SwipeView {
              id: swipeView
              anchors.fill: parent
              currentIndex: tabBar.currentIndex
              visible: true
              Signin {
                  id: signin
              }
      }
      

      I already try to move connection into Signin.Qml but I have the same issue.

      Start_request slot do a shared_ptr :

      std::make_shared<request>(ioc, ctx)->run( );
      

      run function call function on_resolve, which call on_connect, which call on_handshake, which call on_write which call on_read, where is emitted the signal .

      1 Reply Last reply
      0
      • V Vana

        Hello,
        I do an HTTP request and get a response from it .
        I check the http code status and emit a signal to a qml component to call a slot.
        My goal is to do a simple login form, with api call. When user log in, the qml login form switch to qml index component.
        For that, onSignal, I would like to change visible value.

        request.h

        class request : public QObject, public std::enable_shared_from_this<request>
        {
            Q_OBJECT
        
        signals:
            Q_INVOKABLE void login();
        

        request.cpp

        void request::on_read(boost::system::error_code ec, std::size_t bytes_transferred)
        {
            boost::ignore_unused(bytes_transferred);
        
            if(ec)
                return fail(ec, "read");
        
            //TODO : Improve to get the user infos
            pt::ptree root;
            std::stringstream stringstream;
            stringstream << res.body();
            pt::read_json(stringstream, root);
        
            switch(res.result_int())
            {
            case 200:
                emit login(); //here the signal
                std::cout<<res.result_int()<<std::endl; //I see '200'
                break;
        

        main.cpp

        int main(int argc, char *argv[])
        {
            QGuiApplication app(argc, argv);
            QQmlApplicationEngine engine;
        
            boost::asio::io_context io_context;
            boost::asio::ssl::context ctx{ssl::context::sslv23_client};
            load_root_certificates(ctx);
            request request(io_context, ctx);
        
            engine.rootContext()->setContextProperty("http", &request);
        
            engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        
            return app.exec();
        }
        

        main.qml

        Window {
            visible: true
            width: 640
            height: 480
            title: qsTr("Chat ")
            
            Connections {
                target: http
                onLogin: {
                   console.log("login ok ! ") //Here I can't see signal
                }
            }
        
            Index {  
                id: chat
                visible: false
            }
        
        S Offline
        S Offline
        sharath
        wrote on last edited by sharath
        #4

        @Vana said in Signal from c++ to QML with setContextProperty:

        case 200:
        emit login(); //here the signal
        std::cout<<res.result_int()<<std::endl; //I see '200'

        Where you are calling this on_read(boost::system::error_code ec, std::size_t bytes_transferred) function. i think the control is not coming into this method. you just confirm whether the control is coming into this method by putting some logs.

        1 Reply Last reply
        0
        • V Offline
          V Offline
          Vana
          wrote on last edited by
          #5

          I call on_read(boost::system::error_code ec, std::size_t bytes_transferred) only from c++ side.

          Here the request class.cpp

          #include "request.h"
          #include <iostream>
          #include <boost/beast/http/verb.hpp>
          #include <boost/utility/string_view.hpp>
          
          request::request(boost::asio::io_context& ioc, ssl::context& ctx) : resolver(ioc) , stream(ioc, ctx)
          {
          }
          
          void request::fail(boost::system::error_code ec, char const* what)
          {
              std::cerr << what << ": " << ec.message() << "\n";
          }
          
          void request::run(char const* host, char const* port, char const* target, unsigned int version, QString method, QString body)
          {
              // Set up an HTTP GET request message
              http::verb method_verb;
              boost::string_view method_strview ;
              method_strview = method.toStdString();
              method_verb = boost::beast::http::string_to_verb(method_strview);
              req.version(version);
              req.method(method_verb);
              req.target(target);
              req.set(http::field::host, host);
              req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
              req.set(http::field::content_type, "application/x-www-form-urlencoded");
              req.body() = body.toStdString() ;
              req.prepare_payload();
          
              auto self = shared_from_this();
              resolver.async_resolve(host, port, [self](boost::system::error_code ec, tcp::resolver::results_type result)
                                                 {
                                                      self->on_resolve(ec, result);
                                                 });
           }
          
          void request::on_resolve(boost::system::error_code ec, tcp::resolver::results_type results)
          {
              if(ec)
              {
                  //return fail(ec, "resolve");
              }
              // Make the connection on the IP address we get from a lookup
              std::shared_ptr self = shared_from_this();
              boost::asio::async_connect(stream.next_layer(), results.begin(), results.end(), [self](boost::system::error_code ec, tcp::resolver::iterator)
                                                                                              {
                                                                                                  self->on_connect(ec);
                                                                                              });
          }
          
          void request::on_connect(boost::system::error_code ec)
          {
              if(ec){
                  //return fail(ec, "connect");
                  }
          
              // Perform the SSL handshake
              auto self = shared_from_this();
              stream.async_handshake(ssl::stream_base::client, [self](boost::system::error_code ec)
                                                               {
                                                                  self->on_handshake(ec);
                                                               });
          }
          
          void request::on_handshake(boost::system::error_code ec)
          {
              if(ec){
                  return fail(ec, "handshake");
              }
          
              // Send the HTTP request to the remote host
              auto self = shared_from_this();
              http::async_write(stream, req, [self](boost::system::error_code ec, std::size_t bytes_transferred)
                                             {
                                                  self->on_write(ec, bytes_transferred);
                                             });
          }
          
          void request::on_write(boost::system::error_code ec, std::size_t bytes_transferred)
          {
              boost::ignore_unused(bytes_transferred);
          
              if(ec)
                  return fail(ec, "write");
          
              // Receive the HTTP response
              auto self = shared_from_this();
              http::async_read(stream, buffer, res, [self](boost::system::error_code ec, std::size_t bytes_transferred)
                                                    {
                                                      self->on_read(ec, bytes_transferred); // Here the on_read() call
                                                    });
          }
          
          void request::on_read(boost::system::error_code ec, std::size_t bytes_transferred)
          {
              boost::ignore_unused(bytes_transferred);
          
              if(ec)
                  return fail(ec, "read");
          
              //TODO : Improve to get the user infos
              pt::ptree root;
              std::stringstream stringstream;
              stringstream << res.body();
              pt::read_json(stringstream, root);
          
              switch(res.result_int())
              {
              case 200:
                  emit login(); //Here the signal
                  std::cout<<res.result_int()<<std::endl; // I can see this
                  break;
              case 401:{
                  if (root.get<std::string>("message") ==  "wrong username"){
                      std::cout<<"Unknow User"<<std::endl;
                      emit wronglogin();
                      }
                  if (root.get<std::string>("message") ==  "wrong password"){
                      std::cout<<"Wrong password"<<std::endl;
                      emit wrongpassword();
                      }
                  }
                  break;
              }
          
              // Gracefully close the stream
               auto self = shared_from_this();
               stream.async_shutdown([self](boost::system::error_code ec)
                                     {
                                          self->on_shutdown(ec);
                                     });
          }
          
          void request::on_shutdown(boost::system::error_code ec)
          {
              if(ec == boost::asio::error::eof)
              {
                  ec.assign(0, ec.category());
              }
              if(ec)
                return fail(ec, "shutdown");
          }
          
          void request::start_request(QString host, QString port, QString target, unsigned int version, QString method, QString body)
          {
              boost::asio::io_context ioc;
              ssl::context ctx{ssl::context::sslv23_client};
          
              const char* std_host = host.toStdString().c_str();
              const char* std_port = port.toStdString().c_str();
              const char* std_target = target.toStdString().c_str();
              const char* std_method = method.toStdString().c_str();
              const char* std_body = body.toStdString().c_str();
          
              std::make_shared<request>(ioc, ctx)->run(std_host, std_port, std_target, version, std_method, std_body );
          
              ioc.run();
          }
          

          So from QML side, I do this into main.QML:

           Connections {
                  target: http
                  onLogin: {
                     console.log("login ok")
                  }
              }
          

          into Signin.qml i start the http request like this:

           Button {
                  id: send
                  x: 280
                  y: 257
                  width: 61
                  height: 25
                  text: qsTr("Connect")
                  onClicked:{
                      http.start_request("myapi", "443", "/login", 11, "POST", "username=" + login.text + "&password=" + password.text);
                  }
              }
          

          So I can not call on_read() from QML, I only need connect login signal from on_read to QML

          1 Reply Last reply
          0
          • dheerendraD Offline
            dheerendraD Offline
            dheerendra
            Qt Champions 2022
            wrote on last edited by dheerendra
            #6

            The way you have placed the code it should work. You are telling that it is not working. Issue can happen only if

            1. Signal is not emitted
            2. Connection is made after sending the signal
            3. Sender object & receiver objects are different
            4. Objects are destroyed before anything meaning full take place.

            Just ensure that your login() signal is indeed working, try to place the following in your main.cpp & see the login() signal is really working.

            request myrequest(io_context, ctx);
            QObject::connect(&myrequest,&request::login,[](){
                qDebug() << "Login Successfull" <<endl;
            });
            

            Dheerendra
            @Community Service
            Certified Qt Specialist
            http://www.pthinks.com

            1 Reply Last reply
            0
            • V Offline
              V Offline
              Vana
              wrote on last edited by
              #7

              I add this into main.cpp, and I see nothing, only "200" from std::cout<<res.result_int()<<std::endl;

              So the signal is not emitted ?

              1 Reply Last reply
              0
              • dheerendraD Offline
                dheerendraD Offline
                dheerendra
                Qt Champions 2022
                wrote on last edited by dheerendra
                #8

                It is as expected as signal is sent by some other object, we are connecting to different object. Now change your main.cpp to register object like the following. Then see what happens. Please change http->http1. This requires change in qml also from http->http1.

                request myrequest(io_context, ctx);
                engine.rootContext()->setContextProperty("http1", &myrequest);
                engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
                QObject::connect(&myrequest,&request::login,[](){
                    qDebug() << "Login Successfull" <<endl;
                });
                

                Dheerendra
                @Community Service
                Certified Qt Specialist
                http://www.pthinks.com

                1 Reply Last reply
                0
                • V Offline
                  V Offline
                  Vana
                  wrote on last edited by
                  #9

                  I change request to http1, still have issue.

                  Here all source for the concerned class:

                  1 Reply Last reply
                  0
                  • dheerendraD Offline
                    dheerendraD Offline
                    dheerendra
                    Qt Champions 2022
                    wrote on last edited by
                    #10

                    @dheerendra said in Signal from c++ to QML with setContextProperty:

                    qDebug() << "Login Successfull" <<endl;

                    Did the above debug message come ?

                    Dheerendra
                    @Community Service
                    Certified Qt Specialist
                    http://www.pthinks.com

                    1 Reply Last reply
                    0
                    • dheerendraD Offline
                      dheerendraD Offline
                      dheerendra
                      Qt Champions 2022
                      wrote on last edited by
                      #11

                      Following line is culprit for your issue.

                      std::make_shared<request>(ioc, ctx)->run(std_host, std_port, std_target, version, std_method, std_body );

                      Dheerendra
                      @Community Service
                      Certified Qt Specialist
                      http://www.pthinks.com

                      V 1 Reply Last reply
                      0
                      • dheerendraD dheerendra

                        Following line is culprit for your issue.

                        std::make_shared<request>(ioc, ctx)->run(std_host, std_port, std_target, version, std_method, std_body );

                        V Offline
                        V Offline
                        Vana
                        wrote on last edited by
                        #12

                        How I can fix this issue ?
                        create a pointer rather than a smartpointer ?

                        1 Reply Last reply
                        0

                        • Login

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