ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Delphi 13 Florence 下 TRichView v23.0.1 全源码包安装与富文本开发实战

Delphi 13 Florence 下 TRichView v23.0.1 全源码包安装与富文本开发实战

简介:本资源为Delphi 13.1(Florence)平台下的TRichView v23.0.1完整源码包,面向使用Object Pascal进行富文本编辑器、报表系统开发的Delphi开发者,尤其适合需要深入组件内部机制或做二次定制的中高级人员。压缩包共约2000个文件,以1416个cpp、292个hpp、188个h等C++源码与头文件为主体,另含19个pas单元、14个dcu编译单元、6个dproj工程文件及dfm、dpk、dpr等Delphi工程资源,并附带chm帮助文档与pdf说明,整体约47.18MB。TRichView支持字体、颜色、段落、页边距等高级格式化,可插入图片、表格、超链接与嵌入对象,并能导出HTML、PDF等格式。完整源码便于研究、调试、修改与扩展,帮助开发者快速构建功能完备的文档编辑与报表模块。目前已有39人学习下载。

1. Delphi 13 Florence 下拿到 TRichView v23.0.1 全源码包,先想清楚三件事

Delphi 13 Florence 发布之后,VCL 生态里被问得最多的一类问题就是富文本控件怎么选。TRichView v23.0.1 for Delphi 13 Florence Full Source 这个包,本质上是把一套成熟的 Delphi 富文本渲染与编辑控件,连同完整源码一起交到你手里。它解决的不是「显示一段带颜色的字」这种小需求,而是文档级排版:多级样式、表格嵌套、图片浮动、页眉页脚、RTF/DOCX 导入导出、超链接与书签、打印分页。适合谁?做 OA、医疗病历、合同模板、报表批注、聊天记录富文本回显的 Delphi 团队。Full Source 意味着你能改底层、能跟版本、能在出问题时自己下断点,而不是对着 DCU 干瞪眼。这一章先把「值不值得投入」讲透,后面再动手。

很多人第一次接触这个包,是被「Full Source」四个字吸引,但真正决定项目成败的,是三个前置判断:你的 Delphi 13 Florence 是 32 位还是 64 位目标、你的文档是「编辑态」还是「只读渲染态」、你的输出格式是 RTF 还是 DOCX。这三个问题没想清楚,装完控件就会在编译期和运行期各翻一次车。我见过太多人把源码包解压后直接 Install,结果包路径里混着旧版本 DCU,编译报一堆找不到单元,最后怀疑是包坏了。其实不是包的问题,是安装顺序和搜索路径没理干净。

TRichView 的定位和普通 Memo、RichEdit 不一样。VCL 自带的 TRichEdit 走的是 Windows RichEdit 控件,受系统版本影响大,样式能力有限,64 位下还有一堆历史包袱。TRichView 是自己实现渲染管线,样式模型、段落模型、表格模型都是自己的类,所以它能做到 RichEdit 做不到的嵌套表格和精确分页。代价是学习曲线:你得理解它的 Style、ParaStyle、Item 三层结构。这一章不展开代码,先把心智模型立住,从第 2 章开始一步步落地。

2. 把 Full Source 包在 Delphi 13 Florence 里装干净:路径、包组与编译顺序

2.1 解压后的目录该看哪几个,别一股脑全加进搜索路径

拿到 rar 先解压到一个短路径,比如D:\Components\TRichView\,不要放在桌面或带中文、带空格的路径下。Delphi 的包编译对路径里的空格和中文容忍度很低,这是血泪经验。解压后典型会看到几个关键目录:源码单元目录(一堆.pas)、设计期包目录(.dpk)、Demo 目录、帮助文档目录。你要做的第一件事不是打开 Delphi,而是先用资源管理器确认.dpk文件在哪,以及源码.pas是否和.dpk在同一层或相邻层。

