使用QWebChannel时未定义的属性和返回类型

问题描述:

基于QT QWebEnginePage::setWebChannel() transport objectQt: Cannot invoke shared object methods/properties from javascript我试图做一个小演示来测试功能。请参阅下面的基本测试代码。我的问题是:使用QWebChannel时未定义的属性和返回类型

  • 在新的QWebChannel的JavaScript构建过程中,Qt控制台中有很多打印对象的属性?'''?''。没有通知信号,并且不是常量,HTML中的值更新将被破坏!“。这是怎么回事,我该如何解决?
  • 当试图从javascript端检索它们时,所有C++对象属性都是未定义的。什么是通过webchannel检索属性的正确方法?
  • 来自C++函数的所有返回值回到未定义...在javascript中接收C++返回值的正确方法是什么?

.pro文件

QT  += core gui 
QT  += network webenginewidgets webchannel widgets 
TARGET = hfbTestWebChannel 
TEMPLATE = app 
SOURCES += hfbTestWebChannel.cpp 
RESOURCES += hfbTestWebChannel.qrc 

.html文件

<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文件

#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" 

*编辑添加的所有代码的完整性

我最近有同样的问题。经过一番调查后,我想出了如何使其工作。非常感谢这个问题的答案:How to use Qt WebEngine and QWebChannel?

为了获得你的QObject的方法的返回值,你需要定义一个包装你的QObject方法的Q_PROPERTY。例如:

class SharedObject : public QObject 
{ 
    Q_OBJECT 
public: 
    Q_INVOKABLE int getIntValue(); 
    Q_PROPERTY(int intValue READ getIntValue) 

    Q_INVOKABLE QString getStringValue(); 
    Q_PROPERTY(QString stringValue READ getStringValue) 
} 

然后在你的HTML,这样做:

<script type="text/javascript"> 
    document.addEventListener("DOMContentLoaded", function() { 
     new QWebChannel(qt.webChannelTransport, function (channel) { 
     window.sharedObject = channel.objects.sharedObject; 
     alert("intValue: " + sharedObject.intValue); 
     alert("stringValue: " + sharedObject.stringValue); 
     }); 
    }); 
    </script> 

你应该能够看到的intValue和stringValue的在你的JavaScript代码。重要的是我想用Q_PROPERTY。

无论如何,这解决了我的问题,我希望它也可以帮助别人。

面临同样的问题......阅读文档仔细给了我答案。答案是在Qt5中Qt和JS之间的通信是异步的。您必须提供回调函数,该函数将在完成方法并收到结果值后调用。

与其说

var n = theQtObj.getInt(X); 
PrintLog(" back in js with n="+n); 

,你可以拨打作为

theQtObj.getInt(X, function(n) { 
    PrintLog(" back in js with n="+n); 
});