Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I want to access
QtObject
from HTML-page running in
WebView
- invoke methods, read/write properties, etc.
As far as I understood, I need to establish
WebSockets
connection between QML and HTML sides, and then use it as a transport for
WebChannel
.
Don't confuse WebView with
WebEngineView
- I know how to do it with WebEngineView, but I need to do it with WebView.
So, here's what I have.
QML side
QtObject {
id: someObject
WebChannel.id: "backend"
property string someProperty: “property value"
WebSocketServer {
listen: true
port: 55222
onClientConnected: {
console.log(webSocket.status);
//webSocket.onTextMessageReceived.connect(function(message) {
// console.log(qsTr("Server received message: %1").arg(message));
//});
WebView {
url: "index.html"
//webChannel: channel // invalid property name "webChannel"
//experimental.webChannel.registeredObjects: [someObject] // invalid property name "experimental"
WebChannel {
id: channel
registeredObjects: [someObject]
HTML side
window.onload = function()
// here will be QtObject from QML side
var backend;
var socket = new WebSocket("ws://localhost:55222");
socket.onopen = function()
//socket.send("some message");
new QWebChannel(socket, function(channel) {
backend = channel.objects.backend;
function alertProperty()
alert(backend.someProperty);
Simple message exchange works fine (socket.send()
), so transport is okay, but how do I assign WebChannel to WebView? With WebEngineView it was simple, there is a webChannel
property there (and there is even no need in using WebSockets), but there is nothing alike in WebView. I mean, something has to tell WebView that WebChannel contains my QtObject so it would be visible to JS?
And if WebView does not support WebChannel(?), how to do it with external browser then? This example shows that it is possible with C++, but I want to do it with QML.
I use Qt 5.11.1.
WebView
does not support WebChannel
by default. So the solution is to use WebSocketServer
with QWebChannelAbstractTransport
as I show below:
main.cpp
#include <QGuiApplication>
#include <QJsonDocument>
#include <QQmlApplicationEngine>
#include <QWebChannelAbstractTransport>
#include <QtWebView>
class WebSocketTransport : public QWebChannelAbstractTransport{
Q_OBJECT
public:
using QWebChannelAbstractTransport::QWebChannelAbstractTransport;
Q_INVOKABLE void sendMessage(const QJsonObject &message) override{
QJsonDocument doc(message);
emit messageChanged(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
Q_INVOKABLE void textMessageReceive(const QString &messageData){
QJsonParseError error;
QJsonDocument message = QJsonDocument::fromJson(messageData.toUtf8(), &error);
if (error.error) {
qWarning() << "Failed to parse text message as JSON object:" << messageData
<< "Error is:" << error.errorString();
return;
} else if (!message.isObject()) {
qWarning() << "Received JSON message that is not an object: " << messageData;
return;
emit messageReceived(message.object(), this);
signals:
void messageChanged(const QString & message);
int main(int argc, char *argv[])
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<WebSocketTransport>("com.eyllanesc.org", 1, 0, "WebSocketTransport");
QtWebView::initialize();
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
#include "main.moc"
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtWebSockets 1.1
import QtWebView 1.1
import QtWebChannel 1.0
import com.eyllanesc.org 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
WebView {
url: "qrc:/index.html"
anchors.fill: parent
QtObject {
id: someObject
property string someProperty: "prop"
WebChannel.id: "core"
function receiveText(text){
console.log("receiveText: ", text)
signal sendText(string text)
WebSocketTransport{
id: transport
WebSocketServer {
listen: true
port: 12345
onClientConnected: {
if(webSocket.status === WebSocket.Open){
channel.connectTo(transport)
webSocket.onTextMessageReceived.connect(transport.textMessageReceive)
transport.onMessageChanged.connect(webSocket.sendTextMessage)
WebChannel {
id: channel
registeredObjects: [someObject]
// testing
Timer{
interval: 500
running: true
repeat: true
onTriggered: someObject.sendText(Qt.formatTime(new Date(), "hh:mm:ss") + " from QML")
index.html
<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript">
//BEGIN SETUP
function output(message) {
var output = document.getElementById("output");
output.innerHTML = output.innerHTML + message + "\n";
window.onload = function() {
if (location.search != "")
var baseUrl = (/[?&]webChannelBaseUrl=([A-Za-z0-9\-:/\.]+)/.exec(location.search)[1]);
var baseUrl = "ws://localhost:12345";
output("Connecting to WebSocket server at " + baseUrl + ".");
var socket = new WebSocket(baseUrl);
socket.onclose = function() {
console.error("web channel closed");
socket.onerror = function(error) {
console.error("web channel error: " + error);
socket.onopen = function() {
output("WebSocket connected, setting up QWebChannel.");
new QWebChannel(socket, function(channel) {
// make core object accessible globally
window.core = channel.objects.core;
input.innerHTML = core.someProperty;
document.getElementById("send").onclick = function() {
var input = document.getElementById("input");
var text = input.value;
if (!text) {
return;
output("Sent message: " + text );
input.value = "";
core.receiveText(text + " From HTML");
core.sendText.connect(function(message) {
output("Received message-" + core.someProperty + " : " + message);
core.receiveText("Client connected, ready to send/receive messages!");
output("Connected to WebChannel, ready to send/receive messages!");
//END SETUP
</script>
<style type="text/css">
html {
height: 100%;
width: 100%;
#input {
width: 400px;
margin: 0 10px 0 0;
#send {
width: 90px;
margin: 0;
#output {
width: 500px;
height: 300px;
</style>
</head>
<textarea id="output"></textarea><br />
<input id="input" /><input type="submit" id="send" value="Send" onclick="javascript:click();" />
</body>
</html>
The complete example can be found in the following link
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.