试用跨平台 GUI 框架 HaxeUI
HaxeUI 是一款跨平台 GUI 框架,支持网页、桌面和移动端。 框架前端使用 Hexo 语言开发。框架后端使用图形引擎或者原生跨平台 GUI 框架,比如 OpenFL, NME, Kha,PixiJS, wxWidgets, Winforms 等。最终生成 C++ 代码编译成本地可执行文件或者 HTML 代码。在各种后端中,除了 wxWidgets 和 Winforms 使用原生组件外,其他都是使用图形引擎绘制或者生成 HTML 代码。

Haxe 也是一个比较有意思的语言。它本身不能进行本地编译,而是转译成其他语言,比如 Lua, PHP, Java, Python, C++, C# 等,也可以编译成 Neko 或 HashLink 虚拟机的字节码(详见 Haxe Compiler Targets)。Haxe 语言诞生于 2005 年,算是历史久远了,然而其社区却一直不温不火,网上也很难找到中文资料。 Haxelib 上的开发者提交的三方库数量和 Python 的 PyPi 相比,只能说是聊胜于无。
看来也不能对 HaxeUI 抱有太大的希望,让我先在 Windows 上尝试看看。
安装开发环境
首先安装 Haxe 和 HaxeUI(此处使用 Scoop 进行安装):
shellscoop install haxe
haxelib install haxeui-core
通过 haxelib run haxeui-core install
命令可以查看 HaxeUI 支持的后端:
ERROR: no backend specified
Please use one of the following:
html5 | hxwidgets | openfl | nme | pixijs | kha | winforms | android | flixel | electron | qt | heaps | raylib | pdcurses | tauri
然而奇怪的是,命令返回的可选后端和官网文档不一致,而且 android, flixel, electron, qt, heaps, raylib, pdcurses, tauri 这几个后端都不可用。不知道是操作系统的平台限制还是这玩意儿根本就是半成品。
本文仅测试跨平台桌面版,选用 haxeui-hxwidgets, haxeui-openfl, haxeui-nme 和 haxeui-kha 四个后端。
haxeui-hxwidgets
haxeui-hxwidgets 是 HaxeUI 的 wxWidgets 后端。 它生成一个通过 wxWidgets 框架从本机组件构建的 GUI 。
可以通过 haxeui-core 自动安装 hxWidgets 后端所依赖的库:
shellhaxelib run haxeui-core install hxwidgets
也可以手动安装:
shellhaxelib install hxcpp
haxelib install hxwidgets
haxelib install haxeui-hxwidgets
此外还需要下载并编译 wxWidgets 的 C++ 库。我尝试了使用 vcpkg install wxwidgets
来安装编译,但是 HaxeUI 似乎无法识别,只能通过手动安装。
- 从 https://www.wxwidgets.org/downloads/ 下载 wxWidgets 最新版本,目前最新版本是 3.2.4 ;
- 解压后保存在任意路径下,此处路径为 C:\wxWidgets-3.2.4 ;
- 开始菜单中的 Visual Studio 项目下,选择 x86 Native Tools Command Prompt for VS 2022 ,打开编译环境命令行窗口;
- 执行命令编译:
shell
cd /d C:\wxWidgets-3.2.4\build\msw\ nmake -f makefile.vc BUILD=release nmake -f makefile.vc BUILD=release SHARED=1
如果编译成功,则会在 C:\wxWidgets-3.2.4\lib 目录下生成 vc_lib 和 vc_dll 两个目录。
使用下面的命令在当前目录下创建一个 haxeui-hxwidgets 项目:
shellhaxelib run haxeui-core create hxwidgets
在编译项目之前需要先设置一个名为 WXWIN
的环境变量指示 wxWidgets 的安装路径:
shellset WXWIN=C:\wxWidgets-3.2.4
在 PowerShell 命令行下则使用:
powershell$ENV:WXWIN="C:\wxWidgets-3.2.4"
使用如下命令编译 haxeui-hxwidgets 项目:
shellhaxelib run haxeui-core build hxwidgets
默认配置下,编译会链接 wxWidgets 静态库。可以编辑项目根目录下的 hxwidgets.hxml 配置文件,将 -D WXSTATIC
修改为 -D WXDLL
来启用动态库链接。
需要注意的是,默认编译出来的程序无法正确显示中文字符。其原因是 hxWidgets 会将用户界面上的字符串都转换成 UTF-8 编码,而 Windows 不同于 Linux 系统,中文环境默认使用 GBK (CP936) 编码。要解决这个问题,还需要通过 Manifest 来指定程序的编码。
首先,创建一个 Manifest.xml 文件,内容如下:
xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity type="win32" name="MyHaxeUIApp" version="6.0.0.0"/>
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>
然后执行:
shellmt -manifest Manifest.xml -outputresource:Main.exe;#1
mt.exe 并不在默认的 PATH 路径下,而是由 Windows Kits 提供。要在命令行中执行该命令,可以在之前的 x86 Native Tools Command Prompt for VS 2022 命令行窗口中执行。
由于 hxWidgets 使用了原生控件,因此其控件样式无法随意更改,比如不支持 font-style
设置控件的字体样式等。
haxeui-openfl
haxeui-openfl 是 HaxeUI 的 OpenFL 后端。
可以通过 haxeui-core 自动安装 OpenFL 后端所依赖的库:
shellhaxelib run haxeui-core install openfl
haxelib run openfl setup
也可以手动安装:
shellhaxelib install haxeui-openfl
haxelib install openfl
haxelib run openfl setup
使用下面的命令在当前目录下创建一个 haxeui-openfl 项目:
shellhaxelib run haxeui-core create openfl
使用如下命令编译 haxeui-openfl 项目:
shellhaxelib run haxeui-core build openfl windows
同样需要注意的是,默认编译出来的程序也无法显示中文字符。和 hxWidgets 不同的是, OpenFL 不是由于编码问题,而是由于 OpenFL 无法使用系统的中文字体导致的。我们可以打包一个中文字体来显示中文。
OpenFL 支持 OTF 和 TTF 格式的字体文件,不支持 TTC 格式的文件文件。TTC 是一系列字体的打包集合文件,可以转换成 TTF 格式。
下载思源宋体,将 source-han-serif.otf 字体文件存放在项目 assets/fonts 路径下。编辑项目根目录下 application.xml 文件,在 <project>...</project>
中添加一行:
xml<assets path="assets/fonts" rename="fonts" />
在 main-view.xml 中使用中文字体:
xml<style>
.button {
font-size: 12px;
font-name: "fonts/source-han-serif.otf";
}
</style>
另一个比较严重的问题是,OpenFL 后端的文本框在开启输入法时无法显示输入法候选窗口。虽然能够输入中文,但这相当于在盲打了。这个缺陷导致该后端几乎无法在生产环境中使用。
OpenFL 的本地编译的后端是 lime ,而 lime 的后端又是 SDL ……这层层套娃的关系导致想要定位问题都比较困难。
除此之外,偶尔发生菜单排版错乱,同时按钮失效的问题(遇到过几次,暂时还不清楚触发的条件);还有偶尔会触发 TextField 崩溃弹框提示 Invalid object 的问题。

