
简介HTML Component Library v4.6 是一套针对 Delphi 平台的 HTML 渲染控件主要解决 VCL 与 FMX 程序中嵌入网页、解析 HTML/CSS、处理表单交互等问题支持从 Delphi 5 到 Delphi 11 Alexandria 的多个版本适合中高级桌面应用开发者选用。包内共 2000 个文件压缩后 163.33MB包含 564 个 dcu 编译单元、500 个 hpp 头文件、190 个 obj 文件等核心构建产物同时带有 dfm 窗体、fmx/lfm 跨平台界面文件以及 dpk/dproj 工程和 bpl/dcp 运行时包便于按目标 IDE 快速安装部署。另外还提供 chm、pdf 文档与示例工程方便查阅接口和上手测试。已有 54 人学习/下载。同时附带授权补丁与 pas 源文件既能直接集成到开发环境也可基于源码对组件行为进行定制有助于缩短 HTML 相关功能的开发周期。1. Delphi 12.3 上使用 HTML Component Library v4.6先想清楚它到底解决什么在 Delphi 12.3 的 IDE 里HTML Component Library v4.6 是一套老牌第三方控件提供 THtmlViewer、TFrameViewer 等可直接拖放的 HTML 渲染组件同时覆盖 VCL 和 FMX版本跨度从 D5 一直到 D11 Alexandria。很多做 ERP、进销存、报表系统的工程师看到“HTML 控件”第一反应是挂一个 WebBrowser 或 EdgeBrowser但 HCL 的做法完全不同它用自己的解析器和排版引擎画 HTML不依赖操作系统里的浏览器进程因此安装体积小、启动快也几乎没有浏览器版本“昨天能跑今天不能跑”的问题。对正在学习 Delphi 的开发者以及用 Community Edition 做免费桌面工具的团队来说这套控件比 CEF 更容易上手比 WebBrowser 更容易控制渲染结果。本文只讨论 v4.6 的安装、VCL/FMX 接入、参数调优、常见坑和 HTTP 链接拦截技巧标题里出现的 CRACK 文件不属于开发技术内容请从正式授权渠道获取组件安装包后面每个步骤都只针对正规安装包。2. HTML Component Library v4.6 的架构与选型为什么它比 Edge/WebView2 更可控HCL v4.6 最容易被误判的一点是“它到底是不是一个浏览器”。它既不是 Chrome 也不是 IE 的封装而是一个用 Delphi 对象写出来的 HTML 渲染引擎。理解这一点才能解释为什么有的人在老电脑上飞一样运行有的人一接图片多的页面就卡也才能决定你的项目里哪些页面适合交给它。2.1 自绘内核与浏览器内核的差异HCL 在 VCL 版本里通过 GDI 绘制 HTML 元素在 FMX 版本里则走 TCanvas 绘图栈。它保存的是一棵元素节点树然后自己决定字体、边框、段落和表格怎么排。这意味着它不启动子进程、不占用 GPU、不要求系统安装 WebView2 Runtime也没有 ActiveX 注册表残留。代价是它对 JavaScript 的支持很弱对 CSS3 布局也只能覆盖一部分。拿它渲染完整版的单页后台系统会吃力拿它渲染订单、发票、邮件模板、帮助文档则非常合适。下面这张表是我通常会拿给项目组做选型对比的。对比项HCL v4.6WebView2CEF内核来源Delphi 自写Edge ChromiumChromium进程模型单进程多进程多进程安装依赖无需要 Runtime需要大量 DLLVCL/FMX 原生支持两者都有需要第三方封装需要第三方封装HTML5/CSS3可用但有限完整完整内存占用较低较高最高离线场景优秀依赖缓存依赖缓存选型时我给的最实用建议是如果页面固定为项目里自己生成的 HTML且不需要现代前端框架HCL 是成本最低的方案如果页面可能是外部页面、会频繁升级甚至要用 React 或 Vue那就别在 HCL 上浪费力气直接上 WebView2 或 CEF。怕就怕抱着“HCL 能渲染 HTML 就等于能替代浏览器”的预期最终做到一半发现撑不住。2.2 VCL 与 FMX 两套分支的设计差异v4.6 对 VCL 和 FMX 分别维护了单元包而不是用同一套代码硬兼容。VCL 分支依赖 WinAPI 的句柄和消息传递所以在 Windows 下控件交互跟原生控件一样自然FMX 分支则必须用 FMX 的跨平台 TCanvas 去画 Text、Rect 和图片因此在 Linux、macOS 甚至 Android 上也可以显示 HTML 页面只是字体获取方式和输入法行为不同。这就带来一个常见的工程结论老项目升级、保留 Windows 特有能力时优先 VCL如果是新项目并且明确有多端交付要求FMX 分支才是正确选择。两者的公开 API 高度接近但不要在 DFM 里直接混拖 VCL 和 FMX 版本的组件一个窗体只能使用同一套 UI 框架。2.3 为什么 D5 到 D11 Alexandria 都要兼容v4.6 能在这么长的 Delphi 版本区间里通用核心原因是包内做了大量条件编译。它不是分别维护六七个源码副本而是在同一个源文件里用编译器版本指令切分差异代码。老项目从 Delphi 7 升到 Delphi 12.3最常见的工作量不在 HCL而在你自己的字符串类型和 Windows API 调用。HCL 提供的公共组件通常只依赖很少的底层单元所以升级时可以直接重用旧代码里的LoadFromString、OnHotSpotClick这些逻辑。这里也留一个给 Delphi 入门者看的代码片段在单元头部按编译器版本做初始化可以避免在旧版本上误用新语法。unit HtmlInit; interface procedure InitHCLEnvironment; implementation procedure InitHCLEnvironment; begin {$IF CompilerVersion 35.0} // Delphi 11 Alexandria 以上才需要执行的额外初始化 {$IFEND} end; end.这段代码里CompilerVersion是编译器内置的浮点常量35.0 大致对应 Delphi 11 Alexandria。v4.6 源码里遍布类似的$IF分支说明它的设计目标就是让同一份用户代码尽量不经修改跨版本编译。我一般在升级前会先确认项目里有没有直接引用 HCL 私有单元比如从HtmlView内部翻出一些没公开的变量只要公共 API 用法规范D5 时代的代码放到 Delphi 12.3 里仍然能编译通过。3. 在 Delphi 12.3 中安装并注册 HCL v4.6 组件包安装 HCL v4.6 的流程和装普通第三方控件包基本一致但因为它是老式组件库目录里可能同时有 D5、D7、XE、D10、D11 多套包文件不少人就是栽在“打开一个 .dpk 就编译结果报版本不匹配”。所以要先看包内目录再按 Delphi 12.3 对应的包文件走。3.1 先确认包内目录结构一个规范发布的 v4.6 包通常包含 source、packages、bin 三类内容。拿到压缩包后不要先着急双击安装先看目录结构。目录/文件作用Source/VCLVCL 版控件源码加入 Library Path 后编译期才能找到单元Source/FMXFMX 版控件源码Packages/D5-D11各版本.dpk/.bpl工程文件Bin预编译的 DCU 或包输出Demo示例工程安装后对照使用如果只有源码而没有现成的编译好的包需要自己在当前 IDE 环境中编译一次。如果包里带有为 Delphi 12.3 单独准备的包文件直接打开安装。3.2 设置 Library Path 并编译安装在 Delphi 12.3 中先打开Tools Options Environment Options Delphi Options Library - Win32把Source\VCL和Source\FMX加入 Library Path。这一步不能跳过因为.dpk编译时只会按项目搜索路径找HtmlViewer、Htmlsbs这些基础单元。接下来在主菜单选择Component Install Packages或者直接打开 Packages 目录下的.dpk文件。一个典型操作顺序是在 Project Manager 里找到对应 Delphi 12.3 的 VCL 包例如D12_HCL_VCL.dpk右键选择Compile编译成功后右键选择Install看到 “Package ... installed” 提示组件会自动出现在 Tool Palette用同样的方法编译并安装 FMX 包如果不是源码安装而是已经给您提供了.bpl文件则在Install Packages对话框中点击Add选择 VCL 和 FMX 两个.bpl即可。安装完成后在工具面板搜索FrameViewer能出现对应图标就算成功。3.3 用一个最小代码验证安装环境安装未必等于编译环境可用。Library Path 漏配是新手最常见的坑表现为打开示例工程时提示找不到HtmlViewer单元。这里给一个独立的验证函数放在一个空单元里只测试单元的编译期查找是否正常。uses HtmlViewer; function HCLCanCreate: string; var V: TFrameViewer; begin V : TFrameViewer.Create(nil); try Result : OK: V.ClassName; finally V.Free; end; end;这个函数能编译通过说明 Delphi 12.3 的 Library Path 已经正确指向 HCL 源码调用它并返回OK: TFrameViewer则说明运行时也会创建组件对象。要注意的是TFrameViewer.Create(nil)不会自动设置 Parent也不会显示界面因此在这个验证函数里不需要窗口句柄。万一编译失败优先检查Source\VCL是否被加入当前平台为 Win32 的路径里而不是 Win64 或其他平台。4. 在 VCL 与 FMX 中嵌入 HTML 的实战配置安装成功之后最理想的用法不是把 HTML 塞进 TWebBrowser而是直接把TFrameViewer或THtmlViewer当作普通控件放到窗体上。下面从 VCL 和 FMX 两个最小工程讲起。4.1 VCL 最小示例LoadFromString 显示报表在 VCL 窗体上放一个 TFrameViewerIDE 拖拽后默认名是 FrameViewer1再放一个 TButton。按钮事件里写procedure TForm1.ButtonLoadClick(Sender: TObject); begin FrameViewer1.Align : alClient; FrameViewer1.DefFontName : Microsoft YaHei; FrameViewer1.DefFontSize : 10; FrameViewer1.LoadFromString( html headmeta charsetutf-8/head body h2Delphi 12.3 HCL v4.6/h2 p报表正文区域/p /body /html); end;LoadFromString的参数是 Delphi Unicode 字符串HCL 会直接解析内存中的 HTML不会发起网络请求。DefFontName和DefFontSize决定了 HTML 里没有显式写字体样式的那些文字怎么显示。Windows 环境下把默认字体设置为 Microsoft YaHei中文显示效果会比较稳定如果完全不设置组件通常沿用 Windows 的系统 UI 字体字号偏旧。这里有一个实战中容易踩的误区不要在运行时反复设置FrameViewer1.Align。如果窗体设计时就已经设置了 Align运行时再改意义不大而且可能触发布局刷新。上面这个写法只是为了在完全手写代码的工程里也能跑起来。4.2 FMX 最小示例跨平台输出 Hello HTMLFMX 版本的组件在 Delphi 12.3 中安装后会出现在 FMX 组件页里。假设在 Form 上拖拽后 IDE 生成的控件名是HtmlViewer1按钮事件可以这样写procedure TForm2.Button1Click(Sender: TObject); begin HtmlViewer1.LoadFromString( html body h2FMX Hello/h2 pHTML Component Library v4.6 在 FMX 下同样可用。/p /body /html); end;FMX 版不依赖 Windows GDI因此在 macOS 或 Android 上也能绘制出 HTML 页面。但要注意移动端的默认字体列表和 PC 完全不同。如果在 Android 上显示中文出现方块不要急着怀疑 HCL先检查 Delphi 工程是否启用了自定义字体或者是否在 FMX 表单的OnCreate里设置了FontManager的字体路径。常见的做法是给 DefFontName 传入平台自带的中文字体名VCL 用微软雅黑macOS 用 PingFang SCAndroid 用 Droid Sans Fallback 或 sans-serif。4.3 常用属性、方法和事件速查初用 HCL 时掌握几个高频入口就够了。下面的表是基于我实际使用 v4.6 VCL 分支的经验整理出来的FMX 分支的命名基本一致但个别属性可能由 IDE 自动生成。成员类型作用与建议DefFontName属性设置默认字体例如 Microsoft YaHeiDefFontSize属性默认字号建议 9 到 12MarginWidth属性页面左右边距单位像素MarginHeight属性页面上下边距LoadFromString方法从字符串加载 HTML适合报表模板LoadFromFile方法从文件加载 HTML适合离线文档OnHotSpotClick事件链接被点击时触发可拦截并自行处理OnLinkClick事件某些版本中由 OnHotSpotClick 转发用于外部浏览器LoadFromFile加载本地 HTML 文件时路径分隔符建议用绝对路径或相对于ExtractFilePath(Application.ExeName)的路径避免把相对路径写死在当前目录里。遇到外链时HCL 默认可能会打开系统默认浏览器如果希望链接永远不跳转只需要在事件处理函数里把Handled设为 True。这个机制是后面做自定义协议桥接的基础。5. 中文乱码、EdgeBrowser 无反应与性能排错任何 HTML 渲染组件都绕不开字符集问题HCL v4.6 尤其明显。它不是一个现代浏览器不会自动嗅探编码也不会因为你在 HTML 里写了meta charsetutf-8就一定不出乱码。乱码的根源通常是 Delphi 字符串和 HTML 字节流之间的编码转换没有做对。5.1 中文乱码不只是 HTML 声明问题我见过很多 Delphi 新人把 UTF-8 的 HTML 文件直接交给LoadFromFile然后在头部写了 charset结果中文还是乱码。原因是 Delphi 在读取文件时默认按本地代码页Windows 中文系统为 GBK解析字节流如果文件本身是 UTF-8 无 BOMpremature 转码就会出错。正确做法是先按 UTF-8 解码字节再交给组件。uses System.SysUtils, System.NetEncoding; function LoadUtf8Html(const FileName: string): string; var Bytes: TBytes; begin Bytes : TFile.ReadAllBytes(FileName); Result : TEncoding.UTF8.GetString(Bytes); end; // 调用 FrameViewer1.LoadFromString(LoadUtf8Html(report.html));逻辑说明TFile.ReadAllBytes读到的是原始字节TEncoding.UTF8.GetString明确按 UTF-8 解码成 Unicode 字符串。这个做法比让 HCL 自己读文件可靠因为不依赖组件的内部编码判断。如果是数据库字段比如从 SQLite 里读出来的中文备注也是一样的原理先拿到字段对应的 AnsiBytes 或 Blob再统一转成 UTF8 字符串后拼接 HTML。很多人碰到的“Delphi SQLite 乱码”本质就是 CSV 或 Blob 里存的是 GBK而拼接进 HTML 后却按 UTF-8 解码。5.2 别用 EdgeBrowser.Navigate 来做静态报表有个词在最近的问题里出现频率很高“Delphi 运行 EdgeBrowser.Navigate 无反应”。这通常是 Edge WebView2 控件在窗口句柄尚未创建、或浏览器进程初始化失败时导致的。如果你只是在做报表打印和邮件模板完全可以不碰 EdgeBrowser。HCL 自绘引擎没有独立进程不存在“导航无反应”这种状态因为它根本不会导航。它只解析你给它的 HTML 字符串。如果给了完整 URL 必须联网HCL 的能力很弱这也不是它的设计目标。反过来如果确实要用 EdgeBrowser 展示在线页面排错顺序应该是先确认 WebView2 Runtime 已安装然后在FormCreate里调用EdgeBrowser1.CreateBrowser再在OnNavigationCompleted事件中调用Navigate不要直接在FormCreate里写一句Navigate(https://...)就完事。HCL 和 EdgeBrowser 的适用场景是互补的选择依据是页面里到底有没有不可缺失的 JavaScript。5.3 大表格与图片资源的性能控制HCL 为每个 HTML 元素保留对象节点一个大表格如果超过几千行内存会明显上涨。我能给的最直接建议是不要把整张数据库表直接铺到 HTML 里。分页、懒加载、HTTP 图片链接可以缓解但最有效的是拆分页面。比如把每一页报表限制在 500 行以内连续查看时先Free旧的 FrameViewer再创建新实例。以下代码适合在反复加载报表时用procedure TForm1.ReleaseViewer; begin FrameViewer1.Stop; // 停止当前解析 FrameViewer1.Clear; // 清空页内容 FrameViewer1.Free; FrameViewer1 : nil; end;Stop和Clear是 v4.6 常见生命周期方法前者在图片还没下载完时中止解析后者清空节点树。如果组件是在设计期拖上去的直接 Free 会在关闭窗体时造成二次释放所以这里要把FrameViewer1 : nil。比较稳妥的工程做法是运行时动态创建而不是设计期摆死。5.4 跨版本编译注意点虽然 v4.6 支持 D5 到 D11 Alexandria但你在 Delphi 12.3 里写代码时要小心新语法漏进老版本分支。比如Inline Var、泛型匿名函数只适合新版本。如果有需要交付给 D5 环境的包建议用$IF CompilerVersion把新语法隔开。另一个常见问题是字符串索引从 1 开始还是 0 开始这在老版和新版 Delphi 里行为不同处理 HTML 字符串时尽量用Copy、Pos这类跨版本统一函数。6. 用 hcl:// 自定义协议把 HTML 点击事件桥接到 Delphi 后端安装和基本渲染跑通之后一个很实用的能力是让 HTML 页面里的链接直接调用 Delphi 方法。最可靠、不依赖 JS 引擎的方式是拦截 OnHotSpotClick 事件识别hcl://协议头。理解起来像浏览器里的自定义 URI Scheme只是这里完全由 Delphi 自己处理。先构造一个 HTML 示例放在按钮点击事件里加载procedure TForm1.ButtonLoadClick(Sender: TObject); begin FrameViewer1.LoadFromString( htmlbody h3自定义协议测试/h3 a hrefhcl://export导出当前报表/abr a hrefhcl://close关闭窗口/a /body/html); end;然后在 FrameViewer1 的OnHotSpotClick事件里写procedure TForm1.FrameViewer1HotSpotClick(Sender: TObject; const SRC: string; var Handled: Boolean); var Action: string; begin if Pos(hcl://, LowerCase(SRC)) 1 then begin Handled : True; Action : LowerCase(Copy(SRC, 7, MaxInt)); if Action export then ExportReport else if Action close then Close; end; end;SRC参数是 HTML 中 href 的原始字符串。Handled : True表示这个链接已经被 Delphi 消费HCL 不会再尝试打开系统浏览器。Copy(SRC, 7, MaxInt)用来去掉hcl://这部分前缀留下export或close。这里强制转小写是为了避免用户在 HTML 里写HCL://EXPORT导致协议判断不一致。这个模式的进阶价值在于业务侧同事可以独立写 HTML 文档只需要按规定好的协议名称拼链接不需要接触 Delphi 代码。对风险控制也有一个直接好处白名单机制很简单只放行export、close这些固定动作未识别的协议一律Handled : False让外部浏览器接管。如果协议参数需要传值比如hcl://show?id100建议再做一层 URL 解码把amp;还原成再把参数交给专门的数据访问单元。这样前端模板和后端逻辑彻底分离是 HCL 在小团队里最实用的架构技巧。本文还有配套的精品资源点击获取