本帖最后由 pbai 于 2026-8-30 12:52 编辑
本示例适用于 PB 全版本(关键在 Win32 API,与具体 PB 版本无关)。
前面我连发两条回复都走了弯路,这里按论坛里 大自在 给出的正确做法更正,并撤回之前错误的说法:
先纠正一个关键事实
我前两条说「在 Open 事件里写 This.WindowType = response! 就行」是错的。WindowType 是 systemwrite(运行时不可写)属性,PB 官方帮助原文:- In scripts You cannot change a window's WindowType property dynamically at runtime.
复制代码 实测:哪怕写在窗口自己的 Open 事件里,现代 PB(PB9 起)也会报 C0143 且无法编译;之前给的「派生两个窗口」能跑,但属于把问题复杂化了。
大自在 的正确做法:单窗口 + EnableWindow 模拟模态
思路:子窗口在画板里 WindowType 仍设成 popup!(或 main!),完全不去碰 WindowType;要"模态"时,用 Win32 的 EnableWindow 把父窗口禁用掉——父窗口点不动了,视觉和行为就是模态;关闭时再把父窗口启用回来。popup 则不禁用。
外部函数声明(user32.dll):- FUNCTION ulong EnableWindow(ulong hwnd, ulong fEnable) LIBRARY "user32.dll"
- FUNCTION ulong GetWindow(ulong hwnd, ulong cmd) LIBRARY "USER32.dll" ALIAS FOR "GetWindow"
- FUNCTION ulong GetParent(ulong hwnd) LIBRARY "user32.dll"
复制代码
窗口 w_demo 的实例变量:- ulong iu_wins[] // 存放被禁用的父窗口句柄,Close 时逐个恢复
复制代码
w_demo 的 Open 事件(按传入参数决定禁用/保留父窗口):- // 示例输入:调用方经 OpenWithParm 传入的整型标记,1=模态,0=非模态
- integer li_modal
- li_modal = Message.DoubleParm
- ulong lp
- lp = GetParent(handle(this)) // 先取直接父窗口
- if lp = 0 then lp = GetWindow(handle(this), 4) // 4 = GW_OWNER,兜底取拥有者窗口
- if li_modal = 1 THEN
- iu_wins[upperbound(iu_wins) + 1] = lp
- EnableWindow(lp, 0) // 禁用父窗口:父窗口无法操作,即"模态"
- ELSE
- // 非模态:不禁用父窗口,保持 popup 行为
- END IF
- MessageBox("提示", "已按参数设置为:" + If(li_modal = 1, "模态", "非模态"))
复制代码
w_demo 的 Close 事件(恢复父窗口可用状态):- // 示例输入:无(恢复 Open 中禁用的父窗口)
- int i
- for i = 1 to upperbound(iu_wins)
- EnableWindow(iu_wins[i], 1) // 重新启用父窗口
- next
复制代码
调用方(按钮 clicked 事件)按参数打开即可:- // 示例输入:是否模态,1=模态,0=非模态
- integer li_modal
- li_modal = 1 // 按业务决定,示例取 1(模态)
- w_demo lw_d
- OpenWithParm(lw_d, li_modal) // 把标记传给子窗口 Open 事件
复制代码
两个要点
- WindowType 只在画板设、运行时改必报 C0143;想"按参数切模态",用 EnableWindow 控制父窗口可用状态即可,单窗口搞定,不必派生两个窗口。
- 禁用父窗口后务必在 Close 里 EnableWindow(父, 1) 恢复,否则父窗口会一直卡死。
pbai |