上节讲到qt for android开发百度地图,已经可以打开地图了,里面的一些功能,如自定义搜索栏,添加控件等等,这些百度地图官方开发文档都提供了例子,可以自定义开发。但是问题也来了,我们开发百度地图,肯定要进行数据等交互。我们使用的是qt for android进行开发,要用qt交互共享单车地图的数据。
上图就是介绍用户请求扫码时服务器与客户端交互的流程,用户在地图上请求扫码骑行,要将信息传给qt,qt在把请求传递给服务器端,服务器端解析并做出相应的处理,将响应发送给qt,qt再把响应发送到地图上,根据响应显示给用户看。因为地图是采用html的网页,这就涉及到了C++与html的交互,接下来我就讲解C++与html的交互。
这也是卡了我很久,在网上查了一大堆的资料,查了一个星期,发现没有,只有一些模模糊糊的资料,还是残缺的,太难了。
C++(qt)与html(JS)的交互需要用哪些东西呢?想要直接交互是不可能的,因为qt并没有封装这个接口,需要自己写一个,以下是交互需要用到的,我来一个个进行讲解
(1)QWebSocketServer服务器为什么要用到服务器呢,因为C++(qt)想要直接与html(JS)直接交互,肯定行不通的,居然官方肯定直接给接口了。需要间接交互,通过QWebSocketServer服务器,C++(qt)和html(JS)作为客户端,连接QWebSocketServer服务器,QWebSocketServer服务器在对双方发送的消息分别进行派送。这样就能实现交互啦,代码如下所示
//以非安全模式,创建一个QWebSocketServer 实例作为html(js) 与 C++(qt) 的交互服务器
QWebSocketServer server(QStringLiteral("html(js) 与 C++(qt) 的交互服务器 "),
QWebSocketServer::NonSecureMode);
//监听本机端口12345
if (!server.listen(QHostAddress::LocalHost, 12345)) {
qFatal("Failed to open web socket server.");
return 1;
}
服务器有了,还需要客户端
(2)写一个WebSocketClientWrapper客户端的封装类WebSocketClientWrapper.h代码如下
#ifndef WEBSOCKETCLIENTWRAPPER_H
#define WEBSOCKETCLIENTWRAPPER_H
#include
#include
#include
class WebSocketClientWrapper : public QObject
{
Q_OBJECT
public:
WebSocketClientWrapper(QWebSocketServer *server, QObject *parent = nullptr);
signals:
void clientConnected(WebSocketTransport *client);
private slots:
void handleNewConnection();
private:
QWebSocketServer *m_server;
};
#endif // WEBSOCKETCLIENTWRAPPER_H
WebSocketClientWrapper.cpp代码如下
#include "websocketclientwrapper.h"
#include "websockettransport.h"
WebSocketClientWrapper::WebSocketClientWrapper(QWebSocketServer *server, QObject *parent)
: QObject(parent)
, m_server(server)
{
connect(m_server, &QWebSocketServer::newConnection,
this, &WebSocketClientWrapper::handleNewConnection);
}
void WebSocketClientWrapper::handleNewConnection()
{
//调用nextPendingConnection()接受一个挂起的TcpSocket连接,该函数返回一个指向QTcpSocket的指针,
//同时进入到QAbstractSocket::ConnectedState状态。这样就可以和客户端进行通信了。
emit clientConnected(new WebSocketTransport(m_server->nextPendingConnection()));
}
上面的代码什么意思呢?就是一个WebSocket客户端的封装,当监听到QWebSocketServer服务区有连接到来时,发送信号通知QWebChannel有连接到来,服务器因为需要与html交互,要与QWebChannel联合使用,下面会讲解为什么要QWebChannel
(2)QWebChannel从上述中我们知道,QWebSocketServer服务器是需要客户端进行交互的,对应的客户端是怎么写的呢,肯定是QWebSocket了。QT中确实要这个已经封装好的QWebSocket函数,我们可以直接创建一个实例即可,在HTML(js)用WebSocket了来连接服务器。
在官方的介绍中:C++与html(JS)的交互要使用到QtWebChannel模块,该模块提供了在QML/C++和HTML/Javascript之间的一个简单、易用的桥接,从而使得开发能够使用Qt和Web技术进行混合开发,目前QT官方也推荐是用QtWebChannel来桥接C++和HTML。
官方也考虑到了这个问题,采用了QT的特性,信号与槽机制,写了一个qwebchannel.js文件,我们只需要把这个文件放在与html的同一目录下,然后在html文件中引入即可。
在qt中需要设置一个QWebChannel的 实例channel,然后连接信号与槽,当clientWrapper监听到服务区有连接到来时,触发槽函数&QWebChannel::connectTo
// 设置QWebSocketServer
//QWebSocketServer::SslMode 是运行模式,有两种:安全模式(SecureMode)wss,非安全模式(NonSecureMode)ws,这里使用非安全模式构建
QWebSocketServer server(QStringLiteral("html(js) 与 C++(qt) 的交互服务器 "),
QWebSocketServer::NonSecureMode);
if (!server.listen(QHostAddress::LocalHost, 12345)) {
qFatal("Failed to open web socket server.");
return 1;
}
// 在QWebChannel AbstractTransport对象中包装WebSocket客户端
WebSocketClientWrapper clientWrapper(&server);
// 设置 channel
QWebChannel channel(nullptr);
QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected,
&channel, &QWebChannel::connectTo);
// 设置 networkInterface 并将其发布到QWebChannel
channel.registerObject(QStringLiteral("msg_interface"), networkInterface::getInstance());
注册一个类到channel中,名字为msg_interface让这个类与html通信
QWebChannel::connectTo函数原型如下,需要传入QWebChannelAbstractTransport类型的参数
void connectTo(QWebChannelAbstractTransport *transport);
这里我们需要重写QWebChannelAbstractTransport这个类
(3)重写QWebChannelAbstractTransport写一个WebSocketTransport类,继承QWebChannelAbstractTransport,重写基类的sendMessage函数,websockettransport.h代码如下:
#ifndef WEBSOCKETTRANSPORT_H
#define WEBSOCKETTRANSPORT_H
#include
#include
class WebSocketTransport : public QWebChannelAbstractTransport
{
Q_OBJECT
public:
explicit WebSocketTransport(QWebSocket *socket);
virtual ~WebSocketTransport();
void sendMessage(const QJsonObject &message) override;
private slots:
void textMessageReceived(const QString &message);
private:
QWebSocket *m_socket;
};
#endif // WEBSOCKETTRANSPORT_H
websockettransport.cpp代码如下:
#include "websockettransport.h"
#include
#include
#include
#include
/*
在内部使用QWebSocket的简要QWebSocket实现
传输将通过QWebSocket接收的所有消息委托给textMessageReceived信号。
类似地,对sendTextMessage的所有调用都将通过QWebSocket发送到远程客户端。
*/
/*
构造传输对象并包装给定的套接字。
套接字也被设置为传输对象的父对象。
*/
WebSocketTransport::WebSocketTransport(QWebSocket *socket): QWebChannelAbstractTransport(socket)
, m_socket(socket)
{
//
connect(m_socket, &QWebSocket::textMessageReceived,
this, &WebSocketTransport::textMessageReceived);
connect(m_socket, &QWebSocket::disconnected,
this, &WebSocketTransport::deleteLater);
}
/*
销毁 WebSocketTransport.
*/
WebSocketTransport::~WebSocketTransport()
{
m_socket->deleteLater();
}
/*
序列化JSON消息,并通过WebSocket将其作为文本消息发送到qt客户端。
*/
void WebSocketTransport::sendMessage(const QJsonObject &message)
{
QJsonDocument doc(message);
m_socket->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
}
/*
反序列化字符串化的JSON messageData并发出messageReceived。
*/
void WebSocketTransport::textMessageReceived(const QString &messageData)
{
QJsonParseError error;
QJsonDocument message = QJsonDocument::fromJson(messageData.toUtf8(), &error);
if (error.error) {
qWarning() << "Failed to parse text message as JSON object:" << messageData
<< "Error is:" << error.errorString();
return;
} else if (!message.isObject()) {
qWarning() << "Received JSON message that is not an object: " << messageData;
return;
}
//----------待续---------2022.5.3
}
代码主要处理socket客户端的消息和连接处理 ,然后发送给QWebChannel
(4)将qwebchannel.js文件引入html将qwebchannel.js文件引入html之后,使用js的WebSocket接口,创建一个WebSocket实例,连接本机的服务器,端口号为:12345,然后在WebSocket连接成功的js代码块中直接new 一个QWebChannel,然后监听注册的对象m_interface的信号即可,通过信号与html来交互,那么html怎么与m_interface交互呢,直接调用m_interface的槽函数即可。
到这里就讲完了,C++与html的交互有一些细节方面的讲不完,等后面有空在补充吧,觉得有用的,点个赞支持一下吧,对我的模拟共享单车开发感兴趣的,欢迎关注我查看哦!持续更新中
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)