常见做法是只把「源码单元目录」加进 Library Path,把「设计期包目录」单独用于 Install Packages,不要把 Demo 目录也加进搜索路径。Demo 里经常有同名单元或旧版本残留,一旦进了全局搜索路径,编译时 Delphi 会优先命中 Demo 里的旧文件,报出莫名其妙的「方法签名不匹配」。我一般会在加路径之前,先在整个解压目录里搜一遍有没有重复的.pas文件名,重复的先记下来,后面排错用得上。

提示:解压后先别急着 Install,先确认包里是否有针对 Delphi 13 Florence 的包组文件。不同大版本对应的.dpk可能不同,用错版本会在编译期报「unit not found」或「incompatible type」。

2.2 在 IDE 里加 Library Path 与 Install 包组的正确顺序

顺序错了是新手最常见的翻车点。正确顺序是:先配 Library Path,再编译运行期包,最后 Install 设计期包。运行期包(Runtime Package)负责实际功能单元,设计期包(Design Package)负责把控件注册到 Tool Palette。如果先 Install 设计期包,而运行期包还没编译,IDE 会提示找不到依赖单元。

具体操作:打开 Delphi 13 Florence,Tools → Options → Language → Delphi → Library,在Library Path(对应目标平台,Win32 和 Win64 要分别配)里加入源码单元目录。然后File → Open打开运行期包的.dpk,右键Compile,确认无错。再打开设计期包.dpk,右键Install。安装成功后 Tool Palette 上会出现 TRichView 相关控件页。

// 安装完成后,用一个最小工程验证单元能否被引用 // 新建 VCL Application,在 Unit1 的 uses 里加入核心单元 uses Vcl.Forms, RVStyle, // 样式与段落样式定义单元 RVMain, // 主渲染与编辑控件单元 RVTable; // 表格支持单元(用到表格才需要) procedure TForm1.FormCreate(Sender: TObject); begin // 这里只做编译期验证,不创建控件 // 能编译通过说明 Library Path 配对了 end;

上面这段代码的作用不是跑功能,而是验证搜索路径。RVStyle、RVMain、RVTable是 TRichView 体系里最常被引用的三个单元,如果这三个都能被编译器找到,说明路径基本正确。参数说明:RVStyle管样式,RVMain管控件主体,RVTable管表格,按需引用,不要无脑全加,否则编译变慢还容易撞名。如果这一步报「unit not found」,回去检查 Library Path 是不是加在了错误的平台节点下——Win32 的路径不会自动作用于 Win64。

2.3 编译顺序与平台目标:Win32 和 Win64 要各来一遍

Delphi 13 Florence 默认可能只配了一个平台。TRichView 的源码是跨平台的,但包编译是按平台分开的。你如果在 Win32 下 Install 成功,切到 Win64 编译工程时可能又报找不到单元,因为 Win64 的 Library Path 和包二进制是独立的。常见做法是:在Project Manager里把目标平台切到 Win64,重新对运行期包Compile一次,再确认设计期包在 Win64 下也 OK。

这里有个容易忽略的点:设计期包通常只需要在一个平台下 Install 给 IDE 用,但运行期包必须每个目标平台都编译。如果你只做 Win32 应用,可以跳过 Win64;但只要工程里出现过 64 位目标,就必须补上。我一般会在装完后立刻建两个空工程,一个 Win32 一个 Win64,各引用一次核心单元,确认都能编译,再开始写业务。这一步花五分钟,能省后面半小时的排查。

3. TRichView 的样式模型怎么落地:Style、ParaStyle 与 Item 三层结构

3.1 为什么不能像 RichEdit 那样直接塞文本,三层模型到底解决什么

TRichView 和 RichEdit 最大的区别在于它把「字符样式」「段落样式」「内容项」拆成了三层。字符样式(TextStyle)管字体、颜色、粗斜体;段落样式(ParaStyle)管对齐、缩进、行距、段前段后;内容项(Item)是文档流里的最小单位,可以是一段文字、一张图片、一个表格、一个控件占位。你往文档里加内容,本质是往 Item 列表里追加不同类型的 Item,每个 Item 再引用自己的样式索引。

