Ruby 偿试在 Windows 7 下用 Ruby 2.7 开发桌面应用程序框架,寻求 ruby-core 技术支持

yxmmrwx · 2020年08月05日 · 最后由 yxmmrwx 回复于 2022年03月27日 · 2332 次阅读

很喜欢 ruby,现在偿试用 ruby 在 windows7 下开发一个桌面应用程序框架,已有些雏形,但碰到内存有点猛增的样子,不得门道,想问一下有没有谁知道如何联系 ruby-core 组的成员(最好是能看得懂中文的),我想知道要做个应用程序框架,能不能得到他们的技术支持,以增强信心去完成这个偿试。因为也不知道后面还会碰到什么问题,为了完成心愿,都有点想要自己捣鼓个自己能掌控的脚本语言了

坑很大,不建议用 Ruby 开发桌面软件,即使 Ruby 中用的最多的 shoes 也好多年没更新了,说明市场动力不足。 非要用 ruby 开发 桌面应用,其实需要自己慢慢地搭底层,得不偿失。 每一种语言都有适合的场景,非要选择一门自己很喜欢,但是这门编程语言不擅长的领域,效果并不理想。

用 rails 做成 web 应用?

C# WinForm/WPF 不香吗?

还是 electron 吧

Windows 7 都 EOL 了吧

以前想在厨房里面打个洞,拿起我最爱的菜刀,这刀帮我切了 N 多可口的菜肴。多好啊,打个洞不成问题吧,砍了半天,最终未能如愿,弄了个电钻,2 分钟解决。啥道理?用合适的工具解决问题,而不是你喜欢。ruby 真的是和 rails 绑在一起的,开发桌面软件?换工具吧。

我很久之前也尝试了下做一个 Windows 下的 Ruby GUI 框架,基本就是在 C-ext 里包装 Win32API,然后展示一个比较简洁友好的(类似 Shoes / REBOL view)的编程环境。

代码在 https://github.com/luikore/cici2 可以参考下,只是现在 Ruby / Windows API 已不同跑不起来了。

有些坑分享一下:

  • Windows API 有 A 系列和 W 系列,和 UTF-8 编码的 Ruby 程序一起工作要经常转码比较麻烦。
  • 在 C 里调用 Ruby 代码,如果出现异常不捕获会 Segfault,需要了解清楚 C extension 的机制。
  • 得找机会给 Ruby GC,或者用独立线程跑 Ruby。
  • 两个世界文化很不妥贴,用 Visual Studio 编译 Ruby 可以 debug 进去。

如果让我再来一遍的话,我会选择改造成两个进程:一个 Ruby 进程负责处理事件和返回 DOM tree,一个原生 GUI 进程负责转发事件给后面的 Ruby 进程。这样就可以避掉上面的一些坑并且可以统一处理好转码。GUI 进程用纯 C 的 Win32 API 搞,或者现在流行的什么 WPF 搞都可以了。

参考书就是特别古老的 Programming Windows。

内存猛增先查是不是泄漏,再查在哪里泄漏,找 rubycore 不会有帮助

.net WPF 他不香么,人生苦短

推荐 ironruby 虽然不开发了,但是做桌面足够了

还好,坚持做了,有点收获了

