сигнал c ++ для QML с подключением - PullRequest
0 голосов
/ 21 мая 2018

Я посылаю сигнал из c ++ и пытаюсь вызвать слот из QML.Я использую Setcontextproperty и Connection:

main.qml

import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3

Window {
 visible: true
 width: 640
 height: 480

 Index {
    id: chat
    visible: false
  }

  SwipeView {
    id: swipeView
    anchors.fill: parent
    currentIndex: tabBar.currentIndex

    Signin {
        id: signin
    }

 }

TabBar {
        id: tabBar
        x: 274
        y: 123
        currentIndex: swipeView.currentIndex

        TabButton {
            text: qsTr("Login")
        }
  }

}

Signin.qml

    Button {
    id: send
    x: 280
    y: 257
    width: 61
    height: 25
    text: qsTr("Connect")
    Connections {
        target: http
        onLogin : console.log("test200");
    }

    onClicked:{
        http.start_request("/login", "443", "/", 11, "POST", "username=" + login.text + "&password=" + password.text)
       }

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

#include "request.h"

#include <QDebug>
#include <QObject>
#include <QQuickItem>
#include <QQmlContext>


boost::asio::io_service io_service;

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

QGuiApplication app(argc, argv);

QQmlApplicationEngine engine;


std::string login = "allo";

boost::asio::io_context ioc;
boost::asio::ssl::context ctx{ssl::context::sslv23_client};
request request(ioc, ctx);


engine.rootContext()->setContextProperty("tcp_client", &c);
engine.rootContext()->setContextProperty("http", &request);

engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

);

return app.exec();
}

request.h

#ifndef REQUEST_H
#define REQUEST_H

#include <QString>
#include "hash_password.h"
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <QObject>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

using tcp = boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
namespace http = boost::beast::http;
namespace pt = boost::property_tree;

class request : public QObject, public std::enable_shared_from_this<request>
{
Q_OBJECT

signals:
 void login();

public:
explicit request(boost::asio::io_context& ioc, boost::asio::ssl::context& ctx);
void run(char const* host, char const* port, char const* target, int version, QString method, QString body = NULL);
Q_INVOKABLE void start_request( QString host, QString port, QString target, int version, QString method, QString body = NULL);
std::string respond;
QString GetmessageError;

private:
hash_password hashed_password;
tcp::resolver resolver;
boost::asio::ssl::stream<tcp::socket> stream;
boost::beast::flat_buffer buffer;
boost::beast::http::request<http::string_body> req;
boost::beast::http::response<http::string_body> res;

void on_resolve(boost::system::error_code ec, boost::asio::ip::tcp::resolver::results_type results);
void on_connect(boost::system::error_code ec);
void on_handshake(boost::system::error_code ec);
void on_write(boost::system::error_code ec, std::size_t bytes_transferred);
void on_read(boost::system::error_code ec, std::size_t bytes_transferred);
void on_shutdown(boost::system::error_code ec);
void fail(boost::system::error_code ec, char const* what);

//json_parser Jsonresponse;
std::string GetApiResponse(std::stringstream Jsonres, pt::ptree root);

};

#endif // REQUEST_H

request.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, int version, QString method, QString body)
{
 // Set SNI Hostname (many hosts need this to handshake successfully)
 if(! SSL_set_tlsext_host_name(stream.native_handle(), host))
 {
    boost::system::error_code ec{static_cast<int>(::ERR_get_error()), 
  boost::asio::error::get_ssl_category()};
    std::cerr << ec.message() << "\n";
    respond = "test" ;
    return;
 }

// 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();

// Look up the domain name
resolver.async_resolve(host, port, std::bind(&request::on_resolve, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
 }

void request::on_resolve(boost::system::error_code ec, tcp::resolver::results_type results)
{
 if(ec){
    //return fail(ec, "resolve");
    respond = "test" ;
}
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(stream.next_layer(), results.begin(), 
results.end(), std::bind( &request::on_connect, shared_from_this(), std::placeholders::_1));
 }

void request::on_connect(boost::system::error_code ec)
{
 if(ec){
    //return fail(ec, "connect");
     respond = ec.message();
    }

 // Perform the SSL handshake
 stream.async_handshake(ssl::stream_base::client, std::bind(&request::on_handshake, shared_from_this(), std::placeholders::_1));
  }

  void request::on_handshake(boost::system::error_code ec)
  {
  if(ec){
    return fail(ec, "handshake");
  }

 // Send the HTTP request to the remote host
 http::async_write(stream, req, std::bind(&request::on_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
 }

 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
 http::async_read(stream, buffer, res, std::bind(&request::on_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
  }

  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");

   if(res.result_int() == 200)
   {
   std::cout<<res.result_int()<<std::endl;
   emit login();
   }

   else
    std::cout<<"allola"<<std::endl;


// Gracefully close the stream
  stream.async_shutdown(std::bind(&request::on_shutdown, shared_from_this(), std::placeholders::_1));
  }

  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");

  // If we get here then the connection is closed gracefully
  }

  void request::start_request(QString host, QString port, QString target, 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();
  }

  std::string request::GetApiResponse(std::stringstream Jsonres, pt::ptree root)
 {
  pt::read_json(Jsonres, root);
  std::cout<<root.get<std::string>("user.permission")<<std::endl;
  return root.get<std::string>("user.permission");
 }

Я вижу http-запрос (из журналов), вижу cout "200" из c ++ в request.cppно не ответ от qml, console.log ("test200").

Так что не так?

Обновление: минимальный пример с той же проблемой main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "request.h"
#include <QQmlContext>

int main(int argc, char *argv[])
{
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

  QGuiApplication app(argc, argv);

  QQmlApplicationEngine engine;
  request request;
  engine.rootContext()->setContextProperty("http", &request);
  engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

  if (engine.rootObjects().isEmpty())
    return -1;

  return app.exec();
 }

request.h

#ifndef REQUEST_H
#define REQUEST_H

#include <QObject>

class request : public QObject
{
  Q_OBJECT

 public:
 request();

 signals:
 void connection();

 public:
 Q_INVOKABLE void start();
 };

  #endif // REQUEST_H

request.cpp

#include "request.h"
#include <iostream>

request::request()
{
}

void request::start()
{
  for(int i=0; i<10; i++)
    std::cout<<"Hello World from c++"<<std::endl;
  emit connection();
}

main.qml

import QtQuick 2.0
import QtQuick.Controls 2.3

ApplicationWindow {
width: 640
height: 480

Connections {
    target: http
    onConnection: console.log("Hello from QML");
}

Button {
    id: button
    x: 251
    y: 258
    text: qsTr("Button")
    onClicked: http.start()
}
}
...