Qt与HTML通信在项目少量的使用还可以,大面积使用就比较麻烦,没有固定的模式接口。为了方便使用,封装了通信的库Qt端为QtWeb、HTML端为Cjax。
通信逻辑
QtWeb库
1、QtWeb库主要实现内容及功能:
- 提供WebView用于加载显示Html页面
- Html请求信号。收到前端请求后发出请求信号,信号中带有请求数据
- 请求超时处理。前端发送的请求,上层为及时处理回复则进行超时处理
- 主动推送消息到Html。提供notify接口,可主动推送消息到前端Html界面中
- 通信协议采用json格式。
2、QtWeb库的具体实现
QtWeb.h头文件
#ifndef QTWEB_H
#define QTWEB_H
#include <QWebView>
#include "json/json.h"
using namespace std;
class QtWeb : public QWebView
{
Q_OBJECT
public:
QtWeb(QWidget *parent);
~QtWeb();
public slots:
void dealLoadFinished(bool);
void dealRequest(QString jsonStr);
void registerJSObj();
int responseInterFace(QString url, int state, QString data, QString dataType = "json");
void webInterFace(QString url, QString dataType = "json", QString data = "");
void checkTimeout();
public:
void loadUrl(QString urlStr);
signals:
void msgLoadFinish(bool);
void msgSendRequest(QString, QString, QString);
void msgRecieveJsonError(int); //参数为请求的错误码
private:
QList<Json::Value> m_requestList;
};
#endif // QTWEB_H
QtWeb.cpp源文件
#include "qtweb.h"
#include <QWebPage>
#include <QWebFrame>
#include <QDate>
#include <qtimer.h>
QtWeb::QtWeb(QWidget *parent)
: QWebView(parent)
{
QTimer *checkTimer = new QTimer(this);
connect(checkTimer, SIGNAL(timeout()), this, SLOT(checkTimeout()));
checkTimer->start(1000);
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(dealLoadFinished(bool)));
connect(page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(registerJSObj()));
this->setStyleSheet(QString("QScrollBar::vertical{ background-color:rgb(54,80,79);margin:22px 0 22px 0;border:1px solid rgb(20,144,136);}\
QScrollBar::handle:vertical{ background-color:rgb(1,64,71);"));
}
QtWeb::~QtWeb()
{
}
//************************************
// Method: registerJSObj
// FullName: QtWeb::registerJSObj
// Access: public
// Returns: void
// Func: 槽函数 注册Qt的对象以便HTML可以使用
//************************************
void QtWeb::registerJSObj()
{
page()->mainFrame()->addToJavaScriptWindowObject(QString("QtWebObj"), this);
}
//************************************
// Method: loadUrl
// FullName: QtWeb::loadUrl
// Access: public
// Returns: void
// Func: 对上层提供自己添加HTML的方法
// Parameter: QString urlStr html所在路径
//************************************
void QtWeb::loadUrl(QString urlStr)
{
this->load(QUrl(urlStr));
}
//************************************
// Method: checkTimeout
// FullName: QtWeb::checkTimeout
// Access: public
// Returns: void
// Func: 定时器槽函数,定时检查请求是否处理超时,超时立即返回错误
//************************************
void QtWeb::checkTimeout()
{
if (m_requestList.empty())
return;
foreach(Json::Value oneItem, m_requestList)
{
if ((oneItem["timestamp"].asInt() + oneItem["timeout"].asInt()/1000) < QDateTime::currentDateTime().toTime_t())
{
responseInterFace(QString::fromStdString(oneItem["url"].asString()), 504, "error", "Text");
m_requestList.removeOne(oneItem);
}
}
}
//************************************
// Method: dealLoadFinished
// FullName: QtWeb::dealLoadFinished
// Access: public
// Returns: void
// Func: 加载html的槽函数,触发信号,上层可根据参数bSuccess判断加载HTML是否成功
// Parameter: bool bSuccess 代表加载html是否成功
//************************************
void QtWeb::dealLoadFinished(bool bSuccess)
{
emit msgLoadFinish(bSuccess);
}
//************************************
// Method: dealRequest
// FullName: QtWeb::dealRequest
// Access: public
// Returns: void
// Func: 处理JS端的请求,发出信号,由上层处理,不是对Qt端提供的接口。
// Parameter: QString jsonStr JS端传来的请求格式是json字符串
//************************************
void QtWeb::dealRequest(QString jsonStr)
{
Json::Reader reader;
Json::Value root;
if(reader.parse(jsonStr.toStdString().c_str(), root))
{ 不
root["timestamp"] = QDateTime::currentDateTime().toTime_t();
m_requestList.append(root);
string url = root["url"].asString();
string type = root["type"].asString();
string data = root["data"].asString();
emit msgSendRequest(QString::fromStdString(url), QString::fromStdString(data), QString::fromStdString(type));
}
else
emit msgRecieveJsonError(400);
}
//************************************
// Method: responseInterFace
// FullName: QtWeb::responseInterFace
// Access: public
// Returns: int 0代表响应请求成功 -1代表失败
// Func: 响应JS请求,将上层获取的数据传回HTML
// Parameter: QString url 指令
// Parameter: int state 状态码
// Parameter: QString data 返回数据
// Parameter: QString dataType 数据类型
//************************************
int QtWeb::responseInterFace(QString url, int state, QString data, QString dataType /* = "json" */)
{
int countNum = 0;
foreach(Json::Value oneItem, m_requestList)
{
if (QString::fromStdString(oneItem["url"].asString()) == url)
{
Json::Value item;
item["url"] = url.toStdString();
item["state"] = state;
item["datatype"] = dataType.toStdString();
item["data"] = data.toStdString();
string jsonStr = item.toStyledString();
page()->mainFrame()->evaluateJavaScript(QString("responseInterFace(%1)").arg(QString::fromLocal8Bit(jsonStr.c_str())));
m_requestList.removeOne(oneItem);
break;
}
else
countNum++;
}
if (countNum == m_requestList.length())
return -1;
return 0;
}
//************************************
// Method: webInterFace
// FullName: QtWeb::webInterFace
// Access: public
// Returns: void
// Func: Qt端主动推送信号或数据的接口
// Parameter: QString url 指令
// Parameter: QString dataType 数据类型
// Parameter: QString data 推送的数据
//************************************
void QtWeb::webInterFace(QString url, QString dataType /* = "json" */, QString data /* = "" */)
{
Json::Value item;
item["url"] = url.toStdString();
item["datatype"] = dataType.toStdString();
item["data"] = data.toStdString();
string jsonStr = item.toStyledString();
page()->mainFrame()->evaluateJavaScript(QString("webInterFace(%1)").arg(QString::fromLocal8Bit(jsonStr.c_str())));
}
HTML端CJAX的具体实现
在前端开发中与后台通信时经常会使用到AJax,Html与Qt的通信也模仿AJax的使用方法和逻辑实现了CJax,意为与C++的通信。显示的逻辑中主要用到了回调函数,向Qt端发送请求后的success函数和error函数都是采用回调函数实现,还有Qt端主动发送的Notify消息也是预先注册好回调函数进行处理。
1、CJax主要功能:
- 支持GET\POST\GO三个协议类型
- 对请求协议格式进行了封装。模仿AJax的格式进行封装,数据支持json\text\xml
- Notify消息预先注册,消息回调。
2、CJax插件的具体实现
cjax.js
/*****************************************************
*插件名称:CJAX
*创建时间:2016年11月04日
*创 建 人:EdwardYang
*插件功能描述:
* 提供Qt程序加载html界面显示时,html界面和Qt程序的交互功能
* html--->Qt 提供:
*
*********************************************************/
//保存所有未完成的请求数据对象
var requestBobyList = [];
//用于保存notify指令与回调函数的对应
var notifyCMDObjects= [];
/***************************************
*方法名称:CJax
*参 数 requestBody 请求数据对象
*功能描述:向Qt端发送request请求
requestBody对象格式:
{
url:"", //请求指令
type:"", //请求方式(Get、POST、GO)
timeout:3000, //请求超时时间
async:true, //请求回应方式
data:"", //请求数据,之后在POST的时候使用。数据为Json格式的字符串
success:, //请求成功后回调函数,函数原型function(data){}
error:, //请求失败时被调用的函数,函数原型function(errNo){}
}
向Qt发送请求json格式
{
}
**************************************/
var cjax = function(requestBody)
{
//将请求添加到请求列表中
requestBobyList.push(requestBody);
var paramObj = {};
paramObj.url = requestBody.url;
paramObj.type = requestBody.type;
paramObj.timeout = requestBody.timeout;
paramObj.data = requestBody.data;
var str = JSON.stringify(paramObj);
QtWebObj.dealRequest(str);
}
/*********************************************************
*方法名称:responseInterFace
*参 数:responseBody 请求返回数据 json格式
*功能说明:发送请求之后,Qt端返回的数据
{
"url":"", //请求指令
"state":200, //请求返回值
"datatype":"xml/json/text", //返回数据类型
"data":"" //返回数据
}
*********************************************************/
var responseInterFace = function(responseBody)
{
var url = responseBody.url;
for (var i = 0; i < requestBobyList.length; i++)
{
if(requestBobyList[i].url == url)
{
var callback;
if (responseBody.state != 200)
callback = requestBobyList[i].error;
else
callback = requestBobyList[i].success;
callback.call(this, responseBody.datatype, responseBody.data);
requestBobyList.splice(i, 1);
break;
}
}
}
/*********************************************************
*方法名称:webInterFace
*参 数:notifyObj Qt端推送过来的信息结构对象 callback指令对应的毁掉函数
*功能说明:Qt端主动推送消息通知接口
{
"url":"指令", //消息指令
"datatype":"xml/json/text", //数据类型
"data":"" //数据
}
***********************************************************/
var webInterFace = function(notifyObj)
{
var url = notifyObj.url;
for (var i = 0; i < notifyCMDObjects.length; i++)
{
if(notifyCMDObjects[i].notifyCmd == url)
{
var callback = notifyCMDObjects[i].func;
callback.call(this, notifyObj.datatype, notifyObj.data);
break;
}
}
}
/*********************************************************
*方法名称:insertNotifyCMDCallBack
*参 数:cmd 指令 callback 回调函数
*功能说明:保存所有QT端推送的指令和其对应的回调函数
***********************************************************/
var insertNotifyCMDCallBack = function(cmd, callback)
{
var cmdObject = {
notifyCmd:cmd,
func:callback
}
notifyCMDObjects.push(cmdObject);
}