1.安装及介绍
【Qt杂谈2.快速体验Qt for WebAssembly(Windows平台)】
【qt for webassembly环境搭建图文教程】
2.问题及解决方案
2.1.在C++中调用js函数
关于在wasm编译环境中,在c++中调用js,可以参考以下网址:
【emscripten.h】
【asm.js 和 Emscripten 入门教程】
【EM_JS : unable to free const char* in cpp】
2.2.中文无法显示(乱码):
【Qt for WebAssembly中文显示异常】
弄一个otf或者ttf字体文件,然后加到资源库中,然后
1 2
| //注意选择你自己的文件 QFontDatabase::addApplicationFont(":/qml/Font/Alibaba-PuHuiTi-Light.otf");
|
2.3.无法输入中文
好像没有有效的资料解决这个问题,所以我只能调用html的api了。(Qt6.8能够输入中文了,请看这篇文章的最后讨论【Unable to input Chinese (Chinese characters) ?】)
具体实现代码请看另外一篇文章【QtWebAssembly实现中文输入】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #ifdef Q_OS_WASM #include <emscripten.h> #include <emscripten/html5.h>
//获取用户输入,因为Qt不支持直接输入中文。。 EM_JS(const char*, getInput, (const char *str), { const text = UTF8ToString(str); val = prompt("", text);
if(val == null) { val = "" } var jstring = val;
var lengthBytes = lengthBytesUTF8(jstring)+1; var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jstring, stringOnWasmHeap, lengthBytes); return stringOnWasmHeap; }) #endif
...... // 此函数可以作为静态函数,在适当的时候使用 // 调用此函数的效果为:在页面上弹出啊一个输出窗口,用户在输入好信息后,点击确定,窗口消失,此函数返回用户输入的字符串 QString Manager::getUserInput(QString currentText) { QString input = "";
#ifdef Q_OS_WASM input = getInput(currentText.toUtf8().data()); #else
#endif
return input; }
|
2.4.qt对应的emsdk版本
【Qt for WebAssembly】
设置的时候,直接在 Tools --》Options --》device–》webAssembly设置emsk的根目录就行。(记得在设置之前要先安装好python并设置好环境变量,因为QtCreator会调用)
假如在emsdk install 比较新的版本时,可能会出现:
1 2
| D:\Qt\emsdk\emsdk>emsdk install 3.1.25 error: tool or SDK not found: '3.1.25'
|
此时可以先pull一下再install
1
| D:\Qt\emsdk\emsdk>git pull
|
2.5.文件的下载以及上传:
【webassembly: support local system file access】
文件的下载(保存)可以选择用label显示下载链接(点击label后触发下载)。
1 2
| ui->label->setText("<a style='color: green;' href = https://download.qt.io/archive/online_installers/4.1/qt-unified-windows-x86-4.1.1-online.exe> click to download</a>"); ui->label->setOpenExternalLinks(true);
|
或者选择稍微复杂一点的,通过wasm提供的接口,调用js实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #ifdef Q_OS_WASM #include <emscripten.h> #include <emscripten/html5.h> #endif
//获取服务器的地址、端口之类的。 //这个EM_JS是用来声明js函数的,声明之后就可以直接在c++里面用了。 EM_JS(const char*, getTitle, (), { var urlPath = window.document.location.href; console.log(urlPath);
var jstring = urlPath;
var lengthBytes = lengthBytesUTF8(jstring)+1; var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jstring, stringOnWasmHeap, lengthBytes); return stringOnWasmHeap; }) void MainWindow::on_pushButton_download_clicked() {
#ifdef Q_OS_WASM //执行js程序,这个是直接执行的。 EM_ASM({ window.open("http://127.0.0.1/resources/main.cpp"); }); #endif
//前面用EM_JS声明的函数 const char *str = getTitle(); qDebug() << str; free((void*)str); }
|
文件的上传这样(这个是会读取整个文件内容的)
1 2 3 4 5 6 7 8 9 10 11
| void something(const QString &name, const QByteArray &content) { qDebug() << "name:" << name; qDebug() << "content" << content; } void MainWindow::on_pushButton_clicked() { // QFileDialog::getSaveFileUrl(); //这个会打开选择的文件,然后将文件的名称以及内容通过上面的something来反馈出来。对于小文件的处理应该是够了。 QFileDialog::getOpenFileContent("*", something); }
|
2.6.设置调试时的网页浏览器
调试时默认为ie,可以更改为其他浏览器

假如你这里的列表有ie一个,但是实际上你已经装了其他浏览器;那么,你需要在电脑的环境变量path上加上你的浏览器的路径,然后重启QtCreator

2.7.编译时报空间太小
wasm-ld: error: initial memory too small, 18222032 bytes needed
【解决 wasm-ld: error: initial memory too small, 18319040 bytes needed】
修改emsdk/upstream/emscripten/src目录里面的settings.js
里面的 INITIAL_MEM 旧版叫 TOTAL_MEMORY
或者在pro文件中增加
1 2
| #值为64KB的倍数 wasm:QMAKE_LFLAGS += -s \"TOTAL_MEMORY=33554432\"
|
2.8.编译时报 The program “mingw32-make.exe” does not exist or is not executable.
参考【 QtCreator无法启动进程“mingw32-make.exe】
到project里面看,的确是没有找到这个mingw32-make.exe.
ok,用everything来查看一下,这个东西在哪里。
有好几个,但我用的是Qt5.15.2版本的,所以我选择这个:D:\Qt5.15\Tools\mingw810_64\bin\mingw32-make.exe。
将这个:D:\Qt5.15\Tools\mingw810_64\bin路径加到环境变量path中去。

重启一下QtCreator就好了。
在.pro文件中添加:
2.10.获取服务器IP(不适用于域名访问的方式)
参考:【Getting server IP within wasm application】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #ifdef Q_OS_WASM #include <emscripten.h> #include <emscripten/val.h> #include <emscripten/html5.h> #endif
// ---这是第一种方式--- void getServerInfo1() { #ifdef Q_OS_WASM emscripten::val location = emscripten::val::global("location"); auto host = QString::fromStdString(location["host"].as<std::string>()); auto port = QString::fromStdString(location["port"].as<std::string>()); qDebug() << "Server Host:" << host; qDebug() << "Server Port:" << port; #endif }
// ---这是第二种方式--- //获取服务器的地址、端口之类的。 //这个EM_JS是用来声明js函数的,声明之后就可以直接在c++里面用了。 EM_JS(const char*, getTitle, (), { var urlPath = window.document.location.href; console.log(urlPath);
var jstring = urlPath;
var lengthBytes = lengthBytesUTF8(jstring)+1; var stringOnWasmHeap = _malloc(lengthBytes); stringToUTF8(jstring, stringOnWasmHeap, lengthBytes); return stringOnWasmHeap; })
|
2.11.Qt5.15.2的webAssembly版本不支持多线程
因为不支持多线程,因此无法使用QEventLoop,因为一旦调用QEventLoop::quit(),程序就会退出Qt主循环。
【Qt for WebAssembly官网介绍】
【Qt WebAssembly Platform Notes】

而试图同步QNetwrokReply的数据获取,也是不可能的。哪怕你如此处理,整个系统还是会卡住。
do{
qApp->processEvents(); // 这个函数没有生效
}
while(reply->isFinshed() == false)
难搞。
貌似qt6的webAssembly版本才支持多线程,但是我的代码是Qt5的,Qt6在qml上与Qt5差异挺大,所以我换不了Qt6.
