- 图形学
- 桌面应用
【免费下载链接】RGF_CJ
RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。
rgf.rgf_core是 RGF 仓颉版(RGF_CJ)的核心包,承载了绘制库全局初始化、Win32 主消息循环、窗口类体系、渲染事件模型以及一批面向 Win32 互操作的底层工具函数。本文以 doc/api/rgf.rgf_core/readme.md 为骨架,结合仓库源码,系统讲解该包的 API 全貌、调用约定与源码级实现原理,帮助读者掌握用仓颉语言构建 Windows 窗口应用与 2D 渲染程序的完整入口链路。
一、包定位与 API 全景
rgf.rgf_core是 RGF_CJ 项目中规模最大、职责最核心的包:它既是窗口框架(提供WinPure/WinCore窗口基类与全套窗口事件参数类),也是渲染框架(提供Surface、Bitmap、Brush、Path、TextLayout等绘制对象),同时还承载着全局生命周期(rsInitialize/rsDestroy/rsMain)和 Win32 互操作(ru*/rw*系列函数)。
从文档的 API 列表看,该包公开成员可归为八大类:
| 类别 | 数量 | 代表成员 |
|---|---|---|
| 函数 | 22 个(含重载) | rsMain、rsInitialize、rsCreateSysTimer、ruStrToWStr、rwBatchMove |
| 类 | 90+ | WinPure、WinCore、Surface、Color、Ev*事件参数类 |
| 接口 | 12 | IDraw、IEvent、IRenderEvent、IObjLink、IWinMethod等 |
| 结构体 | 2 | Context、ColorPct |
| 枚举 | 40+ | Substrate、RunMode、Antialias、WinStyle等 |
| 类型别名 | 3 | RgfHwnd、RgfHdc、RgfTimer |
| 变量与常量 | 9 | rgfErrorWinUncreated、rgfMessageNote等错误/告警文案 |
| 异常 | 1 | WinException |
从源码结构看(src/rgf_core),该包对应的实现文件按职责拆分得十分清晰:rgf_api.cj(C 侧函数声明与包装)、rgf_base.cj(窗口基类与主入口封装)、rgf_utils.cj(工具函数)、rgf_enum.cj(枚举)、rgf_struct.cj(结构体与几何类)、rgf_type.cj(类型别名)等,读者可据此按图索骥深入阅读。
二、全局生命周期:初始化、释放与主入口
RGF 绘制库的使用遵循“初始化 → 创建资源 → 消息循环 → 销毁”的生命周期,所有入口都集中在rgf.rgf_core。
2.1rsInitialize()与rsDestroy(token)
public func rsInitialize(): ContextPtr public func rsDestroy(token: ContextPtr): BoolrsInitialize()完成 RGF 绘制库的全局初始化,返回一个全局上下文(ContextPtr令牌,源码中为CPointer<Unit>类型别名,见 src/rgf_core/rgf_type.cj)。rsDestroy(token)执行全局释放,传入rsInitialize返回的令牌,返回是否成功。
源码中两者的实现是直接的 C 侧调用包装:rsInitialize调用rApiInitialize(),rsDestroy调用rApiDestroy(token)(见 src/rgf_core/rgf_api.cj)。需要特别注意的是,文档明确提示“本函数创建的上下文环境需要使用rsDestroy()方法释放”——即rsInitialize属于手动管理模式,开发者自己rsInitialize后必须自行rsDestroy,不能依赖 GC。
2.2rsMain:封装 Win32 主流程的入口函数
public func rsMain(create:()->Unit, destroy:()->Unit, mode!:RunMode = ...): Unit public func rsMain(create:()->Unit, mode!:RunMode): Unit public func rsMain(create:()->Unit): Unit public func rsMain(create:()->Unit, destroy:()->Unit): UnitrsMain是应用的主入口,内部封装了 Win32 的标准流程:获取模块句柄 → 初始化绘制库 → 创建Context→ 调用create创建窗口资源 → 进入GetMessageW/TranslateMessage/DispatchMessageW消息循环 → 主窗口关闭后调用destroy释放资源 → 释放上下文。
源码 src/rgf_core/rgf_base.cj 中rsMainInner的实现揭示了几个关键细节:
- 主窗口判定:消息循环以
while(haveMainWin.load())为条件,只要存在主窗口就持续分发消息;WM_QUIT(bRet == 0)或主窗口销毁后循环退出。 - 无效消息过滤:循环内对
hwnd == 0或!wIsWindow(hwnd)的消息直接continue,避免分发到已销毁窗口。 - 中文说明:文档注明“本函数内部封装了 Win 的主要流程,若需要更高的自由度可参考此代码结构自行实现”,即开发者完全可以参照
rsMainInner的代码自行编写更精细的消息循环。
2.3RunMode与调试/发布差异
RunMode枚举定义了主函数执行模式(源码 src/rgf_core/rgf_base.cj):
| 枚举值 | 含义 |
|---|---|
SysThreadAndAsyn | 新建系统线程,异步不阻塞当前线程 |
SysThreadAndWait | 新建系统线程,并等待执行结束(默认) |
CJMainThread | 直接基于仓颉主线程运行 |
rsMain有多个重载,且带@When[debug]/@When[!debug]编译期条件注解,调试与发布构建下的默认行为不同:
- 发布构建(
@When[!debug]):rsMain(create)/rsMain(create, destroy)默认走RunMode.SysThreadAndWait,即新建 UI 线程并阻塞主线程等待结束。 - 调试构建(
@When[debug]):同一签名的重载默认走RunMode.CJMainThread,直接在仓颉主线程上执行窗口逻辑,便于调试。
显式传入mode的重载(rsMain(create, destroy, mode)与rsMain(create, mode))则无编译期差异,完全由开发者指定运行模式。若使用SysThreadAndAsyn,配合ruFinished()判断 RGF 是否执行完成(返回false表示正在执行,true表示完成),用于在其他线程阻塞等待。
三、窗口类体系与窗口事件模型
3.1 窗口类注册:rwRegister/rwUnregister
public func rwRegister(ctxt: WinContext, className: String, style: UInt32, hbrBackground!: Int32 = 5): Bool public func rwUnregister(ctxt: WinContext): BoolrwRegister是 RGF 封装的窗口类注册方法,hbrBackground默认值为5(即NULL_BRUSH,背景画刷为空)。源码 src/rgf_core/rgf_api.cj 中,注册成功后会将className记录进静态映射staticWinClassMap,并回填ctxt.winClassCTxtPtr与ctxt._className;rwUnregister注销成功后同步从映射移除。
文档特别强调一个关键注意事项:非本类注册的窗口类需要手动注入窗口过程函数,否则 RGF 窗口类无法捕获系统事件。也就是说,若开发者自行用原生 API 注册窗口类,必须自行把消息路由到 RGF 的窗口过程,事件系统才能工作。此外“凡注册的窗口类都应该由本方法注销”,源码中还提供了rwClearAllWinClass()在rsMain销毁阶段统一清理所有记录在案、未被释放的窗口类。
3.2 窗口句柄与类型别名
public type RgfHwnd = UIntNative // 窗口句柄 public type RgfHdc = UIntNative // 设备上下文 public type RgfTimer = HANDLE // Timer 句柄三个公开类型别名中,RgfHwnd/RgfHdc是数值句柄,RgfTimer直接映射到 Win32 的HANDLE(见 src/rgf_core/rgf_type.cj)。配套函数ruToHwnd(rgfHwnd)与ruToHdc(rgfHdc)负责把 RGF 句柄还原为 Win32 的HWND/HDC。
3.3 窗口基类与渲染事件接口
类体系的核心是WinPure(RGF 窗口核心,纯窗口,见 doc/api/rgf.rgf_core/类/WinPure.md)与WinCore(继承WinPure,具备渲染能力,见 doc/api/rgf.rgf_core/类/WinCore.md)。二者都实现渲染事件接口IRenderEvent/IRenderEventCore与绑定式事件接口IBindRenderEvent/IBindRenderEventCore。
从源码 src/rgf_core/rgf_base.cj 可以看出窗口生命周期的完整顺序:
beforeCreate():调用createWin后最先触发,此时渲染表面尚未创建;created():窗口创建完成,携带hwnd, x, y, nWidth, nHeight;rendererCreated(surface):渲染表面就绪(WinCore在此默认设置Antialias.HighQuality抗锯齿);createDeviceResources():创建设备相关/渲染资源,此事件可能在窗口周期内被多次调用;onPaint(wRect):窗口需要重绘时触发,参数为需要重绘的矩形;destroyDeviceResources():销毁设备资源;rendererDestroy():渲染表面释放前触发;beforeDestroy():窗口销毁前;destroyed():窗口生命周期终结。
除了覆写式事件方法,窗口类还提供一套绑定式(lambda)事件:bindBeforeCreate、bindCreated、bindRendererCreated、bindCreateDeviceResources、bindOnPaint、bindDestroyDeviceResources、bindRendererDestroy、bindBeforeDestroy、bindDestroyed、bindWndProc。从GFBase.callWndProc的实现看,绑定式事件优先于类自身方法,满足“扩展修订类”的需求——即开发者不必继承窗口类,直接给实例挂 lambda 即可自定义行为。
此外,rgf.rgf_core下还有 90+ 个Ev*事件参数类(如EvMouse、EvKey、EvSize、EvTimer、EvDPIChanged等,见 doc/api/rgf.rgf_core/类 目录),它们把 Win32 消息转换为类型安全的仓颉对象,是绑定式事件与wndProc处理时的参数载体。
3.4 渲染相关辅助函数
rwBatchMove(batch):批量移动窗口,有三种重载,分别接收(RgfHwnd,...)、(WinPure,...)、(IWinMethod,...)元组数组,元组格式为[句柄/窗口, X, Y, 宽, 高]。源码实现使用BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos三件套,保证一批窗口位置更新期间的重绘同步与性能。rwIsMainWin(rw/hWnd/IWinMethod):判断窗口是否为主窗口(haveMainWin原子标志与mainWinHwnd全局句柄配合实现)。rwGetRgfClass(rgfHwnd):通过句柄反向获取窗口类实例(从staticMap永久映射中查找)。rwDefWindowProc(hWnd, uMsg, wParam, lParam):DefWindowProc的包装,用于未处理消息的默认处理。
四、绘制对象与资源管理
rgf.rgf_core同时暴露了完整的 2D 渲染对象体系,按“设备相关/设备无关”和“手动释放/自释放”两个维度组织:
几何与颜色值类型:Point/FPoint(位置)、Size/FSize(尺寸)、Rect/FRect(矩形,实现IRect<T>接口,见 doc/api/rgf.rgf_core/类/Rect.md)、Color(色彩)、Matrix/Matrix3X3。
绘制对象:Surface(窗口渲染表面)、BindSurface(绑定式渲染表面)、Bitmap/MemBitmap(位图/内存位图)、Brush及其子类SolidColorBrush、LinearGradientBrush、BitmapBrush、Path(路径)、StrokeStyle(笔划风格)、Layer(图层)、Image(图像父类)。
文本体系:TextCore、TextFormat、TextLayout、TextInlineObj、TextMetrics、LineMetrics、ClusterMetrics、OverhangMetrics、HitTestMetrics及Range*局部格式类。
资源生命周期:所有资源类都实现IObjLink接口(isValid()有效性验证、release()释放、get/set底层对象访问),基类SfcSubObjBase通过SfcSubObjType枚举区分对象类型并统一走rApiSfcSubObjRelease释放(见 src/rgf_core/rgf_base.cj)。带S前缀的类(SBitmap、SPath、STextLayout等)为自释放版本——它们被渲染表面接管,释放表面时自动释放,无需手动release()。
五、系统工具函数:定时器、字符串与内存互操作
5.1 系统定时器
public func rsCreateSysTimer(callback: CFunc<(CPointer<Unit>, UInt8) -> Unit>, parameter: CPointer<Unit>, dueTime: UInt32, period: UInt32): RgfTimer public func rsDestroySysTimer(timer: RgfTimer): UnitrsCreateSysTimer基于 Win32 定时器队列创建定时器:callback为@C风格回调(可传入@CLambda),parameter为回调参数指针,dueTime为首次执行等待时间(毫秒),period为每次间隔时间(毫秒),成功返回RgfTimer句柄。源码 src/rgf_core/rgf_utils.cj 中,其底层调用wCreateTimerQueueTimer,并附加WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION标志以支持长任务执行;创建失败抛WinException。
务必注意文档提示:“凡是本函数创建的定时器,都需要销毁”——用完调用rsDestroySysTimer(timer)注销(底层wDeleteTimerQueueTimer,失败抛WinException),否则会造成句柄与回调资源泄漏。
5.2 字符串与宽字符互操作
RGF 在仓颉String与 Win32LPWSTR(C 宽字符串)之间提供了一组对称转换工具:
| 函数 | 作用 |
|---|---|
ruStrToWStr(str: String): LPWSTR | 仓颉字符串 → C 宽字符串(含编码转换);创建的字符串需用ruFree释放 |
ruWStrToStr(str: LPWSTR): String | C 宽字符串 → 仓颉字符串(含编码转换,内部自动释放中间结果) |
ruWStrlen(wcharPtr: LPWSTR): UInt32 | 获取 C 宽字符串长度(宽字符数) |
ruFree(cPtr: CPointer<Unit>): Unit | 释放ruStrToWStr申请的宽字符串内存 |
ruStrToCStr<T>(str, callback) | 字符串转换 + 回调内使用 +自动释放,一种更安全的便捷封装 |
ruStrToCStr的实现(源码 src/rgf_core/rgf_utils.cj)为:先ruStrToWStr转换,执行用户回调,最后rApiReleaseWcharStr释放——使用者在回调内使用cStr即可,无需关心释放。推荐优先使用ruStrToCStr而非裸用ruStrToWStr+ruFree,以规避忘记释放的风险。
5.3 指针与内存工具
ruUllToPtr(ptrVal: UIntNative): CPointer<Unit>:将无符号数值(如句柄地址值)恢复为指针。ruLlToPtr(ptrVal: IntNative): CPointer<Unit>:将有符号数值恢复为指针(文档标注“极少数情况下使用”)。ruRedefBit<T1,T2>(v): T2:从内存比特层面重解释数据值,类似 C++ 的联合体(union)。实现上取两个类型大小的最大值开临时缓冲区,writeLittleEndian写入后readLittleEndian读回(源码 src/rgf_core/rgf_utils.cj),约束为T1/T2 <: LittleEndianOrder<T> & CType。ruSafeCStruct<T,RT>(count, callback):自动创建count个T的 CType 内存、执行回调、自动释放,回调收到CPointer<T>,适合向 C 侧传入临时结构体数组。rsModRefToCurrDir():将当前程序的存储路径设为相对路径起点(底层SetCurrentDirectoryToExe),解决资源文件相对路径定位问题。rsGetMonitorFromPoint(x, y / Point / FPoint): Rect:获取桌面坐标系下某点所在显示器的工作区矩形(rcWork)。源码通过EnumDisplayMonitors回调 +PtInRect命中测试 +GetMonitorInfoW获取工作区,未命中时抛WinException。三个重载分别接受(Int32, Int32)、Point、FPoint。rsGetContext(): Option<Context>:获取全局上下文,未初始化时返回None。rsEnd(exitCode: UInt32):结束进程(底层ExitProcess),用于主动终止应用。ruFinished(): Bool:判断 RGF 是否执行完成,配合SysThreadAndAsyn模式下的跨线程等待。
六、结构体、常量与异常约定
6.1 结构体
Context(技术上下文):封装了ctxtPtr(ContextPtr,RGF 全局上下文指针)与hInst(HINSTANCE,程序模块实例句柄),由rsMain内部创建并通过rsGetContext()获取。hInst在rwRegister注册窗口类时作为参数传给 C 侧rApiRegisterWinClass(见 src/rgf_core/rgf_struct.cj 与 src/rgf_core/rgf_api.cj)。ColorPct(颜色及百分比值):用于渐变色标/百分比配对等场景,配合LinearGradientBrush使用。
6.2 错误与告警常量
包内定义了一组rgf*常量(见 doc/api/rgf.rgf_core/变量与常量.md),用于错误抛出与调试提示,例如:
| 常量 | 含义 |
|---|---|
rgfErrorWinUncreated | “访问未创建的窗口类!” |
rgfErrorMainUiThreadinited | “RGF 的主 UI 线程已被初始化!”(重复调用rsMain会抛出) |
rgfErrorCpluapluaObjNotExist | “底层对象未初始化或已经释放!” |
rgfErrorWindowsApi | “Windows Api 出现错误!错误码:” |
rgfErrorArrLenOverflow | “数组长度超出最大限额!” |
rgfWarnValidRdObj | “异步调用渲染时,请对类实例进行有效性验证!” |
rgfMessageNote/rgfWarningNote | 调试消息/告警消息提示(不影响正式程序执行) |
rgfFunctionWillIgnored/rgfWrongAttribution | “当前控件并未实现此绑定式事件!传入的事件函数将被忽略!” |
rgfNegativeReinter | “当前正在进行负值相关的数值重解释!” |
6.3 异常类
WinException(见 doc/api/rgf.rgf_core/异常/WinException.md)是系统相关异常,携带 Win32GetLastError错误码,所有涉及 Windows API 调用的失败路径(定时器创建失败、监视器查询失败、线程创建失败、消息循环错误等)均抛出该异常。
七、典型用法:一个完整的 RGF 窗口应用骨架
综合以上 API,一个典型 RGF 窗口应用的最小骨架如下(结构参考 test/CT/base/src/main.cj 等仓库内测试工程):
package main import rgf.rgf_core.* // 自定义渲染窗口(继承 WinCore 获得渲染能力) class MyWin <: WinCore { public override func createDeviceResources(): Bool { // 创建设备相关资源(画刷、位图等) return true } public override func onPaint(wRect: Rect): Unit { // 在此执行绘制,例如: // surface.clear(1.0, 1.0, 1.0, 1.0) } public override func destroyDeviceResources(): Bool { // 销毁设备相关资源 return true } } // 窗口类上下文(全局) var winCtxt: WinContext = WinContext() main() { // 注册窗口类(hbrBackground 默认 NULL_BRUSH) rwRegister(winCtxt, "MyWindowClass", WinStyle.e2n(WinStyle.Default)) // RGF 主入口:create 中创建窗口资源,destroy 中释放 rsMain({ let win = MyWin() win.createWin( winCtxt, "RGF 示例窗口", 100, 100, 800, 600, // 位置与尺寸 0, // 父窗口句柄(0 为桌面) WinStyle.e2n(WinStyle.Default), substrate: Substrate.Direct2D, // 推荐 Direct2D 渲染后端 bgMod: BackGroundMod.CoverNotDraw, ) win.show(true) }, { // destroy:释放窗口资源 rwUnregister(winCtxt) }) }关键点回顾:
- 渲染后端通过
Substrate枚举选择:Direct2D(推荐)、GdiPlus、Pure(纯窗口无渲染能力)。 rsMain在发布构建默认SysThreadAndWait、调试构建默认CJMainThread,两种模式都能直接运行上述代码。- 如需更高自由度(如自定义消息循环、消息过滤、加速键翻译),文档建议参考
rsMainInner的源码结构自行实现。
八、深入阅读指引
- 包 API 全表:doc/api/rgf.rgf_core/readme.md;函数细节:doc/api/rgf.rgf_core/函数.md
- 窗口基类与事件:
WinPure/WinCore文档见 doc/api/rgf.rgf_core/类,实现见 src/rgf_core/rgf_base.cj - 主入口与消息循环实现:src/rgf_core/rgf_base.cj(
rsMainInner、RunMode) - 工具函数(定时器/字符串/指针/监视器):src/rgf_core/rgf_utils.cj
- C 侧函数声明与窗口类注册:src/rgf_core/rgf_api.cj
- 类型别名定义:src/rgf_core/rgf_type.cj
- 可运行的测试工程:test/CT/base/src/main.cj、test/HLT/base/src/main.cj、test/HLT/pure/src/main.cj
- 图形学
- 桌面应用
【免费下载链接】RGF_CJ
RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。
相关推荐
SFML窗口与事件循环全解:从创建窗口到事件驱动主循环的最实用指南
SFML窗口与事件循环全解:从创建窗口到事件驱动主循环的最实用指南 SFML 是一款轻量高效的 C++ 跨平台多媒体库,其中最核心的入门内容就是 窗口创建 与
图形学音视频游戏开发Piston游戏引擎核心组件解析:输入、窗口与事件循环
Piston游戏引擎核心组件解析:输入、窗口与事件循环 Piston是一个用Rust编写的模块化游戏引擎,以其精简的核心设计和出色的灵活性而闻名。该引擎采用最小
游戏开发Extrapolate未来路线图:即将推出的AI增强功能与平台扩展计划
Extrapolate未来路线图:即将推出的AI增强功能与平台扩展计划 Extrapolate作为一款基于Next.js、Vercel、Replicate等技术
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考