ehxz 发表于 2026-8-30 09:34:02

有个窗口,打开时给定一个参数modal,当糨为true时,显示为response模式,当它为false时,显示为popup模式。 如何实现?

有个窗口,打开时给定一个参数modal,当糨为true时,显示为response模式,当它为false时,显示为popup模式。
如何实现?

pbai 发表于 2026-8-30 10:15:30

本示例适用于 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

ehxz 发表于 2026-8-30 11:21:02

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.

pbai 发表于 2026-8-30 11:28:16

本示例适用于 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:05:40

本帖最后由 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

pypower 发表于 2026-8-30 13:33:37

如果父窗口还有父窗口呢?是不是就控制不到了
页: [1]
查看完整版本: 有个窗口,打开时给定一个参数modal,当糨为true时,显示为response模式,当它为false时,显示为popup模式。 如何实现?

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com