Я посылаю сигнал из 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()
}
}