Based on QT QWebEnginePage::setWebChannel() transport object and Qt: Cannot invoke shared object methods/properties from javascript I tried to make a small demo to test the functionality. See the basic test code below. My questions are:
.pro file
QT += core gui
QT += network webenginewidgets webchannel widgets
TARGET = hfbTestWebChannel
TEMPLATE = app
SOURCES += hfbTestWebChannel.cpp
RESOURCES += hfbTestWebChannel.qrc
.html file
<html>
<body>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript">
var theQtObj;
function buttonA()
{
PrintLog("Button A:init")
if (typeof qt !== "undefined")
{
new QWebChannel(qt.webChannelTransport, function(channel)
{
theQtObj = channel.objects.theQtObj;
PrintLog(" done, now theQtObj=" + theQtObj.toString());
});
}
else
PrintLog("!!!qt undefined!!!" );
}
function buttonB()
{
PrintLog("Button B : call c++ and get some answers!")
if(typeof theQtObj !== "undefined")
{
var X = prompt("Enter a number", "5");
PrintLog("theQtObj=" + theQtObj + " => X=" + X);
var n = theQtObj.getInt(X);
PrintLog(" back in js with n="+n);
var d = theQtObj.getDouble(n);
PrintLog(" back in js with d="+d);
var s = theQtObj.getString(d.toString());
PrintLog("X:" + X + "->" + n + "->" + d + "->" + s);
}
else
PrintLog(" --> theQtObj not defined");
}
function buttonC()
{
PrintLog("Button C:get c++ object member elements")
if(typeof theQtObj !== "undefined")
{
PrintLog("theQtObj._theString=" + theQtObj._theString);
PrintLog("theQtObj._theInt=" + theQtObj._theInt);
}
else
PrintLog(" --> theQtObj not defined");
}
var x=0;
function PrintLog(txt)
{
var myBox = document.getElementById("textBoxLog");
myBox.value += ("\n" + x + ": " + txt);
myBox.scrollTop = myBox.scrollHeight;
return (x++);
}
</script>
<p>Test Example to call Qt function from Javascript </p>
<p>
<input type="button" value=" A:init " onclick="buttonA()">
<input type="button" value=" B:get int " onclick="buttonB()">
<input type="button" value="C:get members" onclick="buttonC()">
</p>
<p>
<textarea id="textBoxLog" rows="31" cols="95">
textBoxLog
</textarea>
</p>
</body>
</html>
.cpp file
#include <QWebEngineView>
#include <QApplication>
#include <QtWebChannel/QtWebChannel>
/////////////////////////////////////////////////////////////////
class hfbDisplayWidget : public QWebEngineView
{
Q_OBJECT
public:
hfbDisplayWidget(QWidget * parent) : QWebEngineView(parent)
{
page()->setWebChannel(&_webchannel);
_webchannel.registerObject(QString("theQtObj"), this);
_theString = "Hello World";
_theInt = 777;
}
QWebChannel _webchannel;
Q_INVOKABLE QString _theString;
Q_INVOKABLE int _theInt;
Q_INVOKABLE int getInt(QVariant n)
{
int N = n.toInt();
QString js = QString("PrintLog('c++ getInt(%1) fired!')").arg(N);
_theString = js;
_theInt = N;
page()->runJavaScript(js, [=](const QVariant &rslt){
qDebug() << js << " -> " << rslt;
});
return N*100;
}
Q_INVOKABLE double getDouble(QVariant d)
{
double D = d.toDouble();
QString js = QString("PrintLog('c++ getDouble(%1) fired!')").arg(D);
page()->runJavaScript(js, [=](const QVariant &rslt){
qDebug() << js << " -> " << rslt;
});
return (D+0.12345);
}
Q_INVOKABLE QString getString(QVariant s)
{
QString S = s.toString();
QString js = QString("PrintLog('c++ getString(%1) fired!')").arg(S);
page()->runJavaScript(js, [=](const QVariant &rslt){
qDebug() << js << " -> " << rslt;
});
return (QString("c++ called with:'") + S + QString("'"));
}
};
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
hfbDisplayWidget view(nullptr);
view.setUrl(QUrl("qrc:/hfbTestWebChannel.html"));
view.show();
return a.exec();
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
#include "hfbTestWebChannel.moc"
*EDIT to add all code for completeness
Faced same issue... Reading doc's carefully gave me the answer. The answer is that communication between Qt and JS in Qt5 is asynchronous. You have to provide callback function which will be called after method completed and result value received.
Instead of calling
var n = theQtObj.getInt(X);
PrintLog(" back in js with n="+n);
you can call at as
theQtObj.getInt(X, function(n) {
PrintLog(" back in js with n="+n);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With