diff --git a/examples/javascript_interop/index.html b/examples/javascript_interop/index.html new file mode 100644 index 0000000000000000000000000000000000000000..bc1082bdcf047432ff6298379721754c883716db --- /dev/null +++ b/examples/javascript_interop/index.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>JavaScript Interop</title> + + <script src="../testapp/testapp.js"></script> + <script src="../testapp/qtloader.js"></script> + <script> + + // JavaScript function which can be called from C++, see + // ../testapp/jsinterop.cpp + function helloJs(name) { + console.log("Hello " + name + " from helloJs"); + } + + // A pice of data, can be accessed from C++ as well + window.data = new Uint8Array([1, 2, 3 ,4]); + + window.addEventListener('load', async () => { + const qtloader = QtLoader({ + containerElements: [document.getElementById("container")], + showCanvas: () => { + + // This example does provide a UI. Instead, enable the "Call C++" + // button which calls the function exported from jsinterop.cpp. + const callCppButton = document.getElementById("callcpp"); + callCppButton.disabled = false; + callCppButton.addEventListener("click", () => { + qtloader.module()["helloCpp"]("Qt"); + }); + }, + }); + qtloader.loadEmscriptenModule("../testapp/testapp"); + }) + </script> + </head> + <body> + <h1>Qt for WebAssembly: JavaScript Interop</h1> + <p> This examples show how to call C++ functions from JavaScript, + and vice versa. Output is printed to the JavaScript console.</p> + <button type="button" disabled="true" id="callcpp" disabled>Call C++ function</button> + <div id="container" style="width:320px; height:200px; visibility:hidden"></div> + </body> +</html> diff --git a/examples/testapp/CMakeLists.txt b/examples/testapp/CMakeLists.txt index 2e6fb896dbaabab97c60d2b0a2468a2e393fcdb5..35ff3d2e579db7580f0ad7901e1dc7117620b74a 100644 --- a/examples/testapp/CMakeLists.txt +++ b/examples/testapp/CMakeLists.txt @@ -6,7 +6,11 @@ set(CMAKE_AUTOMOC ON) find_package(Qt6 REQUIRED COMPONENTS Core Gui) qt_add_executable(testapp - main.cpp rasterwindow.cpp ../../qtwebutils.cpp popup.cpp + main.cpp + rasterwindow.cpp + popup.cpp + jsinterop.cpp + ../../qtwebutils.cpp ) target_link_libraries(testapp PUBLIC diff --git a/examples/testapp/jsinterop.cpp b/examples/testapp/jsinterop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49a851ccdf0933e9b39bdc54c408263bd51efda8 --- /dev/null +++ b/examples/testapp/jsinterop.cpp @@ -0,0 +1,36 @@ +#include <QtCore> +#include <algorithm> +#include <emscripten/bind.h> +#include <emscripten/val.h> + +// This example demonstrates how to interop with JavaScript code +// and data from C++ using Emscripten bind.h and val.h. + +// Sample C++ function. This function is exported to JavaScript using +// EMSCRIPTEN_BINDINGS below. +void helloCpp(std::string name) +{ + qDebug() << "Hello" << QString::fromStdString(name) << "from helloCpp"; + + // Call JS function. See defenition in ../examples/jsinterop/jsinterop.cpp + // The function is accessed via the global "window" object. + emscripten::val window = emscripten::val::global("window"); + window.call<void>("helloJs", name); + + // Copy data from a JavaScript Array. This copies from the + // JavaScript heap to the C++ heap. + QByteArray data = QByteArray::fromEcmaUint8Array(window["data"]); + qDebug() << "Got data bytes" << QString::number(data[0]) << QString::number(data[1]) + << QString::number(data[2]) << QString::number(data[3]); + + // Clear Js-side data, if we don't want to hold a copy there + window.set("data", emscripten::val::null()); + + // Or assign back to it + std::reverse(data.begin(), data.end()); + window.set("data", data.toEcmaUint8Array()); +} + +EMSCRIPTEN_BINDINGS(qt_webutils) { + emscripten::function("helloCpp", &helloCpp); +}