- 图形学
- 桌面应用
【免费下载链接】RGF_CJ
RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。
导读
EvEnterIdle是 RGF_CJ(仓颉版通用渲染框架)在 Windows 平台上为WM_ENTERIDLE(进入空闲状态)消息设计的专用事件参数类。当对话框(DialogBox)或消息框(MessageBox)的消息循环进入空闲状态时,系统会向宿主窗口发送该消息,RGF 将其封装为EvEnterIdle事件对象并派发给应用层。本文以 RGF_CJ 官方 API 文档为基础,结合仓库源码,系统讲解该事件参数类的完整定义、底层消息分发链路、两种使用方式(重写事件方法与绑定事件回调)及典型应用场景,帮助开发者掌握在 RGF 窗口应用中捕获空闲时机、执行后台任务或界面刷新的能力。
一、类定义与文档定位
在 RGF_CJ 中,所有窗口消息事件参数类均位于rgf.rgf_core包,EvEnterIdle的 API 文档位于 doc/api/rgf.rgf_core/类/EvEnterIdle.md,官方类名索引记录于 doc/api/rgf.rgf_core/readme.md(描述为"进入空闲状态 - 事件参数")。
类声明如下:
public open class EvEnterIdle <: EvCoreEvEnterIdle直接继承自事件参数基类EvCore(定义见 src/rgf_core/rgf_proc.cj#L37-L48),因此自动拥有基类提供的message(消息 ID)、wParam、lParam三个原始字段,以及内部标记isOverride(用于标识事件方法是否被应用覆盖)。open关键字表明该类允许被进一步继承或覆写,遵循 RGF 事件参数类的一贯设计风格。- 该类用于承载"对话框或消息框进入空闲状态"这一系统通知的全部上下文信息。
从 src/rgf_core/rgf_proc.cj#L3373-L3384 可以看到该类的完整源码实现:
/** @brief 进入空闲状态 - 事件参数 */ public open class EvEnterIdle <: EvCore{ // DialogBox 或 MessageBox public let fType:EmMsgFilter // 进入空闲态的句柄 public let hwnd:RgfHwnd @OverflowWrapping public init(wParam:UInt64, lParam:Int64) { super(0x0121 /*WM_ENTERIDLE*/, wParam,lParam) fType = EmMsgFilter.num2e(UInt8(wParam)) hwnd = ruInt64SafeToUIntNative(lParam) } }可见构造函数内部硬编码了消息 ID0x0121(即WM_ENTERIDLE),并将原始参数自动解析为两个语义化字段,这正是 RGF 将"裸 Win32 消息"转化为"强类型事件对象"的典型模式。
二、构造函数与原始参数解析
函数签名
@OverflowWrapping public init(wParam: UInt64, lParam: Int64)参数说明
| 名称 | 类型 | 描述 |
|---|---|---|
| wParam | UInt64 | Win32 消息的 wParam,低字节为消息过滤类型(fType 数据来源) |
| lParam | Int64 | Win32 消息的 lParam,为进入空闲状态的窗口句柄(hwnd 数据来源) |
解析逻辑(源码级)
参照 src/rgf_core/rgf_proc.cj#L3378-L3383:
- fType 解析:
fType = EmMsgFilter.num2e(UInt8(wParam)),即取wParam的低 8 位(UInt8截断),再经枚举反向转换函数EmMsgFilter.num2e映射为语义化枚举。 - hwnd 解析:
hwnd = ruInt64SafeToUIntNative(lParam),将有符号Int64安全转换为UIntNative类型的窗口句柄。RgfHwnd是UIntNative的类型别名,定义见 src/rgf_core/rgf_type.cj#L27。 - 基类初始化:
super(0x0121 /*WM_ENTERIDLE*/, wParam, lParam),基类EvCore保存原始消息三要素,供需要底层数据的场景回溯。
@OverflowWrapping注解表明在该构造函数内发生的数值截断/转换运算采用回绕语义(wrap-around),避免仓颉默认的溢出检查在类型转换时抛出异常,保证 Win32 原始参数能够被安全接收。
三、核心字段:fType 与 hwnd
let fType: EmMsgFilter —— 消息过滤类型
public let fType: EmMsgFilter官方文档标注其含义为"DialogBox 或 MessageBox"。该字段的类型EmMsgFilter(消息过滤类型枚举)定义于 src/rgf_core/rgf_proc.cj#L3341-L3371:
public enum EmMsgFilter{ | DialogBox | MessageBox | Menu | ScrollBar | NextWindow public const static func e2Num(tk:EmMsgFilter):UInt8{ return match (tk) { case DialogBox => 0 case MessageBox => 1 case Menu => 2 case ScrollBar => 5 case NextWindow => 6 } } public const static func num2e(num:UInt8):EmMsgFilter{ return match (num) { case 1 => MessageBox case 2 => Menu case 5 => ScrollBar case 6 => NextWindow case _ => DialogBox } } ... }各取值与 Win32 规范一致:
| 枚举值 | 数值 | 含义 |
|---|---|---|
| DialogBox | 0 | 对话框消息循环进入空闲(也是 num2e 的默认兜底值) |
| MessageBox | 1 | 消息框消息循环进入空闲 |
| Menu | 2 | 菜单消息循环进入空闲 |
| ScrollBar | 5 | 滚动条消息循环进入空闲 |
| NextWindow | 6 | 切换窗口消息循环进入空闲 |
需要说明的是,Win32 文档中WM_ENTERIDLE的 wParam 低字正是MSGF_DIALOGBOX(0)、MSGF_MESSAGEBOX(1)、MSGF_MENU(2)等消息过滤类型常量,RGF 通过EmMsgFilter枚举 +num2e将其完整还原。虽然WM_ENTERIDLE最常见于对话框与消息框场景,但枚举中同时覆盖了菜单、滚动条与窗口切换三种过滤器类型,这与 src/rgf_core/rgf_proc.cj#L3362 中case _ => DialogBox的兜底设计共同保证了未知数值也能安全映射。
此外,该枚举还提供了e2Num(枚举→数值)以及==/!=运算符重载(基于e2Num比较),便于在事件处理中直接进行if (e.fType == EmMsgFilter.MessageBox)这类语义化判断。
let hwnd: RgfHwnd —— 进入空闲态的窗口句柄
public let hwnd: RgfHwnd官方文档标注为"进入空闲态的句柄"。它取自lParam,指向触发空闲状态的窗口。注意该窗口是"对话框/消息框所属的宿主窗口",而非对话框自身,这与 Win32 规范一致:WM_ENTERIDLE被发送给创建对话框/消息框的宿主窗口过程,lParam为该宿主窗口句柄。RgfHwnd即UIntNative类型别名(src/rgf_core/rgf_type.cj#L27),可直接用于 RGF 提供的窗口相关 API(如rwGetRgfClass(hwnd)、rwIsMainWin(hwnd)等,参见 doc/api/rgf.rgf_core/readme.md)。
四、底层消息分发链路
EvEnterIdle的触发根源于 Win32 的WM_ENTERIDLE消息。RGF 在 src/win_def/hwinuser.cj#L184 中定义了该消息常量:
public const WM_ENTERIDLE:UInt32 = 0x0121当消息到达窗口过程后,RGF 通过两条链路将其转换为EvEnterIdle事件对象。
链路一:事件方法分发(IEvent / callEvent)
在 src/rgf_core/rgf_proc.cj#L5310-L5314 的callEvent消息分派表中:
case 0x0121 /*WM_ENTERIDLE*/ =>{=> let eObj:EvEnterIdle = EvEnterIdle(wParam,lParam) onEnterIdle(eObj) return (0,eObj.isOverride) }系统先构造EvEnterIdle对象,再调用onEnterIdle(eObj)事件方法;返回元组中isOverride标记了该方法是否被应用覆盖,用于决定是否继续交由DefWindowProc处理。
链路二:绑定回调分发(IBindEvent / callBind)
在 src/rgf_core/rgf_proc.cj#L7470-L7473 的callBind分派表中:
case 0x0121 /*WM_ENTERIDLE*/ =>{=> let eObj:EvEnterIdle = EvEnterIdle(wParam,lParam) return if(let Some(v) <- bindEnterIdle?(eObj)){ 0 }else{ Option<Int64>.None } }这里通过可空回调bindEnterIdle?(eObj)调用绑定的事件处理函数,若已绑定则返回 0,否则返回None交由默认窗口过程处理。
宏生成机制
值得注意的是一致性问题:rgf_proc.cj中的两段分派代码并非手写维护,而是由宏生成。在 src/rgf_core/macros/rgf_proc_utils.cj#L564-L568 和 src/rgf_core/macros/rgf_proc_utils.cj#L1685-L1689 中分别定义了onEnterIdle与bindEnterIdle两种模式对应的代码片段生成规则,宏展开后即产生上述case 0x0121分支。这意味着:只要在窗口类中声明override func onEnterIdle(e: EvEnterIdle): Unit(事件方法模式)或设置bindEnterIdle属性(回调模式),RGF 编译期宏就会自动把该事件接入消息循环,开发者无需手动注册。
五、在窗口应用中监听空闲事件
方式一:重写事件方法(IEvent 接口模式)
IEvent接口声明了func onEnterIdle(e: EvEnterIdle): Unit(见 doc/api/rgf.rgf_core/接口/IEvent.md#L642-L652),默认空实现位于 src/rgf_core/rgf_proc.cj#L6487-L6489:
// @brief 对话框或消息框进入空闲状态 func onEnterIdle(e:EvEnterIdle):Unit{ e.isOverride = false }应用侧可继承窗口类并重写该方法:
public override open func onEnterIdle(e: EvEnterIdle): Unit { // 此时宿主窗口的消息队列已空闲,可执行轻量后台任务 if (e.fType == EmMsgFilter.MessageBox) { println("消息框进入空闲状态,宿主窗口句柄:${e.hwnd}") } // 默认不覆写系统默认处理,保持 e.isOverride 为 false }方式二:绑定回调属性(IBindEvent 接口模式)
IBindEvent接口提供了回调属性bindEnterIdle(见 doc/api/rgf.rgf_core/接口/IBindEvent.md#L342-L346),其默认实现会直接抛出NoneValueException(见 src/rgf_core/rgf_proc.cj#L8259),提示开发者必须显式覆写该属性后才能生效:
public override open mut prop bindEnterIdle: Option<(EvEnterIdle) -> Unit> { get() { None } set(v) { bindEnterIdle = v } }使用时只需给属性赋值:
bindEnterIdle = { e: EvEnterIdle => println("空闲事件触发,消息过滤类型:${e.fType},句柄:${e.hwnd}") }原始消息兜底处理
若两种模式都未启用,wndProc会把该消息交回super.wndProc走DefWindowProc默认流程(参见 src/rgf_core/rgf_proc.cj#L4735-L4741 的wndProc结构)。这与测试工程中的用法一致:在 test/HLT/base/src/test_win.cj#L59-L73 中,测试窗口类同样采用"先按消息值自行判断、未处理则return super.wndProc(...)"的模式,体现了 RGF 事件系统"自定义优先、默认兜底"的分层设计。
六、典型应用场景
结合fType与hwnd两个字段,EvEnterIdle的典型用途包括:
- 空闲期后台处理:在模态对话框/消息框等待用户操作的空闲间隙执行不阻塞 UI 的轻量任务(如预加载资源、刷新状态栏)。
- 宿主窗口联动:通过
hwnd定位创建对话框的宿主窗口,对宿主窗口执行刷新(如调用surface重绘)或状态同步。 - 按过滤器类型分流:利用
fType区分消息来源——例如对EmMsgFilter.MessageBox与EmMsgFilter.Menu分别采取不同的空闲处理策略,避免在菜单弹出期间做不必要的重活。 - 诊断与日志:在调试期记录"何时、哪个窗口、以何种模式进入空闲",辅助分析模态循环中的时序问题。
需要提醒的是,WM_ENTERIDLE本身是一个低优先级通知,触发频率取决于模态循环的空闲时长,因此不建议在该回调中执行耗时操作(会直接拖慢模态循环响应),更适合安排可快速完成或可延后的工作。
七、使用小结
| 要点 | 说明 |
|---|---|
| 消息来源 | Win32WM_ENTERIDLE(0x0121),常量见 src/win_def/hwinuser.cj#L184 |
| 事件对象 | EvEnterIdle <: EvCore,源码见 src/rgf_core/rgf_proc.cj#L3373-L3384 |
| fType | EmMsgFilter枚举,取wParam低字节映射,覆盖 DialogBox/MessageBox/Menu/ScrollBar/NextWindow |
| hwnd | RgfHwnd(UIntNative),来自lParam,指向进入空闲态的宿主窗口 |
| 事件方法 | onEnterIdle(e: EvEnterIdle),见 IEvent 接口 |
| 绑定回调 | bindEnterIdle: Option<(EvEnterIdle) -> Unit>,见 IBindEvent 接口 |
| 宏接入 | 编译期自动生成case 0x0121分派分支,见 rgf_proc_utils.cj |
掌握EvEnterIdle之后,开发者可以在 RGF_CJ 窗口应用中精确感知模态循环的空闲窗口,为对话框、消息框场景下的后台任务调度与界面联动提供可靠的事件入口。如需进一步了解事件参数基类字段,可参考 EvCore 文档;完整的消息过滤类型枚举定义可在 rgf_proc.cj 中查阅。
- 图形学
- 桌面应用
【免费下载链接】RGF_CJ
RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。
相关推荐
RGF_CJ 窗口可视状态变更事件:EvShow 事件参数类深度解析
RGF_CJ 窗口可视状态变更事件:EvShow 事件参数类深度解析 RGF_CJ(仓颉版通用渲染框架)在 rgf.rgf_core 子包中完整封装了 Win3
图形学桌面应用RGF_CJ 中 EvAppCommand 事件参数类与 Windows 应用程序命令(WM_APPCOMMAND)事件处理
RGF_CJ 中 EvAppCommand 事件参数类与 Windows 应用程序命令(WM_APPCOMMAND)事件处理 EvAppCommand 是 RG
图形学桌面应用RGF_CJ 窗口事件指南:EvMouseActivate 鼠标激活事件参数详解
RGF_CJ 窗口事件指南:EvMouseActivate 鼠标激活事件参数详解 本文面向使用 RGF_CJ(仓颉 Windows 通用渲染框架)开发桌面应用的
图形学桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考