简介:本资源是面向Delphi与C++Builder开发者的专业富文本处理组件套件,涵盖TRichView 21.6、ScaleRichView 8.0等7个核心模块的已注册正式版,含全部源代码,适用于开发高定制化文档编辑器、报表系统、HTML导入导出工具及跨分辨率自适应富文本界面。资源包共2000个文件,以1095个cpp/hpp/h头文件与源码为主(支撑VCL/FMX跨平台编译),辅以70个说明文本、46个XML配置与结构定义文件、4个PDF技术文档及1个HTML示例页,完整呈现组件集成路径、事件钩子设计与插件扩展机制;压缩包体积为110.37MB,结构层次分明,便于源码级调试与二次开发。目前已有274人学习下载,开发者可直接复用注册版授权、参考RichViewActions的命令体系实现菜单/工具栏联动,结合RvHtmlImport与RichViewXML快速构建文档双向转换流程,并基于SRVControls与Report Workshop搭建轻量级所见即所得报表引擎。
1. TRichView 21.6 + ScaleRichView 8:Delphi/C++Builder 下富文本渲染与缩放的「稳态组合」,不是插件堆砌,而是生产级排版闭环
你有没有遇到过这种场景:用 Delphi 做一个电子病历编辑器,要求支持图文混排、表格嵌套、打印预览时字体不糊、导出 PDF 保持样式、还要在 4K 屏上拖拽缩放不卡顿?试过原生 TRichEdit?它连行内图片都得自己画;换过 SynEdit?语法高亮强,但表格和分页就是黑匣子;甚至有人硬啃 VCL 的 Canvas 去重绘——结果是改一个边框线,三台测试机表现不一致。TRichView 21.6 + ScaleRichView 8 这个组合,不是又一个“能跑 demo”的控件包,而是某医疗软件公司连续五年迭代的排版底座:它把富文本结构化(RVF 格式)、样式引擎(CSS-like 属性树)、设备无关渲染(DPI-aware canvas pipeline)、以及无损缩放(非 bitmap 拉伸,而是 layout 重计算)全链路串通了。它适合谁?不是写 HelloWorld 的新手,而是正在交付带审批流、多级标题、交叉引用、页眉页脚自动编号的工业级文档系统的 Delphi/C++Builder 开发者。它解决的不是“能不能显示”,而是“在客户现场 Windows Server 2019 + 32GB 内存 + 4K 触控屏上,打开 200 页含 57 张矢量图的检测报告,缩放到 150% 后仍能实时滚动且 CPU 占用 <12%”这个具体问题。
2. 为什么是 TRichView 21.6 + ScaleRichView 8 而非其他组合:从渲染管线看选型硬逻辑
2.1 TRichView 的核心价值不在“富文本”,而在“可编程文档模型”
很多开发者第一眼只看到 TRichView 支持 RTF、HTML 导入、所见即所得编辑——这其实是表象。它的真正骨架是TCustomRichView抽象类定义的Item-Based Document Model:每个段落、图片、表格、超链接、甚至空白行,都是一个独立TRVItemInfo对象,挂载在TRVData的线性列表中。这意味着你可以:
- 在
OnItemDraw中拦截任意 item 的绘制,注入自定义图形(比如用 GDI+ 绘制带阴影的流程图节点); - 通过
GetItemRect()精确获取任意 item 在当前缩放/滚动状态下的屏幕坐标,为右键菜单、拖拽定位、PDF 锚点生成提供像素级依据; - 利用
TRVTableItemInfo的Cells[]数组直接操作单元格内容,无需解析 HTML 表格字符串。
提示:TRichView 21.6 的关键升级是
TRVStyle的样式继承机制重构。旧版(<21.0)中,表格内文字样式会错误继承父段落的字体大小;21.6 引入StyleInheritanceLevel枚举,明确控制rvsilNone/rvsilParent/rvsilDocument三级继承策略,这是处理复杂嵌套文档(如法规文档中“条款 > 子条款 > 示例代码块”)不崩样式的底层保障。
2.2 ScaleRichView 8 不是“加个缩放滑块”,而是重写了 Layout Engine
ScaleRichView 8 的本质,是给 TRichView 的TScrollingWinControl基类注入了一个Scale-Aware Layout Pipeline。它不依赖 Windows 的SetThreadDpiAwarenessContext,而是:
- 在
DoScaleChange()中,将缩放因子(如 1.5)直接作用于TRVData的ScaleX/ScaleY属性; - 触发
RebuildLayout(),强制所有TRVItemInfo重新调用GetMinWidth()/GetHeight(),并基于新缩放值重算BoundsRect; - 最终在
Paint()阶段,用Canvas.ScaleTransform(ScaleX, ScaleY)统一缩放整个视图,而非对位图做StretchDraw。
这就解释了为什么 ScaleRichView 8 缩放时文字边缘锐利、表格线条不断、而某些第三方“缩放组件”放大后全是马赛克——后者只是把最终位图拉伸了,前者是让整个文档模型按比例再生。
2.3 二者协同的不可替代性:一个负责“结构”,一个负责“形变”
| 维度 | TRichView 21.6 | ScaleRichView 8 | 协同效果 |
|---|---|---|---|
| 文档结构 | 提供TRVData、TRVItemInfo、TRVTableItemInfo等完整对象模型 | 无结构能力,仅作用于已存在的TRichView实例 | ScaleRichView 无法脱离 TRichView 独立存在,它必须操作 TRichView 的 Item 链表 |
| 缩放实现 | 自带基础缩放(Scale属性),但仅影响绘制,不重算布局,导致表格错位、换行异常 | 重写RebuildLayout(),确保缩放后所有 item 的BoundsRect准确反映新尺寸 | TRichView 提供结构,ScaleRichView 提供形变,缺一不可 |
| DPI 适配 | 依赖系统 DPI 设置,高 DPI 下需手动处理Scaled属性 | 内置AutoScaleDPI选项,自动监听WM_DPICHANGED并触发DoScaleChange() | 两者结合才能实现“Windows 设置 DPI 变更 → 控件自动重缩放 → 文档布局实时重排”的闭环 |
常见误用是只装 TRichView,然后自己写OnMouseMove+Invalidate()模拟缩放——这会导致GetItemRect()返回的坐标永远是原始尺寸,后续所有定位功能(如点击跳转到某段落)全部失效。ScaleRichView 8 的价值,正在于它把“缩放”这件事,从 UI 层面的操作,下沉到了文档模型层面的契约。
3. 集成部署实操:从注册、安装到首个可运行的缩放文档窗体
3.1 注册与安装路径确认:避开 IDE 缓存陷阱
TRichView 21.6 + ScaleRichView 8 的“已注册正式版”意味着你拥有合法的.lic许可文件和编译好的dcu/obj库。安装不是简单复制文件,关键在三处路径绑定:
# 典型安装目录结构(以 Delphi 11 Alexandria 为例) C:\TRichView\ ├── Source\ # Pascal 源码(.pas),用于调试和定制 ├── Lib\ # 编译好的 dcu(Delphi)或 obj(C++Builder) │ ├── Win32\ # 32位平台 │ │ ├── TRichView21.dcu │ │ ├── ScaleRichView8.dcu │ │ └── ... │ └── Win64\ # 64位平台(必须单独编译!) ├── Demos\ # 官方 Demo,重点看 ScaleDemo.dpr └── License\ # TRichView.lic 和 ScaleRichView.lic注意:Delphi/C++Builder 的 IDE 会缓存
dcu/obj的编译状态。若安装后新建项目仍提示 “Unit not found”,请执行:
Tools → Options → Language → Delphi Options → Library → Library Path,确认C:\TRichView\Lib\Win32(或Win64)已加入;
然后Project → Options → Delphi Compiler → Search Path,同样加入该路径;
最后必须重启 IDE—— IDE 不会热加载新库路径,这是血泪经验。
3.2 创建第一个缩放文档窗体:5 行核心代码
新建一个 VCL Forms Application,按以下顺序操作:
- 将
TRichView和ScaleRichView的设计时包(.bpl)安装到 IDE:Component → Install Packages → Add → C:\TRichView\Lib\Win32\TRichView21.bpl(同理添加ScaleRichView8.bpl); - 从组件面板拖拽
TRichView到窗体,命名为rvMain; - 拖拽
TScaleRichView到窗体(注意:它是个非可视组件,出现在窗体下方组件栏),命名为srvMain; - 在窗体
OnCreate事件中关联二者并启用缩放:
procedure TForm1.FormCreate(Sender: TObject); begin // 关键1:绑定 TRichView 实例 srvMain.RichView := rvMain; // 关键2:启用自动 DPI 缩放(Windows 10/11 推荐) srvMain.AutoScaleDPI := True; // 关键3:设置初始缩放(100% = 1.0) srvMain.Scale := 1.0; // 关键4:加载一个示例文档(RVF 格式,非 RTF!) rvMain.LoadRVF('C:\TRichView\Demos\ScaleDemo\sample.rvf'); // 关键5:强制首次布局计算(避免首次显示空白) srvMain.DoScaleChange; end;逻辑说明:
srvMain.DoScaleChange是核心触发点。它内部会调用rvMain.RebuildLayout(),再调用rvMain.Invalidate(),确保缩放生效。若省略此行,窗体首次显示时可能内容不渲染或尺寸错乱。参数srvMain.Scale是浮点数,支持0.5(50%)到3.0(300%)任意值,非整数倍缩放(如 1.25x)完全支持。
3.3 添加缩放控制 UI:滑块 + 文本显示联动
用户需要直观的缩放控制。在窗体上添加TTrackBar(tbScale)和TLabel(lblScaleValue),设置tbScale.Max := 300; tbScale.Min := 50; tbScale.Position := 100;,然后:
procedure TForm1.tbScaleChange(Sender: TObject); var NewScale: Double; begin // TrackBar Position 50~300 映射为 Scale 0.5~3.0 NewScale := tbScale.Position / 100.0; // 关键:直接设置 ScaleRichView 的 Scale 属性 srvMain.Scale := NewScale; // 同步更新标签显示(格式化为百分比) lblScaleValue.Caption := Format('%.0f%%', [NewScale * 100]); end;参数说明:
tbScale.Position是整数,除以 100.0 转为Double是为了精度。Format('%.0f%%', [...])确保显示为 “150%” 而非 “150.000000%”。此联动是响应式的——拖动滑块瞬间,srvMain即刻重算布局并重绘,无延迟感。
4. 避坑指南:TRichView + ScaleRichView 生产环境踩过的五个真实坑
4.1 现象:缩放后表格列宽错乱,内容挤到第一列
原因:TRichView 21.6 之前版本中,TRVTableItemInfo.SetColumnWidth()方法未考虑当前缩放因子,直接设置像素值。ScaleRichView 8 在RebuildLayout()时,表格列宽未按Scale重新归一化。
解决:升级到 TRichView 21.6完整版(非精简版),并在创建表格后,显式调用rvMain.TableItem.SetColumnWidth(i, WidthInTwips),其中WidthInTwips使用逻辑单位(1/1440 英寸),而非像素。例如:rvMain.TableItem.SetColumnWidth(0, 2880); // 2英寸宽。
4.2 现象:高 DPI 屏幕下,GetItemRect(ItemNo)返回坐标偏移 20px
原因:Windows 高 DPI 模式下,VCL 窗体默认启用PerMonitorV2,但 TRichView 的GetItemRect未自动适配GetDpiForWindow获取的当前 DPI。
解决:在窗体OnCreate中,手动校正:
// 获取当前窗体 DPI const DPI_96 = 96; var CurrentDPI: UINT; begin CurrentDPI := GetDpiForWindow(Self.Handle); rvMain.DPIScale := CurrentDPI / DPI_96; // 告知 TRichView 当前缩放比 end;4.3 现象:C++Builder 项目编译报错E2251 Ambiguous overloaded call to 'ScaleRichView8::TScaleRichView::Scale'
原因:C++Builder 的TScaleRichView类中,Scale属性同时声明为__property double Scale = {read=FScale, write=SetScale}和__property float Scale = {...},造成重载歧义。
解决:打开ScaleRichView8.hpp,注释掉float Scale声明行(通常在第 127 行附近),保留double Scale。这是 C++Builder 10.4+ 的已知头文件缺陷。
4.4 现象:加载大 RVF 文件(>50MB)时,LoadRVF()卡死 10 秒以上
原因:TRichView 默认LoadRVF是同步阻塞式,且未启用内存映射(Memory-Mapped File)。
解决:使用异步加载 + 进度回调:
procedure TForm1.LoadBigRVFAsync; var Stream: TFileStream; begin Stream := TFileStream.Create('huge.rvf', fmOpenRead or fmShareDenyWrite); try // 启用后台线程加载 rvMain.LoadRVFFromStreamAsync(Stream, procedure(Progress: Integer) // 进度回调,0~100 begin pbLoad.Progress := Progress; end, procedure // 加载完成回调 begin srvMain.DoScaleChange; // 强制刷新 end); finally Stream.Free; end; end;4.5 现象:打印预览中,缩放为 125% 时页眉被截断
原因:TRichView.Print系统默认使用Printer.Canvas,其 DPI 固定为 96,而ScaleRichView的缩放仅作用于屏幕Canvas,未同步到打印上下文。
解决:重写OnPrintPage事件,手动应用缩放:
procedure TForm1.rvMainPrintPage(Sender: TObject; var PageNumber: Integer; var MorePages: Boolean; Canvas: TCanvas; Rect: TRect); var ScaleFactor: Double; begin // 获取当前屏幕缩放,用于打印一致性 ScaleFactor := srvMain.Scale; // 打印时 Canvas 缩放需反向补偿(因为打印是物理尺寸) Canvas.SetScale(1.0 / ScaleFactor, 1.0 / ScaleFactor); // 此处调用 rvMain 的默认打印逻辑 rvMain.DefaultPrintPage(PageNumber, MorePages, Canvas, Rect); end;5. 进阶技巧:用 TRichView 的 RVF 格式构建可版本控制的文档工作流
5.1 为什么坚持用 RVF 而非 RTF 或 HTML?
RTF 是二进制标记,不可 diff;HTML 过于松散,<table>嵌套深度、style属性顺序微小变化就导致 Git 显示全文件变更;而 RVF(RichView Format)是 TRichView 自研的纯文本格式,结构清晰、语义明确、无冗余空格。一个典型 RVF 片段:
[RVF] Version=21.6 [Styles] Normal=1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,......提示:RVF 的
[Styles]段是紧凑的二进制编码(Base64-like),但[Items]段是明文。Git 可以精准 diff 出“第 3 行字体从Arial改为SimSun”或“插入了一个新表格”。
5.2 构建文档 CI/CD 流水线:从 RVF 到 PDF/A-3 的自动化
某医疗软件公司用以下脚本实现文档变更自动验证:
// BuildDocPipeline.pas procedure BuildPDFFromRVF(const InputRVF, OutputPDF: string); var rv: TRichView; pdfExport: TRVPdfExport; begin rv := TRichView.Create(nil); try rv.LoadRVF(InputRVF); // 关键:设置 PDF 导出为 PDF/A-3b 合规 pdfExport := TRVPdfExport.Create(rv); try pdfExport.PDFACompliance := rvpdfa3b; // 强制 PDF/A-3b pdfExport.EmbedFonts := True; // 嵌入中文字体 pdfExport.CompressImages := True; // 图片有损压缩,减小体积 pdfExport.ExportToPDF(OutputPDF); finally pdfExport.Free; end; finally rv.Free; end; end;然后在 GitLab CI 中配置:
stages: - validate-docs validate-rvf: stage: validate-docs script: - "dcc32 BuildDocPipeline.dpr" # 编译验证工具 - "./BuildDocPipeline.exe --input docs/manual.rvf --output docs/manual.pdf" - "pdfinfo docs/manual.pdf | grep 'PDF version'" # 检查是否为 1.7(PDF/A-3 要求) - "verapdf --format text docs/manual.pdf | grep 'PASS'" # 用 veraPDF 验证合规性5.3 动态样式注入:用 JSON 配置驱动 RVF 渲染
不硬编码样式,而是将样式规则外置为styles.json:
{ "heading1": { "font": "Microsoft YaHei", "size": 16, "bold": true, "color": "#2c3e50" }, "codeblock": { "font": "Consolas", "size": 10, "bgcolor": "#f8f9fa", "border": true } }在 Delphi 中解析并注入:
procedure ApplyJSONStyles(const JSONFile: string; rv: TRichView); var JSON: TJSONObject; StyleObj: TJSONObject; StyleName: string; begin JSON := TJSONObject.ParseJSONValue(TFile.ReadAllText(JSONFile)) as TJSONObject; try for StyleName in JSON.Keys do begin StyleObj := JSON.GetValue(StyleName) as TJSONObject; rv.Style.TextStyles.Add; // 添加新样式 with rv.Style.TextStyles[rv.Style.TextStyles.Count - 1] do begin Name := StyleName; Font.Name := StyleObj.GetValue('font').Value; Font.Size := StrToInt(StyleObj.GetValue('size').Value); Font.Style := []; if StyleObj.GetValue('bold').Value = 'true' then Font.Style := [fsBold]; Color := StringToColor(StyleObj.GetValue('color').Value); end; end; finally JSON.Free; end; end;这样,UI 设计师改一个 JSON 文件,开发无需重新编译,重启应用即生效。
从那以后我每次交付带文档功能的项目,都强制走一遍 “RVF → Git Diff → 自动 PDF 生成 → veraPDF 验证” 流程。不是为了炫技,而是当客户指着 PDF 说“这个标题行间距不对”时,我能直接打开 Git 历史,定位到哪一行 JSON 被谁在什么时候改了line-height参数——这才是工程化的底气。希望帮到你。
本文还有配套的精品资源,点击获取