首页 前端知识 Qt开发 | Qt Web混合编程 | VS2019 CMake编译CEF与QCefView| QWebEngineView的基本用法 | Qt与html js交互 | Qt与ECharts

Qt开发 | Qt Web混合编程 | VS2019 CMake编译CEF与QCefView| QWebEngineView的基本用法 | Qt与html js交互 | Qt与ECharts

2024-08-04 22:08:39 前端知识 前端哥 656 692 我要收藏

文章目录

  • 一、chrome技术介绍:CEF、QCefView、QWebEngineView
  • 二、VS2019 CMake编译CEF
  • 三、QWebEngineView基本用法
  • 四、VS2019 CMake QCefView编译
  • 五、QCefView使用教程
  • 六、C++ Qt与html js交互
  • 七、Qt与ECharts
    • 1.C++ Qt ECharts显示K线图
    • 2.C++ Qt ECharts数据交互动态修改

一、chrome技术介绍:CEF、QCefView、QWebEngineView

  在很多商业项目中,很多页面并不是用Qt来编写的,而是用Web网页编写,利用Qt将网页加载进来就可以显示界面。大多数web技术都是基于chrome,例如:CEF、QCefView、QWebEngineView,这些都是在native界面里用来显示html网页,并且可以与web交互,例如:常见的登陆窗口、优酷的视频区域、WPS的稻城商城,这些都是用web技术实现的,而native端(客户端),只需要把网页展示出来,实现交互即可。

WPS、优酷、MindMaster等软件的安装目录里都有libcef.dll库文件

  • CEF(Chromium Embedded Framework)

    CEF是一个开源项目,由Marshall Greenblatt在2008年成立,基于Google Chromium项目。它允许开发者将Web browser功能嵌入到他们的应用程序中。CEF支持多种编程语言和操作系统,并且可以轻松集成到新旧应用程序中。它提供了丰富的API,允许应用程序与浏览器之间进行紧密集成,包括自定义插件、协议、JavaScript对象和扩展。CEF的设计注重效率和易用性,提供了C/C++接口,并通过原生库与Chromium和WebKit隔离开来。

  • QCefView

    QCefView是一个集成了CEF的Qt第三方开源库,采用LGPL许可,可以在项目中免费使用。它提供了C++和Web交互的能力,类似于CEF和QWebEngineView的功能。QCefView允许开发者在Qt项目中使用CEF,而无需直接编写与CEF相关的代码。它是一个跨平台的解决方案,可以在不同的操作系统上工作,并且提供了与Qt Widgets相似的使用体验。

    • QCefView介绍
  • QWebEngineView

    QWebEngineView是Qt框架中的一个组件,它基于Chromium内核的Web浏览器引擎,用于在Qt应用程序中嵌入网页内容和实现各种Web应用功能。QWebEngineView支持HTML5、CSS3、JavaScript等现代Web技术,允许开发者在本地桌面应用程序中轻松地集成网页浏览功能。QWebEngineView提供了丰富的API,包括加载网页、与JavaScript交互、监听网页加载事件等。它还支持在Qt Quick中通过QQuickWebEngineView在QML场景中嵌入Web内容。

二、VS2019 CMake编译CEF

  • CEF下载链接(已经编译好):https://cef-builds.spotifycdn.com/index.html

    image-20240705192846047

  • CEF仓库:https://bitbucket.org/chromiumembedded/cef/src/master/

    image-20240705192923882

  • QCefView:https://github.com/CefView

  首先,下载源码并解压。

  将文件夹改名为cef102_x64,并移动到D盘

image-20240705202121081

  在cef102_x64文件夹下新建目录

  • build_vs2019_x64:用于存放编译生成文件
  • cef102_x64_sdk:用于存放提取的SDK,包括头文件与动态库

image-20240705202249944

  打开CMake,对CMake进行如下配置;配置完成后点击“Finish”。

image-20240705202506177

  安装目录选择如下,更改后,再点击“Generate”。

image-20240705202603956

  点击”Open Project“会在VS2019中打开,或者可以点击“cef.sln”来打开。

