I am writing a C++ QWidget application that communicates with JavaScript running in a resource hosted web page. I need to find a way to send an array of the following POD structs to a JavaScript function hosted in the web page but unfortunately the data always ends up as arrays of nulls. I think the problem similar to this question - but this does not have an answer either.
The custom POD struct (I need to send a list (QVariantList) of these) is:
using FPlanWPT = struct FPlanWPT {
//std::string name;
double longitude;
double latitude;
double bearing;
};
// register custom type with the QT type system
Q_DECLARE_METATYPE(FPlanWPT);
The IPC class that is used as a notifier is as follows:
class FlightRoute : public QObject {
Q_OBJECT
Q_PROPERTY(QVariantList data READ data NOTIFY dataChanged)
public:
explicit FlightRoute(QObject* parent = nullptr)
: QObject(parent)
{}
//! Flight route data getter.
QVariantList data() const {
return valueList;
}
public slots:
void updateRouteData(const QVariantList& data);
signals:
void dataChanged(const QVariantList& data);
private:
QVariantList valueList;
};
The idea above is that when the
The closest example I found to what I am trying to achieve is a QT Widget based JavaScript Chart.js application that generates randomized chart columns and updates a chart running in a web page.
The key to getting IPC communication between the QT C++ Widget application and JavaScript is to initialize a QWebChannel on both ends.
On the C++ side this is essentially:
class mainwindow : public QMainWindow
{
Q_OBJECT
public:
explicit mainwindow(QWidget *parent = Q_NULLPTR);
~mainwindow();
...
private:
...
std::unique_ptr<QWebEngineView> mpWebView;
}
the constructor is as follows:
//! Constructor.
mainwindow::mainwindow(QWidget *parent)
: QMainWindow(parent)
, mUI(new Ui::mainwindow())
. . .
, mpWebView(std::make_unique<QWebEngineView>())
, mRecordBuffer{}
, mpWorkerThread{nullptr}
, mpWorkerObject{nullptr}
{
static auto& gLogger = gpLogger->getLoggerRef(
gUseSysLog ? Logger::LogDest::SysLog :
Logger::LogDest::EventLog);
// JavaScript integration - allow remote debugging with mpWebView
qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "1234");
// register custom types for serialization with signals/slots
qRegisterMetaType<FPlanWPT>("FPlanWPT");
// initialize the form
mUI->setupUi(this);
// load the web page containing the google map javascript
mpWebView->page()->load(QUrl("qrc:///html/test.html"));
// initialize the link to the HTML web page content
auto webChannel = new QWebChannel(this);
const auto routeIPC = new FlightRoute(this);
// register IPC object with the QWebChannel
connect(mpWorkerObject, &Worker::fooSignal, routeIPC, &FlightRoute::updateRouteData, Qt::DirectConnection);
webChannel->registerObject(QStringLiteral("routeIPC"), routeIPC);
mpWebView->page()->setWebChannel(webChannel);
// Insert the html page at the top of the grid layout
mUI->flightTrackGridLayout->addWidget(mpWebView.get(), 0, 0, 1, 3);
. . .
}
On the JavaScript side (this is my entire HTML file)
<html>
<head>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
</head>
<body>
<div style="margin:auto; width:100%;">
<canvas id="canvas"></canvas>
</div>
<script>
// function to update the google
var updateMap = function (waypointData) {
// waypoint data is always a list of nulls
console.log(waypointData);
}
// script called once web page loaded
window.onload = function () {
new QWebChannel(qt.webChannelTransport,
function (channel) {
// whenever the route data changes, invoke updateMap slot
var dataSource = channel.objects.routeIPC;
dataSource.dataChanged.connect(updateMap);
}
);
}
</script>
</body>
</html>
Additionally, on the C++ side we set a page from the QWebEngineView to a Gui layout that displays the web content. These need to be initialized ahead of time the signal to slot flows asynchronously through the established QWebChannel. In my case, I only care about sending custom POD structs via QVariant objects from the C++ side to the JavaScript side.
In order to use custom data structures with the QVariant - or in my case QVariantList's - we need to register the custom type with QT - as a sort of meta rtti registration. Without this when the javascript slot function var updateMap will not be able to decode the type information from the fields of the POD.
The