haxeui-nme
haxeui-nme 是 HaxeUI 的 NME 后端。
可以通过 haxeui-core 自动安装 NME 后端所依赖的库:
shellhaxelib run haxeui-core install nme
haxelib run nme setup
也可以手动安装:
shellhaxelib install haxeui-nme
haxelib install nme
haxelib run nme setup
使用下面的命令在当前目录下创建一个 haxeui-nme 项目:
shellhaxelib run haxeui-core create nme
使用如下命令编译 haxeui-nme 项目:
shellhaxelib run haxeui-core build nme windows
与 hxWidgets 和 OpenFL 这两个后端相比,这个后端还算省心,默认编译就能显示中文,只是默认字体有点丑。也可以像 haxeui-openfl 一样,通过编辑 project.nmml 项目配置文件来添加自定义字体。
此外,和 OpenFL 一样,NME 后端的文本框在开启输入法时也无法显示输入法候选窗口,而且一次只能输入一个中文字符,无法输入词语短句。另外还存在输入光标丢失、选中文本后文本不可见等诸多问题。
haxeui-kha
haxeui-kha 是 HaxeUI 的 Kha 后端。安装此后端需要从 GitHub 上下载几百兆的编译环境。最后编译失败,原因不明,也懒得折腾。放弃。
haxeui-flixel
haxeui-flixel 是 HaxeUI 的 flixel 后端。
奇怪的是,haxeui-flixel 无法通过 haxelib run haxeui-core install flixel
命令进行安装,提示 Install not found for "flixel"
错误。
手动安装 haxeui-flixel 后端:
shellhaxelib install flixel
haxelib install haxeui-core
haxelib install haxeui-flixel
haxelib run lime setup flixel
使用下面的命令在当前目录下创建一个 haxeui-flixel 项目:
shellhaxelib run haxeui-core create flixel
另外,使用 haxeui-flixel 后端的项目也无法使用 haxelib run haxeui-core build flixel windows
之类的命令进行构建,提示如下错误:
ERROR: no build found
Invalid field access : execute
Flixel 底层基于 Lime,因此可以用如下命令构建:
shelllime build windows
需要注意的是,Flixel 和 OpenFL 一样使用 Project.xml 作为项目配置文件,因此同一个项目需要同时使用 OpenFL 和 Flixel 后端会比较麻烦。
Flixel 主要用于开发像素类游戏,因此内置的是一种像素风的字体,不太适合作为通用应用的后端。且和 OpenFL 后端有同样的问题——默认不支持渲染非英文字符。
haxeui-heaps
haxeui-heaps 是 HaxeUI 的 Heaps 后端。
Heaps 也是一款游戏引擎框架,不过它不支持转译成 C++ 编译。只能编译为 HTML 5 或者 HashLink 虚拟机字节码。该后端的实用性不大,因此本文不做测试。
haxeui-raylib
haxeui-raylib 是 HaxeUI 的 Raylib 后端。
特别地,使用命令 haxelib run haxeui-core install raylib
无法安装 haxeui-raylib,而使用 haxelib install haxeui-raylib
会提示如下错误:
Error: Failed with error: No such Project : haxeui-raylib
另外,使用 haxeui-raylib 后端还需要依赖 raylib-haxe。但是通过 haxelib 安装的 raylib-haxe 版本太旧,无法正确编译。我们只能从 GitHub 安装最新的版本:
shellhaxelib git raylib-haxe https://github.com/haxeui/raylib-haxe
haxelib git haxeui-raylib https://github.com/haxeui/haxeui-raylib
不得不说,这个 HaxeUI 还真是个半成品呀~
使用下面的命令在当前目录下创建一个 haxeui-raylib 项目:
shellhaxelib run haxeui-core create raylib
使用如下命令编译 haxeui-raylib 项目:
shellhaxe raylib.hxml
和 Flixel 相似,Raylib 后端默认也是用像素风格的字体,且默认不支持渲染非英文字符。
总结
HaxeUI 内置的控件十分丰富,在使用图形引擎后端的情况下,基本能保持不同平台下界面布局和样式的一致性。但是各种小问题也很多,特别是对 i18n 的支持有很多问题。
下面列举了一些主要问题:
- 有些后端不可用,或者是我打开的方法不正确
- haxeui-nme 和 haxeui-openfl 都是通过 SDL 图形引擎绘制控件,这会引起一些兼容性问题:
- NME 默认能够支持中文,但 OpenFL 需要额外的代码才能显示中文
- 两者编译的 Linux 版皆无法在 WSL 2 内置的 MSRDC 中正常渲染,必须使用 X11 Server 才行
- 只有 haxeui-hxwidgets 后端能够在中文环境下正常工作(虽然也有 UTF-8 乱码问题需要另外解决),其他后端都有中文显示或者输入的问题未能解决
- haxeui-hxwidgets 使用原生控件,对于非标准布局程序运行时会报错:
对于桌面应用,在这些后端里唯二可用的便是 OpenFL 和 wxWidgets,其他后端可以不用考虑。
浅析 OpenFL 中文显示问题
后续稍微分析了一下 OpenFL 的源代码,大致弄清楚 OpenFL 为何默认无法显示中文了。
查看 src/openfl/text/_internal/TextEngine.hx 中的 getDefaultFont()
函数实现。OpenFL 内置了三组字体,分别是 _sans
, _serif
和 _typewriter
。这三组字体在 Windows 中分别对应了 Arial
, Times New Roman
和 Courier New
。这三组字体都是英文字体,不包含中文字形。而 haxeui-openfl 组件默认使用 _sans
字体,因此无法渲染中文字符。
haxe#if windows
__defaultFonts.set("_sans",
new DefaultFontSet(findFont(systemFontDirectory + "/arial.ttf"), findFont(systemFontDirectory + "/arialbd.ttf"),
findFont(systemFontDirectory + "/ariali.ttf"), findFont(systemFontDirectory + "/arialbi.ttf")));
__defaultFonts.set("_serif",
new DefaultFontSet(findFont(systemFontDirectory + "/times.ttf"), findFont(systemFontDirectory + "/timesbd.ttf"),
findFont(systemFontDirectory + "/timesi.ttf"), findFont(systemFontDirectory + "/timesbi.ttf")));
__defaultFonts.set("_typewriter",
new DefaultFontSet(findFont(systemFontDirectory + "/cour.ttf"), findFont(systemFontDirectory + "/courbd.ttf"),
findFont(systemFontDirectory + "/couri.ttf"), findFont(systemFontDirectory + "/courbi.ttf")));
如果 OpenFL 要使用中文字体,可以在代码中添加:
haxeopenfl.text.Font.registerFont(openfl.text.Font.fromFile(lime.system.System.fontsDirectory + "/simhei.ttf"));
然后还要在视图中显式定义字体:
html<style>
* {
font-name: SimHei;
}
</style>
暂时没有通用的解决方案,针对不同的语言环境,必须显式定义不同的字体。
而 NME 后端之所以能正常显示中文是因为 NME 使用了本地 C++ 代码,直接调用 Windows 字体渲染接口,实现了 Fallback Font 的特性。