ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

TRichView 23.1全源码版安装与使用指南:Delphi/Lazarus富文本编辑器实战

2026/10/2 3:15:41 拓冰建站 浏览量
TRichView 23.1全源码版安装与使用指南:Delphi/Lazarus富文本编辑器实战 简介TRichView 23.1 完整源码版覆盖 Delphi XE7 至 D12 与 Lazarus FS 环境面向 Delphi/CBuilder 开发者旨在解决富文本编辑器组件在文档创建、查看、打印及跨平台集成方面的实际需求。压缩包共 2000 个文件主体为 1612 个 cpp 工程源文件和 349 个 h 头文件另有 36 个 txt 使用说明、2 个 pdf 官方文档和 1 个 htm 帮助索引包体整体大小 27.55MB按工程目录组织便于直接导入开发环境编译调用。当前已有 152 人学习下载。该版本在 TRichView 23 基础上集成了完整的格式化能力如字体与段落样式、列表和表格嵌套、图片/OLE 对象精确控制同时支持 HTML 双向导入导出、数据库邮件合并和脚本自动化接口还提供加密存储与模块化可扩展架构。读者借此可获得可编译的完整组件源码用于在 Windows、Linux、macOS 上快速构建文档编辑器或嵌入富文本展示功能显著缩短组件选型与底层排版开发周期。1. TRichView-23.1-XE7-D12 Lazarus FS为什么全源码版本值得装进你的 Delphi 工具箱TRichView 是 Delphi 生态里老牌的富文本编辑控件23.1 这个版本号的含义是它同时覆盖从 Delphi XE7 到 Delphi 12 的所有主流分支还单独维护了一套 Lazarus/FPC 分支压缩包后缀的 FS 代表 Full Source——你拿到的是全部源码而不是只有编译好的 DCU 二进制。对还守着老工程、又不得不同时面对新编译器和 Lazarus 跨平台编译的团队来说这一套能省掉自己攒富文本控件的绝大部分成本。适合三类人正在给 Delphi 老项目升级编辑器、想在 Lazarus 下做跨平台文本编辑、以及需要把 RTF、RVF、HTML 文档互通的人。全源码的意义很直接报错能看实现、行为能按需改、跨版本迁移不用等官方补丁。2. 从压缩包到 IDE 面板Delphi 与 Lazarus 两套分支的安装顺序2.1 压缩包里的两套源码Delphi 分支与 Lazarus 分支谁管什么拿到手先别急着双击 dpkTRichView 23.1 这套全源码包的顶层一般就是 Source、Demos、Docs 这几类目录真正决定你能不能装上的是 Source 里按编译器拆的分支。常见布局是Delphi_Common 放跨版本共享的核心单元Delphi_XE7、Delphi_XE8 一直到 Delphi_12 各放一份带 .dpk 和 .dproj 的分支Lazarus 目录下则是 .lpk 包文件和同一批 .pas 核心单元。之所以拆这么细是因为 RTL 接口和 IDE 注册代码在不同版本之间差异不小而 Lazarus/FPC 分支要把控件外壳换成 LCL 实现——滚动条、剪贴板、输入法消息这些在 Delphi 分支里用 VCL 实现的部分Lazarus 下全要走 LCL。所以别幻想拿 Delphi 分支的 DCU 给 Lazarus 用二进制不互通两边得各自编译。FS 后缀最值钱的地方是报错时你能直接打开 .pas 看实现。商用组件不给源码的时代编译报错只能靠玄学猜全源码包则可以断点进 AddHyperlink 内部看它到底改了什么 item。我拿到包的第一步永远是先看 Docs 里的版本说明和 History确认 23.1 对 D12 的 Unicode 支持和 Lazarus 分支的 FPC 最低版本要求这两个信息直接决定我要不要升级而不是闷头装完再说。Delphi 与 Lazarus 两套分支的差异可以先看这张表再动手| 分支 | 包/工程后缀 | 产物 | 适用 IDE 与编译器 | | Delphi | .dpk / .dproj | .dcu / .bpl | RAD Studio XE7 到 12VCL 框架 | | Lazarus | .lpk | .ppu / .o / .a | Lazarus 2.x FPC 3.2.xLCL 框架 |要注意 .ppu 与 FPC 版本强绑定同一份 .pas 用 FPC 3.2.2 编出来的 .ppu换到 3.0 就会报接口不一致。所以 Lazarus 分支的编译产物目录最好按 FPC 版本再拆一层我习惯建 Laz32_FPC322 这种目录名避免升级 FPC 后踩到“明明重新编译了却还是旧接口”的暗坑。2.2 Delphi 12 里安装 TRichView四个步骤和 msbuild 命令行Delphi 分支的安装套路很固定按四个步骤走基本不会翻车。第一步解压到不含空格和中文的路径比如 D:\DevLibs\TRichView-23.1TRichView 的工程文件对路径里的空格很敏感放 C:\Program Files 下是给自己找麻烦。第二步在 IDE 的 Tools Options Environment Delphi Options Library 里把 Source\Delphi_Common 和 Source\Delphi_12 两个目录加进 Library path。这个路径管的是“引用单元时去哪找 .pas 和 .dcu”不加进去后面打开任何工程都会报 Unit RichView not found。第三步是编译顺序问题。打开 RichView.dproj 后先在 Project Options Delphi Compiler 里把 Output directory 指到一个独立目录比如 Lib\D12\Win32再按 Build。默认输出目录通常是工程自己的子目录会把 DCU 散得到处都是以后清理都找不到地方。第四步Build 通过后点 InstallIDE 提示重启重启后组件面板里就会出现 RichView 页拖 TRichViewEdit 到窗体上就算装完。想走命令行也可以方便做 CI 或批量编译msbuild RichView.dproj /t:Build /p:ConfigDebug /p:PlatformWin32 /p:OutputDirD:\DevLibs\TRichView-23.1\Lib\D12\Win32这里 /p:OutputDir 的写法在不同版本的 dproj 里属性名可能略有差异我一般直接在 IDE 里设好再拿 msbuild 复用同一份配置。/p:Platform 先只做 Win32编译通过后再补 Win64因为 64 位下部分 Delphi 老代码会碰到指针尺寸相关的警告先把 32 位跑通能少一半干扰项。装完别急着写业务代码先在空工程里拖一个 TRichViewEdit 出来编译运行确认 DCU 路径没有问题再往老项目里引。2.3 Lazarus/FPC 分支安装lazbuild 一条命令与依赖顺序Lazarus 分支比 Delphi 分支多一个变量FPC 编译器版本和 widgetset 类型。常见做法是用 lazbuild 命令行一次性完成编译和注册比在 IDE 里点来点去更可控lazbuild /path/TRichView-23.1/Lazarus/richview_package.lpk --build-all lazbuild --add-package /path/TRichView-23.1/Lazarus/richview_package.lpk第一条命令的 --build-all 会把 lpk 声明的所有依赖包一起编译第二条把包注册进 IDE。如果只是单个项目要用而不想污染 IDE可以在 Project Project Inspector Add New Requirement 里直接引用 .lpk 文件编译项目时自动带上。我第一次在 Lazarus 2.2 FPC 3.2.2 下装 23.1 分支时直接双击 lpk 编译报 Cant find unit LResources原因就是依赖的 LCL 包没有先构建用 --build-all 之后一次通过这是最典型的依赖顺序问题。Lazarus 生态里同时装多个第三方包时顺序和重名问题比 Delphi 更突出。如果你的 IDE 里还装了 unidac、bgrabitmap 这类包建议先把这些基础包装好、确认能编译再装 TRichView。原因很简单Lazarus 的包搜索路径是全局的两个 lpk 如果都声明了同名的 unit编译器按路径搜索顺序取第一个找到的结果就是“明明装好了却编译不过”查起来非常耗时间。3. 建一个能打字的最小编辑器RichViewEdit 属性、三格式存取与插入 API3.1 最小 FormRichViewEdit 三条必设属性与可运行代码把 TRichViewEdit 拖到 Form 上只是开始真正让它可用需要设置三条属性。第一条是 Style必须指向一个 TRVStyle 实例这决定了文档里所有文本样式索引怎么解析。第二条是 ReadOnly编辑状态必须设为 False否则插光标、接收键盘输入这些行为全被禁掉。第三条是 UndoLimit撤销栈深度设 0 表示不记录撤销历史。这里给出 FormCreate 里最小可运行代码procedure TForm1.FormCreate(Sender: TObject); begin RVEdit : TRichViewEdit.Create(Self); RVEdit.Parent : Self; RVEdit.Align : alClient; // 1. Style 必须最先设置否则后续 Clear 时没有默认样式可用 RVEdit.Style : RVStyle1; // 2. ReadOnly 控制光标与输入 RVEdit.ReadOnly : False; // 3. UndoLimit 控制撤销栈深度50 是编辑器的合理值 RVEdit.UndoLimit : 50; RVEdit.OnChange : rveChange; // 建立默认文档与默认段落 RVEdit.Clear; RVEdit.Text : ; end;这里有个顺序问题Style 必须在 Clear 之前赋值否则 TRichViewEdit 创建文档时不知道该用哪套样式表会出现运行期“默认样式索引越界”之类的黑匣子错误。UndoLimit 不是越大越好每次文本变更 TRichView 都会向撤销栈压入一份文档快照500 步撤销意味着几百份快照常驻内存大文档下这是实打实的内存开销。OnChange 在每次文档变更后触发注意这个事件频率极高回调里只放状态栏字数统计这类轻量逻辑。3.2 文档存取RVF、RTF、HTML 三种格式的边界与参数TRichView 支持多套文档格式最容易踩的坑是把它们混用。我的分法是程序内部存档永远用 RVF跟 Word 交换用 RTF做网页预览用 HTML。RVF 是 TRichView 的原生格式只有它才能完整保留表格合并、书签、图片项这类内部对象读写速度最快RTF 在样式名映射上有坑见第 5 章HTML 导出图片默认走外部文件适合预览不适合当存档。三者取舍看这张表| 格式 | 读写方法 | 典型用途 | 必调参数 | | RVF | SaveRVF / LoadRVF | 草稿、自动存档、增量保存 | 第二参数控制压缩开关 | | RTF | SaveRTF / LoadRTF | 与 Word、WPS 交换 | RTFWriteProperties 样式导出开关 | | HTML | SaveHTML / LoadHTML | 网页预览、发布 | 图片导出目录与相对路径 |实际调用代码如下// 存草稿永远用 RVF无损且快False 表示不压缩方便调试 RVEdit.SaveRVF(ExtractFilePath(ParamStr(0)) draft.rvf, False); // 导出给 Word 的版本走 RTF注意样式名前缀 RVEdit.SaveRTF(export.rtf); // HTML 导出图片默认写相对路径先统一文档存储目录 RVEdit.SaveHTML(preview.html, , , );SaveRVF 的第二个参数是压缩开关我调试阶段都传 False因为压缩后的流没法直接用文本工具看内容正式草稿存档传 True能省不少磁盘占用。LoadRTF 内部会自动处理 RTF 的 \uN 转义不用你管文件编码但前提是 RTFReadProperties 里的默认字体名必须指向一个本机存在的字体否则遇到未声明字体的段落会回退到该默认值表现就是“打开别人的 RTF 字体全变了”。3.3 插入文字、图片、超链接和表格常用 API 与 3 个参数坑编辑器的核心操作是插入TRichView 把这几个能力都集中在 TRichViewEdit 上调用方式不复杂但参数埋着几个坑// 插入文字第 3 个参数是 TextStyleNo0 号通常是默认正文 RVEdit.InsertText(这是一级标题, clWindowText, 1); // 插入图片Name 是图片项的唯一标识后续可用来定位 if Assigned(Image1.Picture.Graphic) then RVEdit.InsertPicture(logo, Image1.Picture); // 插入超链接文字样式用带下划线的那一号 RVEdit.AddHyperlink(打开官网, https://www.trichview.com, 2); // 插入表格先建空表再往单元格填内容 RVEdit.InsertTable(2, 3, clBlack, clNone, clNone, []);第一个坑是 InsertPicture 传的是 TPicture 实例如果你直接加载一张 3000 宽的截图塞进去文档会带着超大图片项一起滚动内存和重绘都会卡到怀疑人生。常见做法是在插入前按 MaxTextWidth 等比缩放缩到编辑器宽度再插。第二个坑是 AddHyperlink 的 TextStyleNo 必须指向一个带下划线和蓝色属性的样式否则超链接看起来跟普通文本一样用户不知道可以点。第三个坑是 InsertTable 的参数签名在不同小版本之间有过微调六个参数里前两个是行列数后面是边框色、单元格底色和一个集合选项我一般以 23.1 源码里的 InsertTable 声明为准必要时直接读 .pas 确认这也是全源码包的好处。表格插入后要逐格填内容需要从 RVEdit.RVData 里遍历 TableItem再操作每个 Cell 的 Text 属性这块建议单独封装别在主流程里裸写。4. 样式、水印与刷新策略用 TRVStyle 和 BGRABitmap 把编辑器界面做像样4.1 TRVStyle 的 TextStyles先建样式号再写内容TRVStyle 是 TRichView 的样式中枢TextStyles 是一个按序号索引的样式集合所有文本插入都靠这个序号引用样式。如果你把样式定义写成“每条文本都带上字体名和字号”那完全违背了 TRichView 的设计——它希望你统一在样式表里定义文档里只存样式号。这样改全局字体时只改样式表存量文档跟着变不用遍历内容。下面是给现有项目补样式的最小代码var Idx: Integer; begin // 0 号预留给正文先设置好再添加其它样式 with RVStyle1.TextStyles[0] do begin FontName : Microsoft YaHei; Size : 10.5; Color : clWindowText; end; // Add 返回新样式的索引之后 InsertText 直接用它 Idx : RVStyle1.TextStyles.Add; with RVStyle1.TextStyles[Idx] do begin StyleName : RV_H1; FontName : Microsoft YaHei; Size : 18; Style : [fsBold]; Color : clNavy; end; end;注意 StyleName 的命名我特意用了 RV_ 前缀这个前缀是给 RTF 导出用的详见第 5 章样式名冲突那条。加载 RTF 时TRichView 会把文档里的样式名跟 StyleName 做匹配匹配不上的段落自动落到 0 号正文样式。所以一个干净的项目里0 号正文永远要有否则打开外部 RTF 时整篇文档的默认样式是空的文字会以系统默认字体显示观感很差。ListStyles 也类似处理项目符号和编号时别在每条段落里手工拼 “1.” 这种字符用列表样式才能在缩进和换行续号上跟 Word 对齐。4.2 用 OnCustomDrawBackground BGRABitmap 画渐变水印背景默认的 TRichView 背景是纯色产品上要加“草稿”“内部文件”这类水印时需要自己接管背景绘制。TRichView 提供背景绘制事件可以在每次重绘背景时插入自定义逻辑。Lazarus 分支下我习惯配合 BGRABitmap 做因为它支持半透明和渐变效果比纯 LCL Canvas 好一个档次procedure TForm1.rveCustomDrawBackground(Sender: TObject; ACanvas: TCanvas; ARect: TRect; var Done: Boolean); var bmp: TBGRABitmap; begin bmp : TBGRABitmap.Create(ARect.Width, ARect.Height); try // 画一个浅色渐变打底 bmp.Fill(ARect.Height, BGRA(245, 247, 250), BGRA(220, 230, 240), bdmVertical); // 半透明水印文字alpha 60 保证底下内容仍可读 bmp.FontHeight : 48; bmp.TextOut(ARect.Width div 2, ARect.Height div 2, DRAFT, BGRA(0, 0, 0, 60), taCenter); bmp.Draw(ACanvas, ARect.Left, ARect.Top); finally bmp.Free; end; end;要点是把 Done 置为 True告诉 TRichView “背景我已经画完了你跳过默认绘制”。如果不置 True默认背景还会再刷一遍出现闪屏和颜色覆盖。在 Delphi 分支下其实不需要 BGRABitmap直接用 ACanvas.GradientFill 或画位图都行但 Lazarus 分支的 LCL Canvas 没有 GradientFill所以这个场景里 BGRABitmap 几乎是必需品。水印文字的位置可以跟 TRichView 的滚动位置联动让水印固定在可视区中央而不是跟着文档滚做法是在事件里取当前可视区偏移并修正 TextOut 坐标这块按产品需求细调即可。4.3 与 unidac、多线程场景的刷新约定TRichView 不是线程安全TRichView 和绝大多数 GUI 组件一样不是线程安全的。这句话在项目里经常被忽略直到出现随机崩溃才开始查。常见场景是用 unidac 在后台线程里查数据库拿到 RTF 字段的 Blob 后直接在线程里调用 LoadRVF——这是典型的翻车写法。正确的约定是数据库查询可以放后台线程但 LoadRVF、InsertText、SaveRTF 这些文档操作必须在主线程执行跨线程调用要用 Synchronize 或 Queue 转回去。procedure TLoadThread.Execute; var S: TMemoryStream; begin S : TMemoryStream.Create; try // 在线程里只做 IO把 Blob 读进内存 QueryStreamTo(S); S.Position : 0; TThread.Queue(nil, procedure begin // 回主线程再改文档这行是安全的 Form1.RVEdit.LoadRVF(S); S.Free; end); except S.Free; raise; end; end;另一个刷新约定是批量操作期间的界面节流。连续 InsertText 几十段时如果每插一段都触发 OnChange 做一次字数统计和状态栏刷新界面会肉眼可见地掉帧。常见做法是先临时把 UndoLimit 置 0批量插入完成后再恢复这样撤销栈不会随着每次插入膨胀OnChange 的次数也少得多。这套约定在存量代码里统一落实后大文档卡顿的问题能消掉大半。5. 避坑与排查23.1 跨版本安装和运行期最常踩的 5 个问题5.1 安装后面板找不到控件编译报 Unit RichView not found现象dpk 装完IDE 提示成功但新工程里控件面板看不到 TRichView手动写 uses RichView 编译直接报 Unit RichView not found。原因Library path 没有覆盖到源码目录或者只加了版本分支目录、漏了 Delphi_Common。IDE 面板找不到控件也是同一根因编译环境根本没把单元纳入搜索范围。解决在 Tools Options Environment Delphi Options Library 里确认两个路径都存在Delphi_Common 和对应版本分支一个都不能少顺序上把 TRichView 的路径放在其它组件库前面。改完先重启 IDE 再看面板路径生效在部分版本里需要重启才能刷新。5.2 Delphi 12 编译报 “Unit RichView was compiled with a different version of System.Types”现象新工程引用 TRichView 后编译报错提示某系统单元版本不一致或者出现一堆 E2201 类型的类型描述不匹配。原因这是典型的残留 DCU 问题。你之前用旧版 Delphi 编译过 TRichViewLib 目录里的 .dcu 是旧编译器产物D12 编译时拿到旧 DCU 觉得接口不匹配。升级 Delphi 最怕的就是这类黑匣子错误它跟业务代码无关。解决把 Lib 目录整个删掉重建在 D12 里重新 Build 一遍确保本次编译产物全部来自当前编译器。如果 IDE 还开了第三方缓存工具一并清理。命令行可以做彻底清理msbuild RichView.dproj /t:Clean /t:Build /p:ConfigDebug /p:PlatformWin32这条命令先执行 Clean 再 Build比在 IDE 里手工删文件更可靠。注意 Win32 和 Win64 的 DCU 不能混放输出目录应该按平台分开。5.3 Lazarus 编译报 Cant find unit LResources 或单元重名现象在 Lazarus 里编译工程时找不到 LResources或者报 “unit RichView is already used by another package”两个包互相干扰。原因第一类是 lpk 的依赖包没有先构建LResources 属于 LCL 的写件包没有按依赖顺序编译就会出现。第二类是系统组件目录里本来就有一份旧版 TRichView 或其同名单元编译器按搜索路径先找到了旧的那份。解决用 lazbuild --build-all 把依赖一次性构建完。单元重名问题则要检查 Tools Options Files 里的包搜索路径把多余的旧副本从路径里移除只保留 23.1 的 Lazarus 目录。我在机器上就遇到过 components\trichview 旧目录没删掉导致新包永远编译不过删掉旧目录后问题消失属于典型的“路径优先级玄学”。5.4 存出的 RTF 在 Word 里字体缩进全乱现象程序里 SaveRTF 出来的文件用 Word 打开标题字体不对、段距消失、编号乱了但在 TRichView 里看是正常的。原因TRichView 导出 RTF 时会把 StyleName 写进文档而 Word 有内置样式名表像 “Heading 1”“Normal” 这类名字会被 Word 强制映射到它自己的内置样式映射后字体、颜色、缩进全被 Word 的模板覆盖。解决把 TRVStyle 里的 StyleName 全部加上项目前缀比如 RV_Normal、RV_H1避开 Word 内置名字。同时在 RTFWriteProperties 里检查和样式导出相关的开关确认不会写出会让 Word 做样式重映射的标记。如果导出 PDF 也出现编号错乱那就不是样式问题而是 Word 域代码不兼容要用 ScaleRichView 走打印驱动导出这是一条不同的路别在 RTF 上死磕。5.5 LoadRVF(Stream) 空白或 EStreamError现象用 TMemoryStream 加载从数据库读出来的 RVFLoadRVF 不报错但编辑器是空的或者直接抛 EStreamError。原因两个常见诱因。一是 Stream.Position 不在 0读出来的流如果先被其它代码消费过位置已经在末尾LoadRVF 读到空内容自然没反应。二是文件内容根本不是 RVF可能只是扩展名改了RVF 文件头有版本标记和校验信息不匹配就抛异常。解决加载前强制 Position : 0并做一次文件头判断S.Position : 0; if S.Size 8 then raise Exception.Create(流为空或不是 RVF 文件); // RVF 文件头带版本标记这里只做长度粗校验 S.Position : 0; RVEdit.LoadRVF(S);如果条件允许调试阶段优先用 LoadRVF(FileName) 直接传路径让组件自己处理文件流能少踩一半这类坑。等确认逻辑没问题再换成流式加载对接数据库。6. 进阶用法后台线程加载大图顺带做 RVF 自动存档后悔药6.1 图片后加载线程 OnChange 防抖自动存档编辑器工程做到后期最影响体验的不是打字而是打开一个带几十张大图的文档时界面白屏。TRichView 的所有文档操作必须在主线程但图片文件的磁盘读取和解码可以挪到后台。我一般写一个极简的图片加载线程线程里只做 LoadFromFile插进文档的动作通过 Synchronize 交还主线程type TImageLoader class(TThread) private FPath: string; FPic: TPicture; protected procedure Execute; override; procedure DoInsert; end; procedure TImageLoader.Execute; begin FPic : TPicture.Create; FPic.LoadFromFile(FPath); // 磁盘 IO 在线程里完成 Synchronize(DoInsert); end; procedure TImageLoader.DoInsert; begin try Form1.RVEdit.InsertPicture(ExtractFileName(FPath), FPic); finally FPic.Free; end; end;这样做的好处是打开文档时主线程先显示文字图片逐个到位用户不用盯着空白界面等。配合 OnChange 防抖定时器做 RVF 自动存档每次 OnChange 重置一个 3 秒的 TTimer到点就把当前文档 SaveRVF 到临时目录。TRichView 的 RVF 写入很快几十 KB 的草稿存档也就是几毫秒的事完全不影响输入流畅度。这套组合我沿用到现在已经成为我做编辑器类工程的默认骨架图片后加载解决卡顿自动存档解决断电和误操作。希望帮到你。本文还有配套的精品资源点击获取