前言
PowerBuilder作为开发工具退出一线行列已经很久了,在2019年来谈这样一款老旧的编程工具是否有意义?诚然,PB有着太多硬伤,但还是有它的用武之地的。而且今天讲的这个“新思维”大部分内容是我在其它地方没有见过的,包含一些比较新的思想,但愿能够给各位读者带来耳目一新的感觉和有价值的参考。
由于内容比较多,打算合起来作为一个库,名字叫PowerPlume,中文为“孔雀翎”,古龙书中强大又美丽的武器。
PowerBuilder编程新思维1:扩展(Lua)
PB环境是封闭的,导致有些部分的能力极弱,依赖开发各类DLL和扩展(PBNI)。把脚本语言引擎引入到PB中,有着很多的现实意义,最大的好处就是能够直接利用脚本语言的各类资源与源码,不用再重复开发。
常见的脚本语言有JS、Python、Ruby等,为什么选择Lua?因为小、因为快。JS由于历史原因,太庞大了。Python和Ruby也不是很小巧。而且环境配置复杂。Lua小巧,接口也很友好,资源也丰富。
接口方面,选择PBNI而不是直接使用DLL,是因为需要处理一些指针和支持PowerObject,总体与LuaApi基本一致。
- global type n_lua from nonvisualobject native "pblua105.dll"
- public function long register(string name, powerobject obj)
- public function long setglobal(string name)
- public function long getglobal(string name)
- public function long setfield(long idx, string key)
- public function long getfield(long idx, string key)
- public function long pushnil()
- public function long pushboolean(boolean value)
- public function long pushlong(long value)
- public function long pushdouble(double value)
- public function long pushstring(string value)
- public function long pushpowerobject(powerobject value)
- public function long toboolean(long idx, ref boolean value)
- public function long tolong(long idx, ref long value)
- public function long todouble(long idx, ref double value)
- public function long tostring(long idx, ref string value)
- public function long topowerobject(long idx, ref powerobject value)
- public function boolean isboolean(long idx)
- public function boolean islong(long idx)
- public function boolean isdouble(long idx)
- public function boolean isstring(long idx)
- public function boolean ispowerobject(long idx)
- public function boolean isnil(long idx)
- public function boolean istable(long idx)
- public function long spop(long n)
- public function long scopy(long idx)
- public function long sinsert(long idx)
- public function long sremove(long idx)
- public function long sreplace(long idx)
- public function long sgettop()
- public function long createtable(long arr, long rec)
- public function long settable(long idx)
- public function long gettable(long idx)
- public function long setmetatable(long idx)
- public function long nextkey(long idx)
- public function long docall(long args, long results)
- public function long dofile(string path)
- public function long dostring(string str)
- public function long enablecall(boolean ui)
- end type
最先实现的功能是在Lua中很简单,PB却无法提供的功能——HashTable。
实例:function integer of_map_set (string as_table, string as_key, powerobject an_value)
在Lua接口基础上,添加了pushpowerobject这个接口,以处理PB对象。
- int ret
- ret = api.getglobal(as_table)
- if (ret = LUA_TNIL) then
- api.createtable(0, 0);
- elseif (ret <> LUA_TTABLE) then
- return FAILURE
- end if
- api.pushstring(as_key)
- api.pushpowerobject(an_value)
- api.settable(-3);
- if (ret = LUA_TNIL) then
- api.setglobal(as_table)
- end if
-
- return SUCCESS
其次,必须利用Lua中比较成熟的资源,可以在https://luarocks.org/上查找下载数较多的模块,放入lib\lua目录下即可require。需要注意的是我们使用的是最新的Lua53,有些库可能不兼容。在源码中已经放入socket(http,ftp,stmp),xml,json库。后续会陆续补上相关的封装接口。
实例:使用cjson模块解析json
- 1 string res
- 2
- 3 i_lua.api.dostring("return require('cjson')")
- 4 i_lua.api.pushstring('decode')
- 5 i_lua.api.gettable(-2)
- 6
- 7 if (not i_lua.api.isfunction(-1)) then
- 8 messagebox("","error")
- 9 end if
- 10
- 11 i_lua.api.pushstring(mle_json.text)
- 12 i_lua.api.docall(1,1)
- 13
- 14 i_lua.api.pushstring("sites")
- 15 i_lua.api.gettable(-2)
- 16
- 17 string key,val
- 18 integer idx
- 19 idx = i_lua.api.sgettop()
- 20
- 21 i_lua.api.pushnil()
- 22 do while i_lua.api.nextkey(idx)<>0
- 23 i_lua.api.pushstring("name")
- 24 i_lua.api.gettable(-2)
- 25 i_lua.api.tostring(-1, val)
- 26 i_lua.api.spop(2)
- 27 tv_1.InsertItemFirst(0,val,1)
- 28 loop
- 29
- 30 i_lua.api.spop(3)
另外,在构建PowerPlume这个库的时候,整体架构在Lua这个模块之上,主要是利用其HashTable这个功能。
效果及源码

源码: PowerPlumeDemoV0.1.1.rar
提供了PB10.5 PB11.5 PB12.5三个版本
<本节完>