开发者

Qt与QWebEngineView交互完整参考示例代码

开发者 https://www.devze.com 2024-08-14 12:45 出处:网络 作者: 莫固执,朋友
目录前言1:Qt的Web 引擎与 WebView交互历史变更2:示例展示3:项目注意事项3.1 :Qt WebEngine locales directory not found at location 错误3.2  运行时 崩溃例如:m_webView->page()->setWebChannel(
目录
  • 前言
  • 1:Qt的Web 引擎与 WebView交互历史变更
  • 2:示例展示
  • 3:项目注意事项
    • 3.1 :Qt WebEngine locales directory not found at location 错误
    • 3.2  运行时 崩溃例如:m_webView->page()->setWebChannel(m_webChannel);或者其他地方莫名崩溃
  • 总结

    前言

    最近刚好需要做一个Qt与Webview的交互,顺便写下整个的交互流程,给需要的各位参考学习。后面会补充,Qt上应用其他Web上的开源图标类的组件js库,例如EChart,vis.js等,通过 Qt+ +JavaScript+ QWebChannel +QWebEngineView 的组合,很多酷炫的效果都可以很方便的做出来。

    1:Qt的Web 引擎与 WebView交互历史变更

    Qt 5.6 引入了 Qt WebEngine 模块:

    在过去,Qt 使用的是 Qt WebKit 作为其 Web 引擎。但自 Qt 5.6 版本开始,Qt 引入了基于 Chromium 的新的 Web 引擎,称为 Qt WebEngine。这个改变带来了更好的性能、更好的 html5 和 css3 支持以及更好的安全性。

    QWebView 被 QWebEngineView 替代:

    在使用 Qt WebKit 时,开发者使用 QWebView 类来显示 Web 内容。但是随着 Qt WebEngine 的引入,Qt 引入了 QWebEngineView 类来取代 QWebView。QWebEngineView 基于新的 Web 引擎,并提供了更现代化的 API 和功能。

    引入了新的通信机制 - QWebChannel:

    在 Qt WebEngine 中,引入了 QWebChannel 作为一种新的机制,用于在 C++ 代码和 javascript 代码之间进行通信。通过 QWebChannel,可以将 C++ 对象暴露给 JavaScript,使得它们可以相互调用和交互。

    更好的扩展性和性能:

    由于 Qt WebEngine 基于 Chromium,因此具有更好的性能和扩展性。它可以使用 Chromium 提供的各种功能和特性,包括先进的渲染引擎、多线程支持、GPU 加速等。

    更新的 html5 和 CSS3 支持:

    Qt WebEngine 提供了更现代化的 HTML5 和 CSS3 支持,使得开发者可以更轻松地创建丰富、交互性强的 Web 应用程序。

    这些是 Qt 的 Web 引擎与 WebView 交互方面的一些主要变化。总的来说,随着 Qt WebEngine 的引入,Qt 在 Web 开发领域取得了重大进步,为开发者提供了更好的工具和功能来创建高性能的 Web 应用程序。

    2:示例展示

    示例是完整Qt代码和Html文件,可以直接测试,注释也写了一些

    通过QWebChannel进行注册和调用:

    这种方法是在Qt中注册QObject对象,使其可以在JavaScript中调用。使用QWebChannel类来建立Qt与JavaScript之间的通信桥梁。

    在Qt代码中,通过registerObject方法将QObject对象注册到QWebChannel中,然后在JavaScript中使用该对象。可以定义槽函数和属性,这些槽函数和属性可以在JavaScript中直接调用和访问。在JavaScript中调用这些槽函数来执行特定的操作,或者读取和设置属性。

    这种方法适用于在Web页面中需要与Qt代码进行交互的场景,需要从Web页面中触发特定操作,并且在Qt代码中执行相应的处理时,或者需要在Web页面中显示Qt代码中的数据时这样做很方便。

    如果想要简单的Qt调用JavaScript函数的话,就使用runJavaScript方法就行

    总的来说,如果需要频繁地进行 C++ 和 JavaScript 之间的通信,使用连接信号与槽会更加方便和高效。而如果只是偶尔需要执行一些 JavaScript 代码,使用 `runJavaScript` 也是一个不错的选择。

    #pragma once
    
    #include <QWidget>
    #include <QJsonObject>
    
    class QWebEngineView;
    class QWebChannel;
    
    class frmgplot : public QWidget
    {
    	Q_OBJECT
    	/*Q_PROPERTY 定义了一个名为 jsonData 的属性,
    	其类型为 QJsonObject,并将其与一个名为 qtjsonData 的成员变量关联起来。
    	当qtjsonData改变时,会自动触发qtdataChanged信号
    	要在类中声明好 信号(qtdataChanged) 和 成员(qtjsonData)
    	*/
    	Q_PROPERTY(QJsonObject jsonData MEMBER qtjsonData NOTIFY qtdataChanged)
    public:
    	frmgplot(QWidget *parent);
    	~frmgplot();
    
    	void initfrm();
    
    	void setQtjsonData(const QJsonObject & jsonData);
    
    public slots:
    	//js 调用qt函数,注意类型必须要是public slots:
    	void jscallQt(const QString &str);
    
    private slots:
    	void onPageLoadFinished(bool success);
    
    signals:
    	//当qtjso编程客栈nData改变时,会自动触发qtdataChanged信号
    	void qtdataChanged(const QJsonObject &jsonData);
    
    private:
    	QWebEngineView *m_webView;
    	QWebChannel *m_webChannel;
    	QJsonObject qtjsonData;
    };
    
    #include "frmgplot.h"
    #include <QWebEngineView>
    #include <QWebChannel>
    #include <QFileInfo>
    #include <QDir>
    #include <QApplication>
    #include <QvboxLayout>
    #include <qmessagebox.h>
    #include <QTimer>
    
    frmgplot::frmgplot(QWidget *parent)
    	: QWidget(parent)
    {
    	//拿到示例后,别忘了在合适的时候 初始化initfrm
    }
    
    frmgplot::~frmgplot()
    {
    }
    
    void frmgplot::initfrm()
    {
    	QVBoxLayout *layout = new QVBoxLayout(this);
    	setLayout(layout);
    
    	// 创建 Web 视图
    	m_webView = new QWebEngineView(this);
    	layout->addwidget(m_webView);
    
    	// 创建 Web 通道
    	m_webChannel = new QWebChannel(this);
    	// 注册到 Web 页面,使 JavaScript 能够调用 Qt类里面的 槽函数
    	m_webChannel->registerObject("frmplot", this);
    	m_webView->page()->setWebChannel(m_webChannel);//设备交互通道
    
    	// 加载 HTML 页面
    	QString filePath = QFileInfo(QApplication::applicationDirPath() + "/web/gplot/js/index.html").absoluteFilePath();
    
    	m_webView->load(QUrl::fromLocalFile(filePath));
    
    	// 连接信号槽以在通道初始化后调用 JavaScript 函数
    	connect(m_webView, &QWebEngineView::loadFinished, this, &frmgplot::onPageLoadFinished);
    }
    
    
    void frmgplot::onPageLoadFinished(bool success)
    {
    	if (success) {
    		// 页面加载完成后调用 JavaScript 函数
    		// 创建定时器,延迟3秒后执行
    		QTimer::singleShot(3000, this, [=]() {
    			// 页面加载完成后调用 JavaScript 函数
    			m_webView->page()->runJavaScript(QString("qtcalljsfunc('%1');").arg("qt call to js"));
    		});
    	}
    }
    
    void frmgplot::jscallQt(const QString &str)
    {
    	QMessageBox::warning(this, QString::fromLocal8Bit("title"), str);
    
    	/*示例:
    	js 调用 qt 后,
    	qt再次设置
    	属性jsonData 的qtjsonData成员,
    	让其改变 然后 触发信号qtdataChanged,从而让web 捕捉到qtdataChanged信号*/
    	QJsonObject json;
    	json["obj1"] = 1;
    	json["obj2"] = 666.666;
    	json["obj3"] = "this objstr";
    	this->setProperty("jsonData", json);
    	setQtjsonData(json);
    }
    
    void frmgplot::setQtjsonData(const QJsonObject &jsonData)
    {
    	//if (qtjsonData != jsonData)
    	{
    		qtjsonData = jsonData;//会自动触发qtdataChanged
    	}
    }
    <!doctype html>
    <html>
    <head>
      <title>Network</title>
      <script src="qwebchannel.js"></script> 
      <style type="text/css">
       #mynetwork {
          width: 80vw; /* 设置为全屏宽度的 80% */
          height: 80vh; /* 设置为全屏高度的 80% */
          border: 1px solid lightgray;
        }
        /* 设置 body 和 html 的宽度和高度为100%,以使 #mynetwork 占据整个屏幕 */
        body, html {
          width: 100%;
          height: 100%;
          margin: 0;
          padding: 0;
        }
      </style>
    </head>
    <body>
       <button id="jscallqtbutton">js call qt</button>
       /*定义一个按钮*/
    <p>
    </p>
    
    <div id="mynetwork"></div>
    
    <script type="text/javascript">
    
    //----------- webchannel qt js 交互
    
     var updatejson=function(text){	
    	// 使用JSON.stringify将QJsonObject转换为字符串,然后再输出
        alert(JSON.stringify(text));  
    }
    
     var webObject;
    
    // Connect to the QWebChannel
      new QWebChannel(qt.webChannelTransport, function(channel) {
    	webObject = channel.objects.frmplot;
    
    	window.foo = webObject;//对象赋值给了全局对象 window 的属性 foo
    
    	//qt信号{qtdataChanged}与js函数连接,就像 qt的信号槽一样
    	webObject.qtdataChanged.connect(updatejson);
    
    	// 1: web view -> qt :web上按钮(jscallqtbutton)按下后,调用qt函数jscallQt
    	document.gwww.devze.cometElementById("jscallqtbutton").onclick = function() {
    		webObject.jscallQt("jschttp://www.devze.comall-qt");
    		alert("jscallQt");
    	};
    
    	//2:qt -> web js 
    	// 示例:在页面上显示jsonData的内容
    	/* jsonDataDisplay = document.getElementById("jsonDataDisplay");
    	jsonDataDisplay.innerHTML = JSON.stringify(jsonData);*/
    			
    });
    //--------
    
     function qtcalljsfunc(text) {
    	alert((text)); 
    }
    
    </script>
    
    
    </body>
    </html>
    

    3:项目注意事项

    3.1 :Qt WebEngine locales directory not found at location 错误

    这个警告是因为 Qt WebEngine 在运行时需要一些 ICU 数据文件,这些文件通常位于 Qt android的安装目录中。警告消息显示 Qt WebEngine 在指定的目录下找不到 ICU 数据文件,因此它会尝试从其他位置加载

    在 Qt WebEngine 中,ICU 数据文件主要用于处理文字排版、文字渲染、国际化以及本地化等任务。因此,运行 Qt WebEngine 应用程序时,它会尝试加载这些 ICU 数据文件,以确保在不同地区和语言环境下能够正确地显示和处理文本。

    icudtl.dat 是 Qt 框架使用的 ICU(International Components for Unicode)数据文件之一。

    icudtl.dat 是在Qt的安装目录中的,在安装目录中搜索并且incudtl.dat和这些pak文件 复制到 执行文件相同层级目录下就可以了。*.pak 是 Qt WebEngine 中的资源文件,它们包含了用于支持开发者工具和其他功能所需的资源。注意拷贝时,要区分 对应版本 。

    Qt与QWebEngineView交互完整参考示例代码

    3.2  运行时 崩溃例如:m_webView->page()->setWebChannel(m_webChannel);或者其他地方莫名崩溃

      QtWebEngineProcess.exe 是 Qt WebEngine 模块的一个子进程,用于在 Qt 应用程序中执行 Web 页面的渲染和相关任务。通常情况下,QtWebEnginpythoneProcess.exe 被设计为与主应用程序(.exe 文件)放置在同一目录下,这是为了便于它与主应用程序之间共享资源和进行通信,否则会出现各种莫名崩溃问题

    总结

    到此这篇关于Qt与QWebEngineView交互的文章就介绍到这了,更多相关Qt与QWebEngineView交互内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号