Qt使用QWebChannel与QWebEngineView内嵌Html交互
Qt通过QWebEngineView渲染html页面,可以通过QWebChannel结合javascript与html交互
其中需要2个js文件,一个jquery文件,如果javascript学得好可以不要,一个是qt提供的qwebchannel.js
先看效果图
根据qtmarkdown示例做的, 列表使用了自定义类Student,本来想通过自定义QType做交互,但没实现,获取到的数据为null,后该为了QJsonObject,
首先学生类,其实就是一个简单的c++类#ifndef STUDENT_H #define STUDENT_H #include #include // Creating a Custom Type // Before we begin, we need to ensure that the custom type we are creating meets all the requirements imposed by QMetaType. In other words, it must provide: // a public default constructor, // a public copy constructor, and // a public destructor. // 使用Q_PROPERTY 还需要提供一个!=重载以及一个赋值=重载 // The class in Qt responsible for custom types is QMetaType. // To make the type known to this class, we invoke the Q_DECLARE_METATYPE() macro // on the class in the header file where it is defined: // Q_DECLARE_METATYPE(Student); // To enable creation of objects at run-time, // call the qRegisterMetaType() template function to register // it with the meta-object system. // qRegisterMetaType("Student"); class Student { public: Student() = default; // 默认构造函数 Student(const QString& name, int age, const QString& tel); ~Student() = default; // 默认析构函数 Student(const Student&); // 拷贝构造函数 Student& operator=(const Student&); // 赋值重载 bool operator!=(const Student&); QString getName() const; int getAge() const; QString getTel() const; private: QString m_Name; int m_Age; QString m_Tel; }; Q_DECLARE_METATYPE(Student); #endif // STUDENT_H
实现#include "student.h" Student::Student(const QString &name, int age, const QString &tel) : m_Name(name) , m_Age(age) , m_Tel(tel) { } Student::Student(const Student& lt) { this->m_Name = lt.m_Name; this->m_Age = lt.m_Age; this->m_Tel = lt.m_Tel; } Student& Student::operator=(const Student& lt) { if (this != <) { this->m_Name = lt.m_Name; this->m_Age = lt.m_Age; this->m_Tel = lt.m_Tel; } return *this; } bool Student::operator!=(const Student& lt) { // 只比较name if (m_Name == lt.m_Name) { return false; } return true; } QString Student::getName() const { return m_Name; } int Student::getAge() const { return m_Age; } QString Student::getTel() const { return m_Tel; }
最重要的是通信类, 这里有点绕,需要理解信号与槽#ifndef USERDOCUMENT_H #define USERDOCUMENT_H #include #include #include #include "student.h" class UserDocument : public QObject { Q_OBJECT Q_PROPERTY(QString title MEMBER m_title NOTIFY titleChangedFromQt FINAL) Q_PROPERTY(QJsonObject jsonStudent MEMBER m_jsonStudent NOTIFY studentChangedFromQt FINAL) public: UserDocument(QObject* parent = nullptr) : QObject(parent) {} // 设置标题并发送titleChangedFromQt void setTitle(const QString& title); // 设置学生类并发送studentChangedFromQt void setStudent(const Student& student); Student getStudent() const; signals: // qt端发送信号给web端同步修改标题 void titleChangedFromQt(const QString& title); // qt端发送信号给web端同修改学生 void studentChangedFromQt(const QJsonObject& jsonStudent); // 当web端发送titleChangeFromWeb后同步修改qt端标题 void titleChangedForQt(const QString& title); // 当web端发送studentChangedFromWeb后同步修改qt端学生 void studentChangedForQt(const Student& student); public slots: // web端发送给qt端同步修改标题 void titleChangeFromWeb(const QString& title); // web端发送给qt端同步修改学生 void studentChangedFromWeb(const QJsonObject& jsonStudent); private: QString m_title; Student m_student; QJsonObject m_jsonStudent; QRect m_rect; }; #endif // USERDOCUMENT_H
实现#include "userdocument.h" #include void UserDocument::setTitle(const QString& title) { m_title = title; emit titleChangedFromQt(m_title); } void UserDocument::setStudent(const Student& student) { m_student = student; QJsonObject jsonStudent; jsonStudent.insert("name", student.getName()); jsonStudent.insert("age", student.getAge()); jsonStudent.insert("tel", student.getTel()); m_jsonStudent = jsonStudent; emit studentChangedFromQt(jsonStudent); } Student UserDocument::getStudent() const { return m_student; } void UserDocument::titleChangeFromWeb(const QString& title) { emit titleChangedForQt(title); } void UserDocument::studentChangedFromWeb(const QJsonObject& jsonStudent) { m_jsonStudent = jsonStudent; QString name = jsonStudent.find("name").value().toString(); int age = jsonStudent.find("age").value().toInt(); QString tel = jsonStudent.find("tel").value().toString(); Student stu{name, age, tel}; m_student = stu; emit studentChangedForQt(m_student); }
主界面,ui需要提供一个QLineEdit用作标题,一个QTableWidget显示列表,一个QLineEdit表示名称,一个QSpinBox表示年龄, 一个QLineEdit表示电话,一个QWdiget提升为QWebEngineView显示网页,一个QProgressBar显示网页加载进度, 当然,这个看自己需求。#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "userdocument.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); void initBrower(); // 初始化浏览器 void setStudentList(); // 设置qt端学生列表 void setWebStudentList(); // 设置web端学生列表,通过jquery设置 private slots: void webViewSource(); // 查看web源码 void webViewProgress(int progress); // web加载进度 void webViewLoadFinished(bool finisned); // web加载完毕 void titleChanged(); // qt端标题修改 void titleChangedForQt(const QString& title); // web端标题修改 void studentChangedForQt(const Student& student); // web端学生修改 void selectTableRow(int index); // QTableWidget行选中 void btnSubmitClicked(); // 提交按钮 private: Ui::MainWindow *ui; UserDocument m_UserDocument; QStringList m_studentListHeader; QList m_studentList; }; #endif // MAINWINDOW_H
实现#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include "student.h" #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); ui->pProgressWebLoad->setMaximumHeight(5); ui->pProgressWebLoad->hide(); // 标题改变,html里面的标题也跟着改变 connect(ui->pLeMainTitle, &QLineEdit::textChanged, this, &MainWindow::titleChanged); // QTableWidget行点击 connect(ui->pTbUserList->verticalHeader(), &QHeaderView::sectionClicked, this, &MainWindow::selectTableRow); // 提交按钮 connect(ui->pBtnSubmit, &QPushButton::clicked, this, &MainWindow::btnSubmitClicked); // 初始化浏览器 initBrower(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::initBrower() { ui->pWebBrower->load(QUrl("qrc:/resources/index.html")); QWebChannel* channel = new QWebChannel(this); // web与qt通信主要手段 channel->registerObject("UserDocument", &m_UserDocument); ui->pWebBrower->page()->setWebChannel(channel); // 初始化web标题 m_UserDocument.setTitle("User Manage"); // 模拟部分学生 Student stu = {"Jone", 18, "028-87930392"}; Student stu2 = {"Jim", 17, "028-46443534"}; Student stu3 = {"Sam", 18, "028-57657446"}; Student stu4 = {"Lucy", 17, "028-78745448"}; m_studentList.append(stu); m_studentList.append(stu2); m_studentList.append(stu3); m_studentList.append(stu4); // 初始化web表单 m_UserDocument.setStudent(stu); // web端学生修改 connect(&m_UserDocument, &UserDocument::studentChangedForQt, this, &MainWindow::studentChangedForQt); // web端标题修改 connect(&m_UserDocument, &UserDocument::titleChangedForQt, this, &MainWindow::titleChangedForQt); // 初始化qt表单 ui->pLeName->setText(stu.getName()); ui->pSbAge->setValue(stu.getAge()); ui->pLeTel->setText(stu.getTel()); // 设置QTableWidget 表头 m_studentListHeader << "Name" << "Age" << "Tel"; ui->pTbUserList->setColumnCount(m_studentListHeader.count()); // 这个要在setHorizontalHeaderLabels前 ui->pTbUserList->setHorizontalHeaderLabels(m_studentListHeader); // 初始化qt端学生列表 setStudentList(); // 把前进、后退、刷新按钮加入到页面 QToolBar* toolBar = addToolBar("Tool"); toolBar->addAction(ui->pWebBrower->pageAction(QWebEnginePage::Forward)); toolBar->addAction(ui->pWebBrower->pageAction(QWebEnginePage::Back)); toolBar->addAction(ui->pWebBrower->pageAction(QWebEnginePage::Reload)); // 添加查看源码按钮 toolBar->addAction("ViewSource", this, &MainWindow::webViewSource); // web加载进度 connect(ui->pWebBrower->page(), &QWebEnginePage::loadProgress, this, &MainWindow::webViewProgress); // web加载完毕 connect(ui->pWebBrower->page(), &QWebEnginePage::loadFinished, this, &MainWindow::webViewLoadFinished); } void MainWindow::setStudentList() { ui->pTbUserList->setRowCount(m_studentList.count()); int i = 0; for (Student stu : m_studentList) { QTableWidgetItem* item; item = new QTableWidgetItem(stu.getName()); ui->pTbUserList->setItem(i, 0, item); item = new QTableWidgetItem(QString::number(stu.getAge())); ui->pTbUserList->setItem(i, 1, item); item = new QTableWidgetItem(stu.getTel()); ui->pTbUserList->setItem(i, 2, item); i++; } } void MainWindow::setWebStudentList() { QString html(tr("%1 | %2 | %3 |
") .arg(m_studentListHeader.at(0)) .arg(m_studentListHeader.at(1)) .arg(m_studentListHeader.at(2))); for (Student stu : m_studentList) { QString body(tr("%1 | %2 | %3 |
") .arg(stu.getName()) .arg(stu.getAge()) .arg(stu.getTel())); html += body; } // 使用jquery同步学生列表 QString code(tr("$qt.jQuery("#users").html("%1")").arg(html)); // 执行javascript ui->pWebBrower->page()->runJavaScript(code); } void MainWindow::webViewSource() { // 查看源码 QTextEdit* source = new QTextEdit(nullptr); source->setAttribute(Qt::WA_DeleteOnClose); // 关闭自动delete ui->pWebBrower->page()->toHtml([source](const QString& html) { source->setPlainText(html); }); source->resize(600, 500); source->show(); } void MainWindow::webViewProgress(int progress) { // 当在加载中时显示进度条,否则不显示 if (progress < 100) { ui->pProgressWebLoad->show(); } else { ui->pProgressWebLoad->hide(); } ui->pProgressWebLoad->setValue(progress); } void MainWindow::webViewLoadFinished(bool finisned) { if (finisned) { // web加载完毕就初始化学生列表 setWebStudentList(); } } void MainWindow::titleChanged() { // qt端标题修改同步修改web端标题 m_UserDocument.setTitle(ui->pLeMainTitle->text()); } void MainWindow::titleChangedForQt(const QString& title) { // web端标题修改同步修改qt端标题 ui->pLeMainTitle->setText(title); } void MainWindow::studentChangedForQt(const Student& student) { // web端x学生添加同步添加qt端学生, 修改原理一样 ui->pLeName->setText(student.getName()); ui->pSbAge->setValue(student.getAge()); ui->pLeTel->setText(student.getTel()); m_studentList.append(student); setStudentList(); setWebStudentList(); } void MainWindow::selectTableRow(int index) { // QTableWidget行选中 QTableWidgetItem* itemName = ui->pTbUserList->item(index, 0); QTableWidgetItem* itemAge = ui->pTbUserList->item(index, 1); QTableWidgetItem* itemTel = ui->pTbUserList->item(index, 2); QString name = itemName->text(); int age = itemAge->text().toInt(); QString tel = itemTel->text(); // 获取到的数据同步到qt表单 ui->pLeName->setText(name); ui->pSbAge->setValue(age); ui->pLeTel->setText(tel); // 获取到的数据同步到web表单 Student stu = {name, age, tel}; m_UserDocument.setStudent(stu); } void MainWindow::btnSubmitClicked() { // 提交表单 QString name = ui->pLeName->text(); int age = ui->pSbAge->value(); QString tel = ui->pLeTel->text(); // 只做添加 Student stu = {name, age, tel}; m_studentList.append(stu); setStudentList(); setWebStudentList(); }
html页面比较简单,懂前端的应该不难看懂 User Manage
买华为mate还是p20?这两款华为系列手机都属于华为高端旗舰产品,华为mate系列目前最新的机型为mate10系列。也即将更新mate20,P系列也是属于旗舰机型最新机型为P20!mate10采用5。9英
华为mate40已经降到4199了,这也太香了吧华为mate40系列可是华为手机里面最受欢迎的型号之一了吧!搭载华为麒麟9000的处理器,,支持40W的快充,最重要的是全网通5G。以至于此次华为P50系列上市,也丝毫没有影响ma
新能源物流车市场觉醒选一块好电池有多重要?新能源物流车经过几年的发展,数量不断增加,目前保有量已超过50万辆。越来越多的运营经销商金融机构终端用户开始接触新能源物流车。当前,部分城市的新能源物流车市场正处于觉醒时分,想加入
小米手机官方维修能信吗?我的小米10s摔地上,前屏因为贴了钢化膜所以钢化膜和屏都没有破损,后玻璃盖碎了。前屏磕成漏液,造成手机上半部分不显示触摸屏失灵,没办法关机。只能下半部分打开app然后上滑退出。八月
个性DIY,定制属于自己的插排,奥睿科ORICO无线插排插排,无论是家庭还是办公都很常用的设备。想必不用过多介绍,大家都很熟悉。但是平时使用时也会遇到一些问题,大多集中在线缆的问题,要么不够长要么材质差使用中容易过热等问题。正好看到OR
更新F13使用体验OPPOA91就在刚刚也是推送了colorOS11F13安卓补丁,在为时一天的使用体验下来分享这次优化的部分。优化系统UI动画从系统底层优化A91的打开退出以及其他多种场景下的动画
哪一品牌的电视盒子值得推荐,波多星Y1实测无广告且不卡顿最近有朋友问什么牌子的电视盒子最好,我花了半个月的时间仔细评估了波多星电视盒子Y1,想向大家推荐一下这一款电视盒子。先简单说明一下我为什么推荐这款电视盒子,因为它实在是太方便了,简
超长待机还能给手机充电,出门必备神器南卡N2s开箱超长待机还能给手机充电,出门必备神器南卡N2s开箱说起蓝牙耳机,以前可能大家还在纠结到底买国际大品牌还是买国产新兴品牌,而如今蓝牙耳机就和智能手机一样,通过近几年的高速发展,各大品
企业办公更畅爽,宝藏品牌爱快WiQ1800评测如今,随着企业数字化转型的进程不断加快,联网终端的数量激增,伴随而来的是企业愈发重视影响其核心业务的网络基础设施和网络设备建设另一方面,随着WiFi6新一代无线局域网传输技术的兴起
售价2499起!小米平板5pro速览这是一块11的大屏幕,却拥有2。5K超清晰显示,支持HDR1O,每一处细节都细腻养眼,多达1O亿色的真彩显示,为你真实还原天地间的缤纷多彩。轻盈机身,纤薄设计骁龙870处理器当家旗
2021年1000元2000元档最值得买的3款手机超高性价比一红米K40系列1性能。红米K40在2000元价位上采用了次旗舰处理器骁龙870,跑分仅次于骁龙888。足以流畅地运行所有的app,带来畅快的体验。2屏幕。K40采用了三星新一代E