Delphi 13中TRichView富文本控件的安装配置与避坑指南
发布时间:2026/10/10 7:53:33 锦皓数字建站

简介面向使用 Delphi 13 Florence 的应用开发者这份 TRichView v23.0.1 完整源代码包提供了专业级富文本处理组件的全部实现适合需要构建文档编辑器、报表系统或复杂排版界面的中高级工程师使用。压缩包共收录 2000 个文件以 1416 个 C 源文件、292 个头文件、188 个头文件以及 19 个 Delphi 单元文件为核心辅以工程配置、组件包、资源文件、编译后单元和多份帮助文档覆盖了界面、核心引擎与项目构建等完整代码结构便于查阅接口与理解架构整体压缩包约 47.18MB。目前已有 39 人浏览学习。从源码中可深入探究字体样式、段落控制、图片表格插入、超链接及嵌入对象等高级功能的实现机制掌握导出 HTML、PDF 等格式的底层方法也可直接修改单元代码以满足定制需求对提升 Delphi 原生组件二次开发能力很有帮助。整体来看这份源码既可直接安装使用也可作为扩展富文本功能的开发蓝本。1. 用 TRichView 之前先搞懂为什么选择 Full Source做 Delphi 桌面端的都知道编辑器这块历来是痛点。Memo 只能处理纯文本标准 RichEdit 一遇到复杂排版、表格套嵌、HTML 互转就开始摆烂等你真把几千行带图片的合同文档加载进来卡顿和乱码会一起找上门。TRichView 这套商业控件解决的就是这个场景——它提供一套完全自绘的富文本文档模型不依赖系统 RichEdit支持 RTF、HTML、图片、表格、段落样式而且每个元素都可以精确控制。标题里出现的Full Source更是关键源码不仅意味着可以下断点跟进每一次鼠标点击后的内部状态变化更意味着 Delphi 13 升级时你可以自己动手把不兼容的接口补上而不是黑着匣子等作者更新。这个包适合两类人一类是正在做 OA、合同管理、病历编辑这类需要复杂排版能力的桌面程序另一类是已经受够了第三方编辑器控件在中文排版和性能上翻车的开发者。接下来我按自己的落地顺序来拆先装对再调通后避坑最后讲几个让这套控件真正值回票价的用法。2. 在 Delphi 13 Florence 里安装 TRichView v23.0.1解压、搜索路径与编译顺序2.1 解压前先核对版本号与目录结构拿到 rar 压缩包后别急着双击解压到桌面。TRichView 的目录结构依赖安装路径后面配置 Delphi 的 Library Path 时要用绝对路径路径里一旦出现中文、空格、过长层级IDE 编译搜索文件时就会出幺蛾子。我一般先建立一个干净的目录例如D:\Components\TRichView\v23.0.1然后把包解进去。解压完成后先打开根目录看一下。这个版本对应 Delphi 13 Florence支持的平台包括 Win32 和 Win64。源码包内部一般会按source、packages、lib、demos组织。真正需要关心的不是 demos而是以 delphi 版本号命名的分组包目录。比如Packages\Delphi13\下存放的是面向新版本的编译工程文件里面有.dpk包工程和.dproj项目。不要一上来就打开 IDE 双击安装先确认包分组目录里是否存在RichView_D13.dpk或类似命名的文件——这是能否在 Delphi 13 里成功编译的前提。注意如果解压后发现目录里只有.dpk没有.dproj说明该包是在旧版 IDE 环境打包的。Delphi 13 可以打开.dpk并自动迁移生成.dproj但迁移过程中可能丢失平台配置需要手动补。建议直接检查*.dproj的存在性缺失时先在资源管理器里看有没有Helper脚本或Build批处理文件。2.2 配置库路径与编译包顺序反了会白忙活很多人在 Delphi 13 安装第三方控件失败原因是编译.dpk之前没有提前把源文件目录加入 IDE 的 Library Path。TRichView 的包之间互相引用如果包的requires子句里的单元找不到编译器的报错往往不是“找不到文件”而是一连串莫名其妙的F1026 File not found: RichView.pas。所以顺序必须是先加搜索路径再编译安装包。操作路径如下打开 Delphi 13 IDE进入Tools Options Environment Options Delphi Options Library在Library Path里添加下面三条具体以你的解压目录为准D:\Components\TRichView\v23.0.1\Source D:\Components\TRichView\v23.0.1\Packages\Delphi13 D:\Components\TRichView\v23.0.1\lib这里有个参数细节Library Path是给编译器和 IDE 的工程搜索器用的Browsing Path是给代码编辑器里的代码提示和定义跳转用的。如果只加了 Library Path 而忘记加 Browsing Path编译能通过但按Ctrl点击跳不进 TRichView 源码调试时容易抓瞎。所以两条路径都添上同样的目录。添加完路径后重新打开 Delphi 13保险起见路径变量刷新偶尔需要重启 IDE随后开始编译包。2.3 从源码编译并安装到 IDE 的完整操作在 IDE 里打开Packages\Delphi13\RichView_D13.dproj工程文件右键 Project Manager 里的RichView_D13工程节点选择Compile。观察 Messages 窗口确认没有红字报错后再右键选Install。Install 会把设计期包注册到 IDE 的组件面板安装成功后你会看到一个名为RV或RichView的新组件页里面有TRichView、TRichViewEdit、TRichViewPrint等若干控件。安装过程如果不想手工在 GUI 里点也可以用命令行方式批处理内容如下echo off REM 切换到包所在目录确保 MSBuild 能找到工程文件 cd /d D:\Components\TRichView\v23.0.1\Packages\Delphi13 REM 先清理旧生成文件避免残留 .dcu 影响新版编译 msbuild RichView_D13.dproj /t:Clean /p:ConfigRelease if errorlevel 1 goto :error REM 用 Release 配置编译平台选 Win32生成 .bpl 与 .dcu msbuild RichView_D13.dproj /t:Build /p:ConfigRelease /p:PlatformWin32 if errorlevel 1 goto :error echo 编译完成请回到 IDE 中执行 Install 操作注册设计期包。 goto :eof :error echo 编译失败查看 MSBuild 输出定位缺失单元或路径错误。这段批处理的逻辑是先 Clean 掉可能存在的旧版.dcu文件防止 Delphi 13 的编译器捡到上一个版本留下的二进制单元导致链接错误然后以 Release 配置编译。其中/t:Clean与/t:Build是 MSBuild 的目标操作/p:ConfigRelease指定使用发布配置比 Debug 少一些断言代码运行效率更高/p:PlatformWin32限定 32 位目标。如果你后续想编译 Win64 版的运行时包把 Platform 换成 Win64 再执行一次即可。注意Install 操作必须在 IDE 里手工执行命令行编译不会自动注册组件到面板。如果跳过 Install你只是编译出了.bpl文件设计期仍然拖不出控件。2.4 验证安装跑通一个最小编辑器安装完成后新建一个 VCL 应用程序在窗体上放一个TRichViewEdit一个TButton然后给按钮写加载 RTF 的代码。运行起来能打开.rtf文件就说明编译安装全链路是通的。这里有一个很容易忽略的验证点要把项目设置为释放编译Release再跑一次避免 Debug 模式下没暴露 DLL 依赖问题。Release 下如果报Unable to load package RichView_D13.bpl八成是搜索路径里少了.bpl所在的输出目录把包工程的Output Directory也补进 Library Path 即可。3. 设计一个可用的 TRichView 编辑器核心属性、文档模型与工具栏联动3.1 TRichView 与 TRichViewEdit一个负责展示一个负责编辑初次接触 TRichView 的人容易犯一个错误以为 TRichView 本身就能当编辑器用。实际上 TRichView 是只读的文档呈现组件它负责加载、排版、绘制、打印真正接受键盘输入、光标移动、选中高亮的是TRichViewEdit。两者共享同一个文档模型单元CRVData所以你可以把TRichViewEdit当作“可编辑的 TRichView”。从架构上看这带来一个好处同一个文档可以同时挂在两个组件上比如左边是编辑区右边是只读预览区它们之间通过RichViewEdit.Assign(RichView)或共享RVData实现数据同步。这在做合同编辑的左右分栏预览时特别有用不需要在文档改变后手动重新加载文件。3.2 必须调对的几个核心属性下面是实际开发中几乎每天都要碰到的属性参数按重要程度排列属性参数设置作用踩坑点RichViewEdit.RTFReadPropertiesTextStylesMode rvrsAddIfNeeded控制从 RTF 读入时如何处理文档里出现的未知文本样式设成rvrsIgnore会把原有样式丢掉中文排版全乱RichViewEdit.RTFWritePropertiesTextStylesMode rvrsAllSameSaveImages True写出 RTF 时的样式保存策略决定是否内嵌图片rvrsAllSame让输出体积更小但复杂样式可能丢失Options[rvsoHorzScrollBar, rvsoVertScrollBar]控制编辑器的滚动条显示漏掉rvsoAllowPopups会导致右键菜单不弹RichViewEdit.StyleTBackgroundStyle的FillColor统一管理字体颜色、超链接、段落样式不赋值的话默认样式表为空输入中文时可能出现方块OnChange事件Changed标记在每次文档修改后触发可联动保存按钮置灰/置亮程序初始化时赋默认文本也会触发注意加状态锁其中RTFReadProperties.TextStylesMode是需要重点说明的参数。RTF 文件里每个文本片段都可能带独立的字体定义如果你设成rvrsAddIfNeededTRichView 会把文档中出现的每个新样式追加到样式表中——文档越复杂样式表膨胀越严重设成rvrsUseExisting则相反遇到未知样式时套用一个已有默认样式适合做统一排版。我通常建议编辑器类工具用rvrsAddIfNeeded而导出类工具用rvrsUseExisting原因后面避坑章会展开。3.3 加载与保存三种格式的读写细节TRichView 读写文件不是直接调LoadFromFile就完事的。它区分了LoadRTF、LoadHTML、LoadText三个入口而且格式只是入口内部转换依赖你在设计期设置好的一组RTFReadProperties、HTMLReadProperties、TextReadProperties。以加载 RTF 为例常见的做法是procedure TForm1.LoadRtfFile(const AFileName: string); var Stream: TFileStream; begin // 用文件流方式读取避免 TRichView 内部重复打开文件句柄 Stream : TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone); try // 先清空再加载防止旧文档的样式污染新文档 RichViewEdit.Clear; // 加载过程中自动应用 RTFReadProperties 的样式策略 RichViewEdit.LoadRTFFromStream(Stream); RichViewEdit.Modified : False; finally Stream.Free; end; end;这段代码有三个细节值得说。第一用fmShareDenyNone打开文件流是因为 Word 或 WPS 经常以共享读方式占用 rtf 文件不同这个标志的话LoadFromFile会直接抛共享冲突。第二Clear必须在LoadRTFFromStream之前调用否则旧文档的样式表会残留在文档数据里新文档的样式序号错位切换文档后有概率出现字体突然变大的怪象。第三加载成功后必须把Modified置回False否则用户什么都没做关闭程序时也会弹“是否保存”的提示。保存时对称SaveRTFToStream之前要设置RTFWriteProperties里的SaveImages。如果设为False文档里的图片会丢失如果设为True输出的 RTF 会变成 OLE 对象内嵌格式体积暴涨。嵌入式 OA 的合同数据表里我一般建议在保存时把图片单独抽出来存文件RTF 里只保留引用路径避免 RTF 文件动辄几十 MB。3.4 一个可抄作业的最小编辑器代码搭建一个够用的编辑器壳子下面这段代码可以直接粘到窗体里type TForm1 class(TForm) RVEdit: TRichViewEdit; ToolbarPanel: TPanel; BtnBold: TButton; procedure BtnBoldClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure RVEditChange(Sender: TObject); private FRichViewSet: TRichView; // 只读预览组件 end; implementation procedure TForm1.FormCreate(Sender: TObject); begin // 设置基础的文档样式避免输入中文变成方块 RVEdit.Style : TBackgroundStyle.Create(nil); RVEdit.Style.FillColor : clWhite; // RichViewEdit 必须设置默认字体中文环境用宋体最稳妥 RVEdit.SetFont(宋体, 10); end; procedure TForm1.BtnBoldClick(Sender: TObject); begin // 针对当前选中文本切换粗体属性 if Assigned(RVEdit.RVData) then RVEdit.RVData.SetItemBold(RVEdit.RVData.GetOffsBeforeCurItem, not RVEdit.RVData.IsItemBold(RVEdit.RVData.GetOffsBeforeCurItem)); end; procedure TForm1.RVEditChange(Sender: TObject); begin // 文档被修改时联动预览组件刷新 if Assigned(FRichViewSet) then FRichViewSet.Assign(RVEdit); end;这段代码里RVEdit.RVData是文档模型的核心对象所有针对光标位置的查询和修改都要经过它。GetOffsBeforeCurItem拿到当前光标所在项的偏移位置IsItemBold判断该项是否为粗体SetItemBold设置粗体状态。粗体切换不是简单的SelAttributes.Style : fsBold因为 TRichView 的文档模型里每个 item 都携带独立的字符样式必须通过RVData定位到 item 再操作。这也是它和标准 RichEdit 在设计思路上最大的区别。4. 这几个坑最常翻车安装与运行的避坑笔记4.1 编译时冒出msxmldom.dcu not found跟 TRichView 没半毛钱关系现象编译一个本来就正常的老项目加入 TRichView 后突然疯狂报msxmldom.dcu not found。原因这个单元属于 Delphi 自带的 XML 相关包。TRichView 的 HTML 导入导出功能依赖 MSXML DOM 解析器它的uses里声明了这个单元。但你的工程搜索路径里没有包含 Delphi 的 XML 源目录或者你安装的 Delphi 13 组件不完整缺少了xmldom相关的运行时源文件。常见于精简版 Delphi 或手动清理过source目录的环境。解决先检查Tools Options Library里的系统路径是否包含$(BDSLIB)\$(Platform)\release以及$(BDS)\source\rtl\win32等缺什么补什么。补完还是不行的直接使用 XML 直译器时忽略当前安装包附带的RVXml.pas改用 TRichView 自身实现的 XML 接口在工程里dcc32的参数中增加-D NO_MSXML再重编译。注意这个宏要在工程的Conditional Defines里同时为调试版和发布版设置否则用户环境里报的错就是“没有定义”。4.2F1026 File not found: RichView.pas但文件明明存在现象路径配置正确文件也确实在硬盘上但 IDE 编译时提示找不到。原因这是 Delphi 13 的 Library Path 和项目*.dproj中的DCC_UnitSearchPath互相干扰导致的。dproj文件里如果你之前手动编辑过搜索路径IDE 会优先用项目里的路径而忽略全局 Library Path。另外TRichView 的源目录里存在多个子文件夹编译器递归搜索子目录的能力有限遇到.pas放在深层子目录的情况就会漏。解决打开Project Options Delphi Compiler Search Path把 TRichView 的Source目录和Source\gpl等所有包含.pas的子目录全部显式添加进去不要依赖全局路径。还要检查是否有SearchPath里写着$(BDSCOMMONDIR)\components把这个变量展开后如果指向了旧的组件目录也可能让编译器优先搜到老版本的RichView.pas。4.3 安装后 IDE 每次启动都弹“无法加载包”或访问冲突现象安装成功后重启 Delphi 13弹窗提示包加载失败或者打开窗体设计器时报 Access Violation。原因最常见的是同时安装了 32 位和 64 位的包而 IDE 本身是 32 位进程却加载了 64 位的设计期包另外旧版的RichViewDesign设计期包和 v23.0.1 的运行时包版本不匹配互相调用接口时崩掉。解决反编译线上的经验是只保留当前 IDE 架构对应的设计期包。用到 64 位就把 64 位的运行包编出来放到系统目录但设计期包始终只安装 32 位版本。另外卸载旧版包时一定要把C:\Users\用户名\AppData\Roaming\Embarcadero\BDS\23.0\KnownPackages\里残留的.bpl注册项一起清掉。这种暗雷不在项目文件里而是在 KnownPackages 里IDE 启动时会读它。4.4 中文输入后光标错位或回车不换行现象在 TRichViewEdit 里输入中文时光标跑到字符后面或者按回车后没有生成新段落。原因TRichView 的文档模型对中文字符宽度计算依赖字体映射。如果你在设计期先设置了Font.Charset : ANSI_CHARSET运行后用户输入的是 UTF-8 中文内部字符宽度计算就会错乱。另一个原因是输入法在 IME 组合阶段 TRichView 没有正确处理WM_IME_NOTIFY消息回车被输入法吞掉。解决组件初始化时强制设置RVEdit.Options : RVEdit.Options [rvsoAllowTextOverflow]并确保字体设置为DEFAULT_CHARSET不要写死 ANSI。如果还不行检查窗体上是否放了TApplicationEvents并拦截了Message某些版本里它会把WM_IME_CHAR消息过滤掉。4.5 表格单元格内无法正常编辑或选择现象插入表格后点击单元格能显示光标但输入文字后光标消失或者跨单元格选择区域不正确。原因表格在 TRichView 文档模型中是特殊的TRVTableCell子文档它内部的RVData与外部文档的RVData不同。如果你在OnMouseDown里手动写了 RVData 的定位代码使用的却是外层的RVData就会定位失败。解决在需要操作表格时先从RichViewEdit.GetCurrentItem判断Item is TTableCell如果是表格单元格用TTableCell(Item).Data获取内部的TRichViewData再进行操作。代码切换表格和文本的样式时同理要先检查当前是否在表格里。5. 该不该换掉标准 RichEdit选型对比与 Full Source 的真正价值5.1 功能维度对比TRichView 比标准控件多出什么维度标准 RichEditTRichView关键差异文档模型系统内部 OLE 对象黑匣子纯 Delphi 对象树可遍历调试时可看到每个 item 的所有属性RTF 兼容度依赖系统版本XP 与 Win11 不同自带完整 RTF 解析器跨系统一致性强HTML 互转原生不支持需要自己写转换器内置SaveHTMLToStream可直接生成网页版合同预览表格1.0 版本几乎不可用支持嵌套表格、合并单元格复杂排版的核心刚需图片缩放无支持百分比缩放、裁剪插入大图不会让编辑器卡死自定义绘制只能通过 OLE 回调可以重写DrawItem事件可以做批注、水印、修订标记对做 OA 或医疗系统开发的人来说表格和 HTML 互转能力往往是决定性的。合同里套一个“住院费用清单”的自适应表格标准 RichEdit 做起来会让人怀疑人生TRichView 里面只需要一个TTable的MergeCells和设置列宽比例就能处理。5.2 性能与内存文档模型带来的真实差异标准 RICHEDIT 的能力依赖操作系统的 riched20.dll它内部有复杂的 OLE 容器和流化机制文档大到一个阈值会自动启用分层存储而 TRichView 把一个文档里的所有内容线性化存储为 item 数组。这看起来 TRichView 更占内存实际上恰恰相反。标准 RichEdit 为了兼容各种 OLE 嵌入对象每个段落都会保留不少元数据TRichView 的 item 只存实际内容和一个样式索引内存消耗是更可控的。实测一个 200 页的合同带十张图和几十个表格标准 RichEdit 拖起来明显掉帧TRichView 在相同机器上流畅度能保持住。原因在于 TRichView 绘制时只重绘可视区域内的 item而不是全文档重排。5.3 Full Source 在维护上的回报不再被圣诞节打爆电话商业控件最怕什么怕作者停更怕新版 Delphi 一出控件不再兼容怕客户机器上字体映射和你本地不一致导致排版出错。Full Source 版虽然贵但买的是“后悔药”Delphi 12 升 13 时如果某个内部结构改了导致编译不过你可以自己打开源码改一行而不是上论坛发帖等回复。另一个实际收益是中文排版定制——TRichView 的默认断行逻辑遵循西方排文规则对中文标点避头尾的处理不够有源码在手你可以直接改RichView.pas里的BreakText相关函数逻辑。5.4 什么时候不值得上 TRichView不是所有项目都该用重型控件。如果你的需求只是做一个便签工具、一个纯文本存储查看器、或者 Form 上的简单备注输入标准 Memo 就够了。TRichView 的启动包体积、内存占用、安装复杂度都是额外成本。还有人用它来做富文本邮件编辑实际上 UI 层复杂度远高于邮件协议层的富文本兼容需求这时不如直接上 HTML 编辑器容器。选型时能走标准控件就优先标准控件标准控件确实搞不定了再切 TRichView。切换的成本主要在于所有原来对TMemo的Lines.Text操作要改成RVData的 item 操作逻辑完全不是一个模型改造成本不是改 API 名称那么简单。注意如果你目前只停留在RichEdit.Lines.Add这个层面那么垂直切换到 TRichView 之后你需要先转变理念TRichView 里没有“行”的概念只有“段落”和“item”。前者是容器后者是内容单元。这种粒度变化是一切 API 差异的根源。6. 进阶技巧把 TRichView 从“能用”变成“好用”的三个操作6.1 用自定义段落样式实现“自动编号但不自动重排序”很多人用 TRichView 做文档套打时发现它不像 Word 一样自动维护多级列表。别急着硬写字段更新逻辑利用它底层的能力在OnParaOptionsChange事件里拦截列表项的变化然后为每个段落标记自定义序号。比如给段落样式增加一个VisibleNo属性文档加载完成后遍历所有段落统计相同 listId 的段落在当前章节中的序号再重新绘制这些序号。这样做的好处是序号不是文本永远不需要处理“删掉一行字后编号从 3 跳到 5 但缩进不跟着变”的问题。6.2 打印与 PDF 导出不让编辑器撤掉最后一块拼图TRichView 的打印依赖TRichViewPrint组件它可以直接把文档模型映射到TPrinter.Canvas上。PDF 导出的做法常见有两种一是把打印画布挂载到TPDFPrinter之类的第三方打印驱动上二是在 Delphi 13 里直接用TPrinter.SetPrinter切换到 PDF 打印机。前者能保留字体嵌入后者实现成本低但依赖机器装了 PDF 虚拟打印机。我的习惯是实现两个分支发布版走代码判断系统是否有 PDF 打印机没有就用自带的TRichViewPrint配合一个成熟的 GDI 转 PDF 库。注意在分页打印时TRichViewPrint.FormatPages要在OnBeforePrintPage里做页眉页脚重绘不要在打印循环里反复调用否则性能会断崖式下跌。6.3 增量保存大型编辑器应用防崩溃的救命设计TRichView 的SaveRTFToStream每次都会把整个文档全量写出去。对于用户长时间编辑、文档超过几十 MB 的场景每次自动保存都在挑战硬盘和用户耐心。更稳的做法是维护一个“脏标记”列表OnChange触发时记录本次变化的 item 范围自动保存任务只输出自上次保存以来被修改的 item。TRichView 虽然没提供直接增量 API但它支持SaveTextPiece等片段导出接口可以把变化区域先转成纯文本增量日志异常恢复时再重放。这个方案会丢失格式历史但至少保证了崩溃后不会完全丢内容。这也是我从一个做病历系统的朋友那里学到的教训——他的客户 400 页的病历文书全量保存一次要 4 秒加了增量日志机制后 100 毫秒内搞定。最后讲一个花了我一个下午才想通的习惯每写完一段 TRichView 的代码我都会在RVData.OnModified里挂一段OutputDebugString记录哪个 item 和哪个样式发生了变化。一段时间后你会在日志里发现看似无害的AddText其实会重建整个段落对象导致前面几段设置的样式全被重置。这种问题靠肉眼很难看出但日志不会骗人。希望这些笔记能让你少走几个弯路——至少不用像我一样为了一个光标错位的问题把RichView.pas翻了个底朝天。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。