image-20240705202640686

  在VS2019中点击“生成解决方案”。

image-20240705202902421

  点击“视图–>错误列表”可查看编译器错误。

image-20240705203029253

  修改后,点击重新生成解决方案。

image-20240705203234217

image-20240705203410609

生成的静态库如下:

image-20240705203643370

三、QWebEngineView基本用法

  QWebEngineView是Qt框架中的一个组件,用于在Qt应用程序中嵌入网页内容和实现各种Web应用功能。

  • 创建 QWebEngineView 实例

    QWebEngineView *view = new QWebEngineView(parent);
    
  • 加载网页: 使用 load 方法加载一个 URL:

    view->load(QUrl("http://www.baidu.com"));
    //或者
    view->setUrl(QUrl("http://www.baidu.com"));
    
  • 显示视图: 将 QWebEngineView 作为窗口或控件显示:

    view->show();
    
  • 网页导航

    • 后退view->back();
    • 前进view->forward();
    • 刷新view->reload();
    • 停止加载view->stop();
  • 获取当前 URL

    QString currentUrl = view->url().toString();
    
  • 设置新页面: 可以为 QWebEngineView 设置一个新页面:

    QWebEnginePage *newPage = new QWebEnginePage(this);
    view->setPage(newPage);
    
  • 监听加载完成: 通过信号 loadFinished 监听网页加载完成的事件:

    connect(view, &QWebEngineView::loadFinished, [&](bool ok){
        if (ok) {
            qDebug("加载成功");
        } else {
            qDebug("加载失败");
        }
    });
    
  • 执行 JavaScript: 在页面加载完成后执行 JavaScript 代码:

    view->page()->runJavaScript("console.log('Hello, World!');");
    
  • 设置网页标题: 可以设置 QWebEngineView 的标题,这通常反映当前加载页面的标题:

    view->setWindowTitle("我的网页浏览器");
    

四、VS2019 CMake QCefView编译

  • QCefView官网:https://cefview.github.io/QCefView/
  • Github地址:https://github.com/CefView/QCefView

编译操作

  1. 下载克隆代码

      QCefView是Qt对CEF的封装,编译时需要依赖CEF。虽然QCefView工程里有CefViewCore目录,但是是空的,需要手动clone CefViewCore的代码,然后放到QCefView工程里。

    git clone https://github.com/CefView/QCefView.git
    git clone https://github.com/CefView/CefViewCore.git
    

    image-20240706123239208

  2. 修改CEF配置文件

    在编译前,需要做一些配置修改,由于QCefView依赖于CEF,在使用CMake配置项目时,会在线下载CEF工程,如果没有很好的网络环境,可能无法下载CEF二进制包,对于此问题,可以手动下载CEF二进制包,放到指定目录即可。

    打开D:\QCefView\CefViewCore\CefConfig.cmake,查看cef版本,如:

    image-20240706141955310

    # Current version
    "95.7.12+g99c4ac0+chromium-95.0.4638.54"
    

    注释掉下面一句话,意思是如果不存在cef二进制包的话,去这个网址下载

    image-20240706142139113

    可以科学上网去访问:https://cef-builds.spotifycdn.com/cef_binary_95.7.12+g99c4ac0+chromium-95.0.4638.54_windows64.tar.bz2来下载压缩包,然后直接解压放到D:\QCefView\CefViewCore\dep目录下,结果如下:

    image-20240706143237408

    此外,需要打开D:\QCefView\QtConfig.cmake配置文件,修改Qt路径如下:

    image-20240706143437344

    添加系统环境变量QT_SDK_DIR

    image-20240706143748175

    打开 cmd 软件 输入 qmake -query 如果出现的是 msvc_2019 则说明qt 的配置环境正确

    image-20240706144016101

  3. 用cmake进行编译

    • 在QCefView根目录下创建两个文件夹,如:build_vs2019_x64目录和QCefViewSdk_x64目录,

      • build_vs2019_x64目录:将Cmake产生的vs sln解决方案放到该目录下
      • QCefViewSdk_x64目录:SDK目录

      image-20240706145209232

    • 打开CMake开始配置,编译x64版本

      image-20240706145403142

      点击“Finish“后,进行如下修改:

      • 勾选【BUILD_DEMO】可以同时编译生成cef的示例程序
      • 修改编译后的安装路径【CMAKE_INSTALL_PREFIX】

      Snipaste_2024-07-06_14-59-35

      点击【Configure】->【Generate】->【Open Project】,自动打开VS;

      用vs2019打开项目后,需要调整Qt版本

      image-20240706150948526

      点击“生成解决方案”。

      image-20240706151208944

      提取SDK,包含头文件、静态库与动态库。

      右击“INSTALL”->“仅用于项目“->”仅生成INSTALL“

      image-20240706151332239

      image-20240706151559771

      image-20240706151619218

  4. 入门示例

    对入门示例设为启动代码进行编译运行

    image-20240706152719199

    若QCefView的Qt dll版本和电脑版本不一致,会导致链接错误,需去电脑安装位置把dll copy过来即可。3个必备的core、gui、widgets