这是配置文件的样子 { applications{

aio(CAppDemo){

title=mls "aio 测量系统" version="0.0.2" software_version="0.0.0"

font_name=mls "宋体" font_size=30

prop_int=127{ title=mls "亮度" default=0 llimit=0 ulimit=444 mouse_wheel=1.0

} def_prop_cmd_line

begin_def_measure_val{

prop_mesure_float=-0.0{ title=mls "半径" unit=UnitTypeMM

std=0.0 correct=0.05 llimit=-0.5 ulimit=0.5 }

end_def_measure_val}

light_adj=127{ title=mls "亮度" }

app_idle_time=0.0{ title=mls "程序空闲时间" unit=UnitTypeMS format="%6.3f" editable=false #read_only= true }

app_idle_proc_time=0.0{

title=mls "程序空闲处理时间" unit=UnitTypeMS format="%6.3f" }

worktable{ pos{ x=0.0{ title=mls "X" llimit=-100.0 ulimit=100.0 } y=0.0{ title=mls "Y" } ff=0.0{ title=mls "Z" } } }

time_for_show_caret=0.5{ title=mls "定时显示光标"

llimit=0.1 ulimit=1.0 mouse_wheel=0.01 unit=UnitTypeMS

}

ui_config=false{ title="配置 UI" }

test_mesure_val=0{

}

length_unit=UnitTypeMM{ title=mls "长度单位" vals=[UnitTypeMM,UnitTypeInch,UnitTypeMil] } angle_unit=UnitTypeDu{ title=mls "角度单位" vals=[UnitTypeDu,UnitTypeHuDu,UnitTypeDFM] } time_unit=UnitTypeS{ title=mls "时间单位" vals=[UnitTypeH,UnitTypeM,UnitTypeS,UnitTypeMS,UnitTypeUS] } vel_unit=UnitTypeMMPerS{ title=mls "速度单位" vals=[UnitTypeMMPerS,UnitTypeDuPerS,UnitTypePlusPerS] } show_dyn_prompt=true{ title=mls "显示动态提示" } user_type=PermissionUser{

}

} } }

这是 UI 配置的样子 PermissionUser.password="" PermissionEngine.password="1" PermissionAdmin.password="11" PermissionSuper.password="111"

{ (CWinDlg, NameFrmMain){ (CWinTitleBar, at: AlignTypeTop, as: AlignSizeToTextHeight, name: NameAppTitleBar){ new_btn(FunWinClose) new_btn(FunWinMaximize) new_btn(FunWinMinimize) new_btn(FunMoveWin) new_btn(FunELine) new_btn(FunERect) new_btn(FunMakeUI) title="aio 测量系统 0.0.0" } (CWinStatusBar, at: AlignTypeBottom, as: AlignSizeToTextHeight, name: NameStatusBar){ (CWin, at: AlignTypeRight, as: 100){ title="CWin_7880" } (CWin, at: AlignTypeRight, as: 150, name: NameCmdStatistics){ title="1/0/1" } new_prop_win($root.os.applications.aio.prop_int, at: AlignTypeRight, as: 200) title="退出" } (CWinPanel, at: AlignTypeRight, as: 1019, name: NameRightBar){ (CWinTab, at: AlignTypeClient, as: 0){ (CWinPropGrid, at: AlignTypeClient, as: 0, name: NameGridAppProp){ (CWin, at: AlignTypeRight, as: 150){ title="CWin_9300" } new_prop($root.os.applications.aio.app_idle_time) new_prop($root.os.applications.aio.app_idle_proc_time) new_prop($root.os.applications.aio.time_for_show_caret) new_prop($root.os.applications.aio.show_dyn_prompt, class: CWinPropbool) new_prop($root.os.applications.aio.refresh_wins) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_int) new_prop($root.os.applications.aio.prop_mesure_float) prop_split=300 title="程序属性" } (CWinPropGrid, at: AlignTypeClient, as: 0, name: NameGridDocProp){ prop_split=300 title="文档属性" } (CWinPropGrid, at: AlignTypeClient, as: 0, name: NameGridCmdProp){ prop_split=300 title="命令属性" } (CWinPropGrid, at: AlignTypeClient, as: 0, name: NameGridActiveEntityProp){ prop_split=300 title="活动图元属性" } (CWinGridReport, at: AlignTypeClient, as: 0, name: NameReport){ title="报表" } active_page=0,NoNotical fir_visible=0 } (CWinPanel, at: AlignTypeTop, as: 300){ (CWinCoorBar, at: AlignTypeClient, as: 0, name: NameCoorBar){ prop_split=274 title="NameCoorBar" } (CWinLightCtrlBar, at: AlignTypeRight, as: 200, name: NameLightCtrlBar){ rings=4 areas=8 title="NameLightCtrlBar" } title="CWinPanel_12760" } title="NameRightBar" } (CWinPanel, at: AlignTypeClient, as: 0){ (CWinCanvas, at: AlignTypeClient, as: 0, name: :canvas){ title="canvas" } (CWinCmdBar, at: AlignTypeBottom, as: 300, name: NameCmdBar){ title="NameCmdBar" } title="CWinPanel_19580" } frm_rect.val=CRect.new [0, 0, 2560, 1600] modal_frm.val= true title="NameFrmMain" } }

Kao,这格式都丢失了~!@#¥%……&*

已经可以运行中进行控件的增删及自由布局,并自动保存改变, UI 的设计不象现有的多数软件是在设计时进行,都在运行时通过鼠标拖拽完成,无需手写代码,真正达到 wysiwyg 的效果了

上面的 UI 配置是程序自动产生的,只有 app 配置是手定的

当然也可以在自动产生的代码中加入手工写的代码来增加控件

配置文件的写法,比其它什么 json,yaml,xml 直观得太多了!

从 CObj 派生的类不需要写 attr_accessor,你只管按路径写法去读写你程序用到的属性,不存在就自动生成,而其默认值就是 nil 例: 写:$root.os.applications.app.main_frm.rect.val=[0,0,640,480] 读:$root.os.applications.app.main_frm.rect.val 这里除了$root 是需要主动生成之外,其它后面的路径节点都是不存在就动态产生,无需在类中先 attr_accessor

完善控件后,用 RAIO(我给这个框架起的名字)在做项目时,程序员只需要用内置的功能就可以用 wysiwyg 的方式快速生成 UI,然后接下来就是直接进入 app 逻辑的编写

需要 登录 后方可回复, 如果你还没有账号请 注册新账号