Project1

标题: RMXP多窗体 v2.0 [打印本页]

作者: SixRC    时间: 2017-11-1 20:21
标题: RMXP多窗体 v2.0
本帖最后由 SixRC 于 2017-11-2 08:05 编辑

新开一主题 因为改了很多 解决了很多上一版本的问题
这次写了好多天 写到今天终于感觉 几乎是差不多了吧
果然代码还是要慢慢慢慢写 涂涂改改涂涂改改才好发布的
那么 现在由我来介绍 这次版本的优点
1.窗口独立 大小随意 这次是真独立
独立的鼠标键盘消息获取 独立的窗口焦点 独立的关闭
和主窗口没有关联了 你可能会担心窗口失去焦点带来的不刷新的问题
所以第二点
2.支持后台运行 你可以指定后台运行与否
即使失去焦点也会继续刷新
你也可以直接不要显示窗口 当作多线程来用..
3.支持消息传递
虽然只支持四个整数的传递 不过可以传指针 实际上是没什么问题的
4.内存释放优化
这个想了很久 不过大多失败了
不过后来发现简单的做法似乎是最有效的
5.使用方便 很方便了
只要给它运行的代码 告诉他窗口多大放哪里显不显示等等
用完了判断一下是否结束就可以了

具体使用说明请见脚本
RMXP多窗体 v2.0


然后是一些实现上的细节
模仿了exe加载rgss的方式加载了新的rgss 开始问题很多 不过慢慢都解决了
在RGSSGameMain那里我直接pass掉了控制线程的建立(原来用来检查10s和关闭进程用)
注入了rgss原来的窗口消息处理机制 所以收到 0x10 的VM_CLOSE可以自己控制怎么关掉
后台运行由改掉一个跳转实现 rgss收到 0x1C WM_ACTIVATEAPP  会把一个变量改成1 判断为1则刷新否则继续循环
窗口的建立综合了createwindowex和rgss 在前者确定x和y 后面确定宽高
在加载RSS103J的时候dllmain会建立一个heap freelibrary的时候它又会释放掉 所以只需要free就能解决很大程度上的内存泄漏
位图和精灵则通过dispose 音频暂时没有处理 余下的大约是增加了3M 其中1M是实例带来的 所以实际上只有2M没释放 可以说是很少了
我猜是gdi对象 大概字体啥的 没释放吧
等等等等暂时没想那么多了就这样吧

欢迎提出建议 不过不一定会解决就是了

然后是一个范例:
RMXP多窗体v2.0范例.zip (746.22 KB, 下载次数: 187)
能很好的帮助理解脚本的使用
范例配图


作者: imsy    时间: 2017-11-1 20:53
本帖最后由 imsy 于 2017-11-1 23:25 编辑

虽然对“当作多线程来用”非常感兴趣但是范例闪退……

无论是双击game.exe、从工程测试还是管理员身份运行,都直接窗口出现一两秒后直接没有了,什么内容都还没显示就消失了……
Ewindow文件夹里有两个dll和两个rxdata。
32位Win7系统,也许是个例吧,楼主可以等等看别的坛友

在main里到处加p找是在哪里出问题的,然后定位在了p1.run这里,这以上的p都p出来了,后面的没出来就闪退了。


楼主更新了主楼的脚本,现在已经可以使用了



作者: fux2    时间: 2017-11-2 10:15

我还以为是黑Graphics在多个窗口上画,没想到这么高端,连内存都独立了

作者: Tian_Ya    时间: 2018-2-5 23:52
关于前辈的RMXP多窗体 v2.0
请问能否实现,生成的窗体跟随主窗体的移动而移动
要如何做到呢?
作者: SixRC    时间: 2018-2-6 16:40
本帖最后由 SixRC 于 2018-2-6 16:43 编辑
Tian_Ya 发表于 2018-2-5 23:52
关于前辈的RMXP多窗体 v2.0
请问能否实现,生成的窗体跟随主窗体的移动而移动
要如何做到呢? ...


RUBY 代码复制
  1. #随主窗口移动而移动
  2. hm = Win32API.new('kernel32','GetModuleHandleA','p','l').call('RGSS103J')
  3. code = [139,68,36,4,139,128,196,182,18,0,139,64,8,194,16,0].pack('C*')
  4. $main_hwnd = Win32API.new('user32.dll','CallWindowProc','pllll','l').call(code,hm,0,0,0)
  5. xy = ' '*16
  6. Win32API.new('user32','GetWindowRect','lp','v').call($main_hwnd,xy)
  7. $main_xy = xy.unpack('ll')
  8. class << Graphics
  9.   GetWindowRect = Win32API.new('user32','GetWindowRect','lp','v')
  10.   MoveWindow = Win32API.new('user32','MoveWindow','llllll','l')
  11.   alias e_update update
  12.   def update
  13.     xy = ' '*16
  14.     GetWindowRect.call($main_hwnd,xy)
  15.     if (xy1 = xy.unpack('ll')) != $main_xy
  16.       GetWindowRect.call(Ewindow::Hwnd,xy)
  17.       xy2 = xy.unpack('llll')
  18.       MoveWindow.call(Ewindow::Hwnd,xy2[0]+xy1[0]-$main_xy[0],
  19.                                    xy2[1]+xy1[1]-$main_xy[1],
  20.                                    xy2[2]-xy2[0],
  21.                                    xy2[3]-xy2[1],0)
  22.       $main_xy = xy1
  23.     end
  24.   e_update
  25.   end
  26. end


把它插到子窗口的脚本前面就可以了
哪个或哪些个子窗口需要随着主窗口动而动就插过去
子窗口需要是后台运行的
原理是检测主窗口的位置 他动了子窗口就跟着动 所以每次update会刷新位置
子窗口自己移动不会影响主窗口 测试了下效率和效果蛮好的
作者: Tian_Ya    时间: 2018-2-7 14:59
SixRC 发表于 2018-2-6 16:40
#随主窗口移动而移动
hm = Win32API.new('kernel32','GetModuleHandleA','p','l').call('RGSS103J')
code ...

同样的窗口x,y坐标在不同分辨率的电脑生成的位置不同
作者: 黑白无双    时间: 2018-2-21 20:33
不错,感谢楼主分享。




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1