参考:https://blog.csdn.net/m0_37251750/article/details/126508912?ops_request_misc=%7B%22request%5Fid%22%3A%22172023942916800186593833%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fall.%22%7D&request_id=172023942916800186593833&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-126508912-null-null.142v100control&utm_term=Qt网络篇:QCefView入门及环境配置&spm=1018.2226.3001.4187

五、QCefView使用教程

  通过复现QCerView Test来学习其使用。首先,使用VS2019创建Qt x64项目,

image-20240706153858339

image-20240706154013007

代码编写步骤

  • 将QCefView SDK copy到项目中,右键项目属性进行配置,include、lib、bin

    image-20240706154148721

    include:右击“属性”,配置属性,点击“C/C++”->“常规”,在“附加包含目录”中添加头文件目录

    image-20240706154646257

    lib:右键“属性”,配置属性,点击“链接器”–>“常规”,在“附加库目录”中添加库文件目录

    image-20240706155009016

    点击“链接器”–>“输入”,在“附加依赖项”中添加lib库名称

    image-20240706155246014

    点击“确定”–>“应用“,项目属性配置完成

  • copy QCefView 提供的代码,窗口和main函数代码

  • copy QCefView Qt设计器布局

  • 调整CefViewWidget.h的头文件

  • 调整代码

  • 解决编译错误

    image-20240706160638435

    无法链接的错误:要么是lib未链接,lib名或路径写错了,要么就是虚函数未实现。

    编译错误的具体原因:

      QCefView将CefViewWidget类分为两个地方实现,代码少copy了一些,虚函数未链接,编译失败。

六、C++ Qt与html js交互

  除了可以显示网页,还可以和网页交互,互相发消息,调用函数。

  • html页面调用C++函数,在c++.h里声明

    //接收来自html发来的内容,必须要加Q_INVOKABLE,不然收不到
    Q_INVOKABLE void receiveTextFromHtml(const QString& r_text);
    
  • C++发送内容给html,html链接

    //index.html文件中
    //响应Qt的信号sendText,接收来自Qt发送的内容message,在html上显示
    content.sig_sendTextToHtml.connect(function(message) {
        output("接收到来自Qt的文本: " + message);
    });
    
  • Qt与html js的桥梁 QWebChannel

    QWebEnginePage* pPage = ui.webEngineView->page();
    QWebChannel* channel = new QWebChannel(this);
    
    //注册html对象
    channel->registerObject(QStringLiteral("content"), m_pWebObj); //第二个参数需要是QObject的派生类
    pPage->setWebChannel(channel);
    
    connect(m_pWebObj, &WebObject::sig_SendToUI, this, &QtWebDemo::update_text);
    

    registerObject类似于反射机制,qwebchannel.js可以从m_pWebObj里面反射出想要执行的Qt函数

