Qt使用QWebChannel与QWebEngineView内嵌Html交互

Qt通过QWebEngineView渲染html页面,可以通过QWebChannel结合javascript与html交互

Qt通过QWebEngineView渲染html页面,可以通过QWebChannel结合javascript与html交互

其中需要2个js文件,一个jquery文件,如果javascript学得好可以不要,一个是qt提供的qwebchannel.js

先看效果图

Qt使用QWebChannel与QWebEngineView内嵌Html交互

根据qtmarkdown示例做的, 列表使用了自定义类Student,本来想通过自定义QType做交互,但没实现,获取到的数据为null,后该为了QJsonObject,

首先学生类,其实就是一个简单的c++类

#ifndef STUDENT_H#define STUDENT_H#include <QString>#include <QMetaType>// 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>("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 <QObject>#include <QJsonObject>#include <QRect>#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 <QDebug>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 <QMainWindow>#include <QJsonObject>#include "userdocument.h"QT_BEGIN_NAMESPACEnamespace Ui { class MainWindow; }QT_END_NAMESPACEclass MainWindow : public QMainWindow{    Q_OBJECTpublic:    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<Student> m_studentList;};#endif // MAINWINDOW_H

实现

#include "mainwindow.h"#include "ui_mainwindow.h"#include <QToolBar>#include <QTextEdit>#include <QtWebChannel>#include "student.h"#include <QHeaderView>#include <QDebug>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("<tr><th>%1</th><th>%2</th><th>%3</th></tr>")                 .arg(m_studentListHeader.at(0))                 .arg(m_studentListHeader.at(1))                 .arg(m_studentListHeader.at(2)));    for (Student stu : m_studentList)    {        QString body(tr("<tr><td>%1</td><td>%2</td><td>%3</td></tr>")                     .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页面比较简单,懂前端的应该不难看懂

<html>    <head>        <meta charset="utf-8" />        <title>User Manage</title>        <style>            .container {                width: 1000px;                margin: 0 auto;                margin-top: 30px;            }            .header {                text-align: center;                margin: 20px auto;            }            .main {                display: flex;            }            .list {                flex: 0 0 60%;            }            .users {                border-left: 1px solid #cccccc;                border-top: 1px solid #cccccc;                border-spacing: 0;                width: 100%;            }            .users td {                border-right: 1px solid #cccccc;                border-bottom: 1px solid #cccccc;                padding: 5px;            }            .user-form {                flex: 0 0 38%;            }            .user-form .form-group {                display: flex;                margin-bottom: 20px;            }            .user-form .form-group .label {                flex: 0 0 120px;                text-align: right;                padding-right: 5px;                line-height: 32px;            }            .user-form .form-group .input-box {                flex: 1;            }            .user-form .form-group .input-box input {                width: 100%;                height: 32px;                line-height: 32px;                border-radius: 5px;                border: 1px solid #cccccc;            }            .user-form .form-group .input-box button {                width: 120px;                height: 32px;                line-height: 32px;                text-align: center;            }            #log {                position: bottom;                height: 150px;                left: 0;                right: 0;                bottom: 0;                border-left: 1px solid #cccccc;            }        </style>        <script src="jquery-3.5.1.min.js"></script>        <script src="qwebchannel.js"></script>    </head>    <body>        <div class="container">            <div class="header">                <h1><input type="text" name="title" id="title" value="User Manage" /></h1>            </div>            <div class="main">                <div class="list">                    <table class="users" id="users"></table>                </div>                <div class="user-form">                    <form>                        <div class="form-group">                            <div class="label">Name:</div>                            <div class="input-box">                                <input type="text" name="name" id="name" value="" />                            </div>                        </div>                        <div class="form-group">                            <div class="label">Age:</div>                            <div class="input-box">                                <input type="number" name="age" id="age" value="" />                            </div>                        </div>                        <div class="form-group">                            <div class="label">Tel:</div>                            <div class="input-box">                                <input type="text" name="tel" id="tel" value="" />                            </div>                        </div>                        <div class="form-group">                            <div class="label"> </div>                            <div class="input-box">                                <button type="button" id="changeStudent">Submit</button>                            </div>                        </div>                    </form>                </div>            </div>        </div>        <div id="log">        </div>    </body>    <script>        var $qt = { 'jQuery': jQuery.noConflict(true) };        $qt.jQuery('#log').html("test");                var updateTitle = function(text) {            if (text != "") {                $qt.jQuery('#title').val(text);            }        }        var updateStudent = function(student) {            $qt.jQuery('#name').val(student.name);            $qt.jQuery('#age').val(student.age);            $qt.jQuery('#tel').val(student.tel);        }        var userDocument;        new QWebChannel(qt.webChannelTransport, function(channel) {            userDocument = channel.objects.UserDocument;            $qt.jQuery('#log').html(JSON.stringify(userDocument));            //$qt.jQuery('#log').html(JSON.stringify(userDocument.jsonStudent));            // 同步修改web标题            updateTitle(userDocument.title);            userDocument.titleChangedFromQt.connect(updateTitle);            // 同步显示web学生表单            updateStudent(userDocument.jsonStudent);            userDocument.studentChangedFromQt.connect(updateStudent);        });        // 同步修改qt标题        $qt.jQuery('#title').on("input propertychange", function() {            $qt.jQuery('#log').html($qt.jQuery(this).val());            userDocument.titleChangeFromWeb($qt.jQuery(this).val());        })        // 同步显示qt学生表单        $qt.jQuery('#changeStudent').click(function() {            var stu = {                name: $qt.jQuery('#name').val(),                age: parseInt($qt.jQuery('#age').val()),                tel: $qt.jQuery('#tel').val()            }            userDocument.studentChangedFromWeb(stu);        })    </script></html>

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/112068.html

(0)

相关推荐