有个窗口,打开时给定一个参数modal,当糨为true时,显示为response模式,当它为false时,显示为popup模式。 如何实现?
有个窗口,打开时给定一个参数modal,当糨为true时,显示为response模式,当它为false时,显示为popup模式。如何实现?
本示例适用于 PB 全版本(6.5–2025 R2)。窗口的模态还是非模态由 WindowType 属性(response! / popup!)决定,可以在窗口 Open 事件中根据传入参数动态改写——但必须在窗口显示前设置才生效。
调用方(按钮或菜单中):
// 演示:用 OpenWithParm 把 modal 标记传入窗口
integer li_modal // 1=模态(response!),0=非模态(popup!)
li_modal = 1 // 按你的业务逻辑决定,示例设为 1(模态)
OpenWithParm(w_demo, li_modal) // 打开窗口并传参
目标窗口 w_demo 的 Open 事件:
// 在窗口显示前,根据传入参数改写 WindowType
integer li_modal // 存放调用方传来的 modal 标记
li_modal = Integer(Message.DoubleParm) // 取出 OpenWithParm 传入的整型参数
IF li_modal = 1 THEN
This.WindowType = response! // 模态:阻塞父窗口,常用于需返回值的场景
ELSE
This.WindowType = popup! // 非模态:可与父窗口并行操作
END IF
MessageBox("提示", "当前窗口类型:" + This.ClassName()) // 输出确认结果
注意:WindowType 只能在窗口打开前(Open 事件内或 Open 之前)设置,窗口已显示后再改无效。若想用布尔更直观,可把 1/0 换成字符串 "Y"/"N",改经 Message.StringParm 传入读取。pbai This.WindowType = response! // 模态:阻塞父窗口,常用于需返回值的场景
报错:
Error
C0143: A systemwrite property can be modified only in an event or function in its parent class
C0143: A systemwrite property can be modified only in an event or function in its parent class. 本示例适用于 PB 全版本(6.5–2025 R2)。
感谢反馈,这个 C0143 是个很典型的坑,正好把「WindowType 到底在哪改」讲清楚。
报错根因
WindowType 是窗口的 systemwrite(系统可写)属性。PB 规定:systemwrite 属性只能在「窗口自身类里的脚本」中赋值——也就是该窗口自己的 Open 事件、或定义在该窗口里的 function。一旦你在调用方(按钮 clicked、菜单、其它窗口)里写 w_demo.WindowType = response! 或 w.WindowType = ...,就是在窗口类之外改它的 systemwrite 属性,立刻报:
C0143: A systemwrite property can be modified only in an event or function in its parent class
所以不是 Open 事件里不能改,而是你大概率把赋值写到了调用方。正确的位置必须回到目标窗口 w_demo 的 Open 事件里,用 This.WindowType(或直接 WindowType)。
修正后的完整写法
调用方(按钮 clicked 事件)——只传参,绝不碰 WindowType:
// 示例输入:模态标记,1=模态(response!),0=非模态(popup!)
integer li_modal
li_modal = 1 // 按业务决定,示例取 1(模态)
// 打开窗口并把标记传入,由目标窗口自己改写 WindowType
OpenWithParm(w_demo, li_modal)
目标窗口 w_demo 的 Open 事件——在这里赋值才合法:
// 示例输入:调用方经 OpenWithParm 传入的模态标记
integer li_modal
li_modal = Integer(Message.DoubleParm) // 取出整型参数
// 必须在窗口显示前改写 WindowType,Open 事件正合适
IF li_modal = 1 THEN
This.WindowType = response! // 模态:阻塞其它窗口,常用于取返回值
ELSE
This.WindowType = popup! // 非模态:可与父窗口并行操作
END IF
MessageBox('当前窗口类型', This.ClassName()) // 输出确认结果
两个要点
[*]调用方只管 OpenWithParm 传参,任何 xxx.WindowType = 都不要写在调用方,否则必出 C0143。
[*]WindowType 要在窗口真正显示前设好;Open 事件在窗口绘制之前执行,所以放这里能生效,窗口已显示后再改则无效(但不报 C0143,只是不生效)。
少数老版本若 Open 事件设 WindowType 不生效,退路是在窗口画板里把 WindowType 设成 popup!,再用传入标记决定是否通过 CloseWithReturn 返回值来模拟「模态取结果」——但绝大多数情况按上面 Open 事件写法即可。
pbai 本帖最后由 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 = 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, 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 如果父窗口还有父窗口呢?是不是就控制不到了
页:
[1]