注意:不能缺少qwebchannel.js文件qwebchannel.js 是一个与 Qt WebChannel 相关的 JavaScript 文件,它是 Qt 框架的一部分,用于实现 Web 应用与 Qt 应用程序之间的通信。Qt WebChannel 允许你将 Qt 应用程序的 C++ 对象暴露给 JavaScript,从而可以在 Web 页面上调用这些对象的方法。

示例:

index.js

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script type="text/javascript" src="./qwebchannel.js"></script>
        <script type="text/javascript">
            
            function output(message)
            {
                var output = document.getElementById("output");
                output.innerHTML = output.innerHTML + message + "\n";
            }
			
            window.onload = function() {
            output("我是html页面,我可以在Qt界面上显示");
            new QWebChannel(qt.webChannelTransport, function(channel) {
                
				//这个对象很重要,需要在C++ Qt中注册
                var content = channel.objects.content;

				//用dom获取"发送"按钮
                document.getElementById("send").onclick = function() {
                    var input = document.getElementById("input");
                    var text = input.value; //获取input编辑框的值
                    if (!text) {
                        return;
                    }

                    output("发送内容给自己: " + text);
                    input.value = "";
					
					//Qt对象接收html发送过来的消息,可以在Qt界面上显示
					content.receiveTextFromHtml("接收到来自html的文本:" + text);
                }
				
				//响应Qt的信号sendText,接收来自Qt发送的内容message,在html上显示
				content.sig_sendTextToHtml.connect(function(message) {
                    output("接收到来自Qt的文本: " + message);
                });
            });
            }

        </script>
        <style type="text/css">
            html {
                height: 100%;
                width: 100%;
            }
            #input {
                width: 400px;
                margin: 0 10px 0 0;
            }
            #send {
                width: 90px;
                margin: 0;
            }
            #output {
                width: 500px;
                height: 300px;
            }
        </style>
    </head>
    <body>
        <textarea id="output"></textarea><br />
        <input id="input" /><input type="submit" id="send" value="发送" onclick="javascript:click();" />
    </body>
</html>

ui文件

image-20240706174235605

WebObject.h

#pragma once

#include <QObject>

class WebObject : public QObject
{
	Q_OBJECT

public:
	WebObject(QObject* parent = nullptr) :QObject(parent) {}
	~WebObject();

	void SendTextToHtml(const QString& text);

	//接收来自html发来的内容,必须要加Q_INVOKABLE,不然收不到
	Q_INVOKABLE void receiveTextFromHtml(const QString& r_text);

signals:
	void sig_sendTextToHtml(const QString& text);
	void sig_SendToUI(const QString& htmltext);
};

WebObject.cpp

#include "WebObject.h"

WebObject::~WebObject()
{
}

void WebObject::SendTextToHtml(const QString& text)
{
	emit sig_sendTextToHtml(text);
}

void WebObject::receiveTextFromHtml(const QString& htmltext)
{
	emit sig_SendToUI(htmltext);
}

QtWebDemo.h

#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtWebDemo.h"
#include "WebObject.h"

class QtWebDemo : public QWidget
{
    Q_OBJECT

public:
    QtWebDemo(QWidget *parent = Q_NULLPTR);
    ~QtWebDemo();

public slots:
    void on_btnSend_clicked();
    void update_text(const QString& htmltext);

private:
    Ui::QtWebDemoClass ui;

    WebObject* m_pWebObj = nullptr;
};

QtWebDemo.cpp

#include "QtWebDemo.h"
#include <QWebChannel>
#include <QWebEnginePage>

QtWebDemo::QtWebDemo(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    QString path = QApplication::applicationDirPath() + "/WebPage/index.html";
    ui.webEngineView->setUrl(QUrl(path));

    m_pWebObj = new WebObject();

    QWebEnginePage* pPage = ui.webEngineView->page();
    QWebChannel* channel = new QWebChannel(this);

    //注册html对象
    channel->registerObject(QStringLiteral("content"), m_pWebObj); //第二个参数需要是QObject的派生类
    pPage->setWebChannel(channel);

    connect(m_pWebObj, &WebObject::sig_SendToUI, this, &QtWebDemo::update_text);
}

