介绍
构建客户端程序,常见的选项可能包括mfc、wtl、qt等。最近很多公司也选择使用CEF3来构建他们的客户端程序。由于 CEF3 正是一个浏览器核心,大部分工作都可以通过 JavaScript 来完成,这使得它在资源占用巨大的情况下具有极大的灵活性。虽然一些新的 UI 框架也提供了脚本模块,但它们不能提供程序员可以像 CEF3 那样仅基于脚本完成项目的能力。我想,一个脚本能力完整、体积小巧、效率高的客户端框架应该是客户端程序的不错选择。
代码模块
在源码包中,我们提供了soui4.08.sln和soui4.22.sln。选择一个喜欢的 sln 来打开并构建所有模块,然后运行SLuaDemo.ex。你会看到它是如何工作的。
整个解决方案包括八个模块:
utilities4
,该模块提供了一些基本的工具类,例如SStringA
,SStringW
,SXml
(的包装pugixml
)。soui-system-resource
,该模块是一个简单的资源容器。soui4
,模块为核心模块,提供直接的UI框架。imgdecoder-gdip
,gdiplus
用于进行图像解码的模块。在整个 git repo 中还有其他替代品,例如 wic、stb、png。render-gdi
,渲染模块,基于GDI api将绘图渲染到位图。render-skia
在整个 git repo 中可用,它提供了比 gdi 高得多的效率。lua-54
,lua引擎。在这里,我们使用的是 lua 5.4.4。ScriptModule-lua
, 将使用的 COM 接口导出到 lua 的模块。我们使用lua_tinker
( https://github.com/zupet/LuaTinker ) 将我们的接口导出到 lua。我们更新lua_tinker
支持x64,在Visual Studio 2008可以支持WINAPI等调用模式(好像2015+没有这个问题)。SLuaDemo
,可执行模块,它演示了如何集成上述模块来构建客户端程序并在 lua 脚本中执行所有逻辑。
下面_tWinMain
展示了如何开始演示。这些代码只合成了组成演示的必要组件,没有做任何实际的逻辑。
所有实际逻辑都位于main.lua
. 在解释代码之前main.lua
,我先简单解释一下资源包和布局XML。在soui
中,所有可绘制对象都定义为ISkinObj
。
资源包的主要用途之一是定义ISkinObj
由 XML 和图像文件描述。
由于我们已经定义了必要drawable(ISkinObj)
的,我们可以ISkinObj
在布局 XML 中按名称引用它们。soui 布局的语法与 Android 布局非常相似。Soui 提供了三种主要的布局类型,包括线性布局gridlayout
和锚点布局。Anchor 布局类似于 Android 中的相对布局,但在我看来更灵活。例如,空白布局可能如下所示:
所有资源文件都在uires.idx文件中编制索引。
定义好 UI 布局后,我们可以在main.lua
.
从上面的lua脚本中,我们可以看到基本的步骤包括:
- 创建一个
resprovider
对象并根据resprovider
创建的类型使用文件路径或其他源对其进行初始化。资源类型可以是文件路径、DLL 或 zip 文件等。然后将其添加到应用程序中。 - 创建一个宿主窗口对象,并使用之前资源包中定义的资源名称对其进行初始化。然后调用
hostWnd:create
创建一个hwnd
并调用hostWnd:ShowWindow
显示。 - 按名称查找子项并将其事件连接到响应函数。
好的,仅此而已!
如何将 C++ 对象导出到 Lua
我们lua_tinker
用来做这项工作。类似的代码可能包括luabind、tolua++等。其他包我不熟悉。在使用中lua_tinker
,我发现如果我尝试导出复杂的类,例如一个类有多个基类,它可能会做错事。幸运的是,我们已经使用 COM 实现了所有接口,并且lua_tinker
支持 COM 足以将它们导出到 lua。如果你想知道在 lua 脚本中可以使用哪些类或 API,请查看 module 的源代码scriptmodule-lua
。您将看到如下代码:
使用该代码,我们导出了一个名为的 COM 接口IObjRef
,其中包含三个方法。因此,如果我们得到一个IObjRef
对象并将其存储到变量obj
中,我们可以调用obj:AddRef
来添加对该对象的引用。
完整的 soui4 存储库
在源代码包中,这里只展示了使用的模块。soui 的重要思想之一是为看起来像插件的外部模块提供可替换的模块。您可以在完整的 git 存储库中找到许多功能相似的模块。我们将 soui4 存储在 github 中,GitHub - soui4/soui。