这个模型的好处是:改一处样式,所有引用该样式的 Item 一起变,不用遍历文本。坏处是:你不能像 RichEdit 那样SelAttributes.Color := clRed直接改,必须先有样式,再让 Item 指向它。新手最容易犯的错就是「想临时改一个字颜色」,结果去改全局样式,把整篇文档都改了。正确做法是新建一个 TextStyle,只让目标 Item 用它。

// 初始化一个 TRichView 的样式体系(通常在窗体创建时做一次) procedure TForm1.InitRVStyles; begin // 清空默认样式,避免和设计期残留冲突 RVStyle1.TextStyles.Clear; RVStyle1.ParaStyles.Clear; // 正文样式:宋体 10.5,黑色 with RVStyle1.TextStyles.Add do begin FontName := '宋体'; Size := 10; // 单位是 pt 的十分之一,10 表示 1pt?注意这里按控件约定 Color := clBlack; end; // 强调样式:红色加粗,索引为 1 with RVStyle1.TextStyles.Add do begin FontName := '微软雅黑'; Size := 12; Color := clRed; Style := [fsBold]; end; // 段落样式:左对齐,首行缩进两个字符 with RVStyle1.ParaStyles.Add do begin Alignment := taLeftJustify; FirstIndent := 20; // 单位与控件约定一致,按实际文档调整 end; end;

逻辑说明:TextStyles.Add返回一个样式对象,索引从 0 开始。后面往文档加 Item 时,用索引指定样式。参数说明:Size的单位在不同版本里可能是 pt 或十分之一 pt,务必用 Demo 里的实际效果校准,不要凭记忆写。FirstIndent同理,单位不对会导致缩进看起来「玄学」——明明设了 20 却几乎没缩进,或者缩进到屏幕外。我一般会先做一个只有一行字的测试文档,把缩进调到肉眼合适,再记下这个数值用到正式代码里。

3.2 往文档里追加带样式的段落:AddText、AddPicture 与换行控制