void QtWebDemo::on_btnSend_clicked()
{
    QString text = ui.lineEdit->text();
    m_pWebObj->SendTextToHtml(text);
}

QtWebDemo::~QtWebDemo()
{
    delete m_pWebObj;
}

void QtWebDemo::update_text(const QString& htmltext)
{
    ui.plainTextEdit->appendPlainText(htmltext);
}

main.cpp

#include "QtWebDemo.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtWebDemo w;
    w.show();
    return a.exec();
}

运行结果

image-20240706174530170

七、Qt与ECharts

  ECharts是比QCustomPlot、QWT、QCharts更好的开源图标曲线组件。

ECharts(Enterprise Charts)是一个由百度团队开发的开源可视化库,它基于 JavaScript 和 HTML5 的 Canvas 元素,提供了丰富的图表类型,非常适合用于数据可视化。ECharts 以其强大的功能、灵活的定制性、以及优雅的交互体验而广受开发者和数据分析师的欢迎。

Qt如何使用ECharts

  • 选择示例,点击相应示例,下载html代码

    ECharts网址:https://echarts.apache.org/examples/zh/index.html#chart-type-map

    image-20240706175609923

  • 选择下载,点击“在线定制”

    image-20240706175843428

  • 点击“下载”,编译产生js

    image-20240706175909849

  • 使用QWebEngineView调用echarts html

    QString _klinePath = exe_path + "/myecharts/candlestick-sh.html";
    ui->web_widget->setUrl(QUrl(_klinePath));
    
  • C++ Qt如何动态设置Echarts数据

    利用runJavaScript函数,该函数提供了在 Web 引擎页面上运行 JavaScript 代码的方法

    void runJavaScript(const QString& scriptSource);
    void runJavaScript(const QString& scriptSource, quint32 worldId);
    void runJavaScript(const QString& scriptSource, const QWebEngineCallback<const QVariant &> &resultCallback);
    void runJavaScript(const QString& scriptSource, quint32 worldId, const QWebEngineCallback<const QVariant &> &resultCallback);
    

1.C++ Qt ECharts显示K线图

示例:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QString exe_path = qApp->applicationDirPath();
    QString _klinePath = exe_path + "/myecharts/candlestick-simple.html";
    // qDebug() << _klinePath;
    ui->web_widget->setUrl(QUrl(_klinePath));

    connect(ui->radioButton_kline, &QRadioButton::toggled, [=](bool checked){
        if(checked)
        {
            ui->web_widget->setUrl(QUrl(_klinePath));
        }
    });

    connect(ui->radioButton_line, &QRadioButton::toggled, [=](bool checked){
        if(checked)
        {
            QString _linePath = exe_path + "/myecharts/line-smooth.html";
            ui->web_widget->setUrl(QUrl(_linePath));
        }
    });
}

Widget::~Widget()
{
    delete ui;
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

运行结果

image-20240706182043223

2.C++ Qt ECharts数据交互动态修改

示例:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    void on_btnDefault_clicked();
    void on_btnReDefine_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QString path = qApp->applicationDirPath() + "/echarts/line-simple.html";
    ui->widget->setUrl(QUrl(path));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btnDefault_clicked()
{
    ui->widget->page()->runJavaScript("init()");
}

void Widget::on_btnReDefine_clicked()
{
    QJsonObject seriesData;

    //设置x轴数据
    QJsonArray dataX = {1, 5, 10, 15, 20, 25, 30, 35, 40};
    seriesData.insert("data_xAxis", dataX);

    //设置y轴数据
    QJsonArray dataY = {100, 70, 1230, 110, 50, 890, 79, 128, 256};
    seriesData.insert("data_yAxis", dataY);

    QString optionStr = QJsonDocument(seriesData).toJson();
    QString js = QString("load_data(%1)").arg(optionStr);

    //C++调用js方法
    ui->widget->page()->runJavaScript(js);
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
转载请注明出处或者链接地址:https://www.qianduange.cn//article/14805.html
评论
发布的文章

安装Nodejs后,npm无法使用

2024-11-30 11:11:38

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!