0

I created an easy login form in html with a submit button that when I clicked it, a Javascript's function check if the login is correct or not.
All put all files into a qrc file in QT and I wrote this code for run the program:

login.pro

QT += webenginewidgets core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = login
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

FORMS += \
        mainwindow.ui

RESOURCES += \
    login.qrc


mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtWebEngineWidgets>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    void connectToJs(bool result, QWebEngineView *view);
private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H


mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtWebEngineWidgets>
#include <QUrl>
#include <QtWebView/QtWebView>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QFile apiFile(":/qtwebchannel/qwebchannel.js");
    if(!apiFile.open(QIODevice::ReadOnly))
        qDebug()<<"Couldn't load Qt's QWebChannel API!";
    QString apiScript = QString::fromLatin1(apiFile.readAll());    
    apiFile.close();

    view->page()->runJavaScript(apiScript);
    view->load(QUrl(QStringLiteral("qrc:/new/prefix1/index.html")));
    connect(view->page(), SIGNAL(loadFinished(bool)), this, SLOT(connectToJs(bool, view))); 

    setCentralWidget(view);
}

void MainWindow::connectToJs(bool result, QWebEngineView * view) {

    qDebug() << "connectToJs!" << result;
    if (result) {
        QWebChannel *channel = new QWebChannel(view->page());
        view->page()->setWebChannel(channel);
        channel->registerObject(QString("nameObject"), this);
    }
}

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


index.html
<html>
<head>
    <title>Javascript Login Form Validation</title>
    <script src="login.js"></script>
</head>
<body>
    <div class="container">
        <div class="main">
            <h2>Javascript Login Form Validation</h2>
            <form id="form_id" method="post" name="myform">
                <label>User Name :</label>
                <input type="text" name="username" id="username"/>
                <label>Password :</label>
                <input type="password" name="password" id="password"/>
                <input type="button" value="Login" id="submit" onclick="validate()"/>
            </form>             
        </div>
    </div>
</body>
</html>


login.js
function validate(){
    var username = document.getElementById("username").value;
    var password = document.getElementById("password").value;
    if ( username == "Jack" && password == "login"){
        alert ("Login successfully");
    }
    else{
        alert("Error: the login is incorrect!");
    }
}

var workoutObject;

if (typeof qt != 'undefined') {
    alert("Qt is OK!!");
    new QWebChannel(qt.webChannelTransport, function (channel) {
        workoutObject = channel.objects.nameObject;
    });
}
else {
    alert("Qt is not defined!");
}



That I want now is pass the username and the password from html to QT when I click the button.
How can I implement the QWebChannel?

  • 2
    Possible duplicate of [Expose C++ object to Javascript in Qt with QtWebEngine](https://stackoverflow.com/questions/27512526/expose-c-object-to-javascript-in-qt-with-qtwebengine) – eyllanesc Oct 23 '17 at 18:13

1 Answers1

3

In order to pass args from HTML/JS to QT via QWebEngine you will have to use the QWebChannel. There are some prerequisites for this task:

First you will have to create Qt object to interact with HTML/JS

H file

  class QJavaScriptProxy : public QObject
  {
     Q_OBJECT

     private:
            QString m_oUserName;
            QString m_oPassword;
     public:
        // Ctor
        QJavaScriptProxy(QObject * poParent = Q_NULLPTR);
        // Expose function to HTML/JS
        Q_INVOKABLE void setUserNameAndPassword(const QString & oUserName, const QString & oPass);
           ...
  };

Cpp file

  QJavaScriptProxy::QJavaScriptProxy(QObject * poParent) : QObject(poParent)
  {
     // Set object name will be used as JS variable
     setObjectName("m_oQtProxy");
  }
  QJavaScriptProxy::setUserNameAndPassword(const QString & oUserName, const QString & oPassword)
  {
     //store user name and password
     m_oUserName = oUserName;
     m_oPassword = oPassword;
  }

Then register this object in your MainWindow

QWebChannel * poChannel = new QWebChannel(view->page());
view->page()->setWebChannel(poChannel);
// Create proxy object
m_poQtProxy = new QJavaScriptProxy(this);
// Register object
channel->registerObject(m_poQtProxy->objectName(), m_poQtProxy);

Add the qwebchannel.js file and link it to your HTML resources

index.html

<script src="qwebchannel.js" type="text/javascript"></script>

In the JavaScript side

login.js

 new QWebChannel(qt.webChannelTransport, function(channel){
            // Set global Qt proxy object
            window.qProxy = channel.m_oQtProxy;             
        });


    // Pass user name and password to QT
    // Note: you can call this function on button click.
    function toQT(name, pass){
       qProxy.setUserNameAndPassword(name,pass);
    }
Simon
  • 1,522
  • 2
  • 12
  • 24
  • In internet I found more examples that use **QWebSocket**, should I use it to pass the data or not? – Jacopo Gardin Oct 26 '17 at 07:25
  • 1
    If you want to interact between JS and QT the example above should do the work. – Simon Oct 26 '17 at 11:21
  • When I run the project, I have this error: `js: Uncaught ReferenceError: QWebChannel is not defined` – Jacopo Gardin Oct 27 '17 at 07:40
  • Which Qt version you are using ? this integration is available from version 5.5 – Simon Oct 29 '17 at 06:26
  • I'm using QT 5.9.1... I edited the question, now with the SIGNAL I solved the problem of the asynchronous files but the SLOT doesn't work... Have you got any advice for me? – Jacopo Gardin Oct 30 '17 at 08:57
  • You don't need this slot, you can create the **WebChannel** and register the object in your contractor before loading the html page. – Simon Oct 30 '17 at 09:59
  • Ok, so, for example, I can change the slot with a function that check if the username and password are correct? – Jacopo Gardin Oct 30 '17 at 10:28
  • yes, create function/slot `MainWindow::check(const QString & oName, const QString & oPass)` and from the **js** side call `workoutObject.check('name','pass');` – Simon Oct 30 '17 at 10:42
  • God damn I have again the error `js: Uncaught ReferenceError: QWebChannel is not defined`. Is it possible because the **HTML** side and **js** side are asynchronous? I thought to solve it with the signal `loadFinished(bool)` but, at the end, it doesn't work correctly... – Jacopo Gardin Oct 30 '17 at 10:58
  • Try to run this example [WebEngine Markdown Editor Example](https://doc.qt.io/qt-5/qtwebengine-webenginewidgets-markdowneditor-example.html) – Simon Oct 30 '17 at 11:40
  • Will this example work with Mobiles as well. Is there any problem due to `QWebEngineView` not present in the mobile platforms (instead they have `QWebView`)? – iammilind May 16 '18 at 08:44