有了样式,就可以往文档里加内容。TRichView 的追加 API 是流式的:先AddText加文字,再AddPicture加图片,段落结束时用AddText(#13)或专门的换行方法。注意#13在 TRichView 里是否被当作段落分隔,取决于版本和配置,稳妥做法是用它提供的段落结束方法,而不是硬塞回车符。

// 往文档追加一段正文 + 一段强调文字 + 一张图片 procedure TForm1.BuildDocument; begin RVMain1.Clear; // 清空现有内容 // 第一段:正文样式(索引 0),段落样式(索引 0) RVMain1.AddText('这是正文第一段,使用默认样式。', 0); RVMain1.AddText(#13, 0); // 段落结束,具体以控件文档为准 // 第二段:强调样式(索引 1) RVMain1.AddText('这是红色加粗的强调内容。', 1); RVMain1.AddText(#13, 1); // 追加一张图片,图片本身不依赖文字样式 RVMain1.AddPicture('D:\test.png', 0); end;

逻辑说明:AddText的第二个参数是 TextStyle 索引,不是 ParaStyle 索引。段落样式通常在段落级 API 里设置,或者通过ParaStyleNo属性控制。参数说明:图片路径必须是绝对路径或工程能解析的相对路径,路径不存在时不会抛异常,而是静默不显示,这是排查「图片不出现」时的第一检查点。Clear会释放已有 Item,频繁重建文档时要注意性能,大文档建议用增量更新而不是每次 Clear。

3.3 表格与嵌套:TRichView 表格模型和普通 Grid 的本质差别

TRichView 的表格是文档流的一部分,不是独立的 Grid 控件。这意味着表格可以嵌在段落之间,单元格里还能再放文字、图片甚至另一个表格。这和 StringGrid、DBGrid 完全不是一个思路。做合同、病历这类「表格里套表格」的文档,这是它最值钱的地方。

// 在文档中插入一个 2x2 表格,并往单元格写内容 procedure TForm1.InsertTable; var Table: TRVTableItemInfo; begin // 创建表格对象,2 行 2 列 Table := TRVTableItemInfo.CreateEx(2, 2, RVMain1.RVData); try // 往单元格写文字,样式索引 0 Table.Cells[0, 0].AddText('姓名', 0); Table.Cells[0, 1].AddText('张三', 0); Table.Cells[1, 0].AddText('科室', 0); Table.Cells[1, 1].AddText('内科', 0); // 把表格作为 Item 追加到文档 RVMain1.AddItem('', Table); except Table.Free; raise; end; end;

逻辑说明:CreateEx创建表格,Cells[row, col]访问单元格,单元格本身也是一个小文档容器,所以能继续AddText。参数说明:行列索引从 0 开始;AddItem把表格挂到主文档流。注意异常处理里Table.Free的位置——如果AddItem成功,表格所有权转移给文档,不能再 Free;只有失败时才需要自己释放。这个所有权细节是 TRichView 里最容易内存泄漏的地方,我一般会在AddItem前后各打一个日志,确认所有权转移时机。

4. 富文本导入导出与打印:RTF、DOCX 和分页的边界在哪

4.1 RTF 导入导出:格式保真度和样式映射的取舍

TRichView 支持 RTF 读写,但「支持」不等于「无损」。RTF 本身是个老格式,样式表达能力有限,TRichView 的高级特性(比如某些嵌套表格、自定义 Item)导出成 RTF 会丢。常见做法是:如果文档只在你的系统内部流转,用 TRichView 自己的格式存;如果要和 Word 互通,用 RTF 或 DOCX,并接受一定程度的样式简化。

// 导出当前文档为 RTF 文件 procedure TForm1.ExportRTF(const AFileName: string); begin RVMain1.SaveRTF(AFileName, False); // 第二个参数控制是否包含某些扩展信息 end; // 从 RTF 文件导入 procedure TForm1.ImportRTF(const AFileName: string); begin RVMain1.LoadRTF(AFileName); end;

逻辑说明:SaveRTF和LoadRTF是最简单的出入口。参数说明:第二个布尔参数在不同版本里含义可能不同,常见是控制是否写入兼容性标记,建议先用 Demo 里的默认值,确认 Word 打开正常后再调。导入时如果 RTF 里用了系统没装的字体,TRichView 会回退到默认字体,不会报错,所以「导入后字体变了」通常不是控件 bug,是字体缺失。

4.2 DOCX 导出的现实预期:哪些能带过去,哪些一定丢

DOCX 导出比 RTF 新,但同样不是无损。能稳定带过去的是:文字、基本字符样式、段落对齐、简单表格、图片。容易丢的是:TRichView 特有的 Item 类型、复杂嵌套表格的边框细节、自定义绘制。我的经验是:把 DOCX 导出当成「给外部看的快照」,不要当成「可再编辑的工程文件」。如果业务要求 Word 里改完再导回来还能完全还原,那要提前做格式能力评估,别等上线才发现。

4.3 打印与分页:为什么屏幕上好好的,打印就断行错位

打印错位是富文本控件的经典坑。屏幕上按像素排版,打印按物理尺寸排版,两者的字体度量、边距、DPI 都不一样。TRichView 提供了打印相关的分页控制,但需要你显式设置页面尺寸和边距,不能指望它自动和屏幕一致。

// 打印前设置页面参数(示意,具体属性名以控件版本为准) procedure TForm1.SetupPrint; begin RVMain1.PrintPageWidth := Round(21.0 * 96 / 2.54); // A4 宽约 21cm 换算成像素 RVMain1.PrintPageHeight := Round(29.7 * 96 / 2.54); // A4 高 RVMain1.PrintMargins.Left := 100; RVMain1.PrintMargins.Right := 100; RVMain1.PrintMargins.Top := 100; RVMain1.PrintMargins.Bottom := 100; end;

逻辑说明:把物理尺寸换算成打印像素,再设边距。参数说明:96是屏幕 DPI 假设值,实际打印 DPI 可能不同,所以更稳的做法是用控件提供的物理单位 API,而不是自己硬算。如果打印出来每页行数不对,先检查PrintPageHeight和边距是否把可用高度算错。我一般会先打一份只有页码的测试文档,确认分页点,再放正式内容。

5. 避坑与排查:TRichView 在 Delphi 13 下最容易翻车的五个点

5.1 安装后 Tool Palette 有控件,但拖到窗体就报「Class not found」

现象:包 Install 成功,控件图标也在,但一拖到 Form 上就弹异常,提示类未注册或找不到。原因:设计期包和运行期包的平台不匹配,或者 IDE 里残留了旧版本的同名包。解决:Component → Install Packages里把所有 TRichView 相关包先 Remove,重启 IDE,再按「先运行期后设计期」的顺序重装,并确认两个包的目标平台一致。

5.2 编译报「Unit RVMain was compiled with a different version of RVStyle」

现象:明明只装了一个版本,却报单元版本不一致。原因:Library Path 里同时存在两份源码,或者某处残留了旧 DCU。解决:在 IDE 的Tools → Options → Library里检查路径顺序,把旧路径删掉;再全盘搜索RVStyle.dcu,把非当前版本的 DCU 清掉,然后 Rebuild 整个包。

5.3 文档里图片显示为空白,但文件确实存在

现象:AddPicture调用没报错,文档里就是没图。原因:路径是相对路径,运行时工作目录和你想的不一样;或者图片格式不被当前版本支持。解决:改用绝对路径先验证;确认格式(常见是 BMP、JPEG、PNG,具体支持列表看 Demo);如果是网络路径,先拷到本地测试。

5.4 大文档编辑卡顿,输入延迟明显

现象:文档超过几十页后,每次输入都卡。原因:每次修改触发了全文档重排,或者样式对象被频繁创建销毁。解决:批量修改时用BeginUpdate/EndUpdate包起来;样式对象在初始化时建好复用,不要在循环里反复Add;如果只是只读展示,考虑用渲染模式而不是编辑模式。

5.5 导出 RTF 后在 Word 里打开,表格边框全没了

现象:TRichView 里表格有边框,导出 RTF 后 Word 里看不到。原因:RTF 的表格边框表达方式和 TRichView 内部模型不完全对应,部分边框属性没被写出。解决:导出前把表格边框设成 RTF 能表达的标准样式;或者改用 DOCX 导出;如果必须 RTF,接受简化并在文档规范里写明。

6. 把 TRichView 用进真实项目的两个进阶习惯

第一个习惯是「样式集中管理」。不要在业务代码里到处TextStyles.Add,而是建一个样式注册表,启动时一次性建好,业务代码只引用索引或常量。这样后期改视觉规范,只改一个地方。我吃过亏:一个病历项目里样式散落在十几个单元,改一次字体颜色花了一整天。

第二个习惯是「文档构建与渲染分离」。把「生成文档内容」和「把内容显示到控件」拆成两步,中间用一个中间结构(比如自定义的段落列表)过渡。这样同一份内容可以渲染到 TRichView、导出 RTF、导出 DOCX、打印,而不用为每种输出写一遍逻辑。验证方法是:写一个单元测试,构造中间结构,分别跑四种输出,检查关键字段是否一致。

输出目标建议路径主要丢失项
内部存储TRichView 原生格式无
Word 互通DOCX 导出自定义 Item、复杂嵌套边框
老系统互通RTF 导出高级表格、部分样式
打印打印 API + 分页设置屏幕与纸张度量差异

最后一个技巧:调试文档问题时,先把文档SaveRTF到磁盘,用文本编辑器打开看结构。RTF 是纯文本,样式和内容都在里面,比在 IDE 里猜快得多。这个习惯帮我定位过好几次「样式没生效」的问题——一看 RTF 就知道样式索引根本没写进去。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进