☰
EhLib无源码版安装实战:Delphi中DBGridEh实现排序合计与导出
2026/10/10 4:35:08 网站建设 项目流程

简介:这套Delphi控件资源面向使用Delphi 13.1的桌面应用开发者,核心是EhLib.VclFmx 13.0.015组件库,用于强化VCL/FMX环境下的数据感知、表格展示与数据库交互能力。压缩包共2000个文件,体积349.63MB,文件类型包括1915个hpp头文件、22个doc、18个docx、14个sql脚本、21个md及辅助txt/css等,doc/docx与md主要说明版本更新、俄英双语发布说明和安装指导,sql则补充了常见数据源的建表与查询脚本。已有66人浏览/学习。包内还包含Demos示例项目,便于参照学习各控件的应用场景;Hlp与doc文档为属性、方法和事件提供详细参考;styles目录提供界面样式资源,可快速统一应用外观;DataDrivers与DataService目录则包含多种数据源访问组件,帮助开发者减少排查数据集成问题的时间。资源整体不含源码,可直接集成使用,覆盖组件部署、界面定制与示例学习,适合希望快速构建稳定数据应用的Delphi项目团队。

1. 拿到EhLib.VclFmx.13.0.015这个包:先弄明白它解决了什么

标题里那一长串,拆开其实就三件事:EhLib 控件库、VCL 和 FMX 双框架支持、13.0.015 这个不带源码的发布版。会搜这个包的人,多半是被 Delphi 自带的 DBGrid 逼到了墙角——列排序要自己写标题栏点击事件,合计要自己拼 Footer,做 Excel 导出要整个 OLE 对象绕一大圈,而 DBGridEh 把这些全部塞进了属性面板,双击几下就能出效果。这包适合正在用 Delphi 13.1 做桌面或跨平台业务系统的团队,尤其是订单、财务、后台管理这类天天跟表格打交道的项目。无源码版本意味着你不用关心编译链,代价是调试时进不了控件内部,这一点在最后一章我会讲清楚怎么绕。

2. EhLib 组件体系速览:先分清 DBGridEh、DBComboBoxEh 和原生 DBGrid 的边界

2.1 EhLib 到底是一组什么组件:不止一个网络表格

EhLib 在 Delphi 生态里活了将近二十年,核心卖点不是“另一个网格控件”,而是围绕网格构建的一整套数据输入输出组件族。安装完你在 IDE 组件面板里能看到十几个以 Eh 结尾的组件:DBGridEh 是门面,负责展示、排序、合计、树形、冻结列;DBComboBoxEh 负责下拉选择,能在下拉里显示多列;DBDateTimeEditEh 处理日期时间输入,带日历下拉;DBLookupComboboxEh 处理主从表查找;DBEditEh、DBMemoEh 则是普通文本输入的增强版。这套组件能在一个工程里保持一致的视觉风格和交互逻辑,这才是很多人从原生控件迁过来的真正理由。

组件名框架支持典型场景我常用的关键属性
DBGridEhVCL / FMX单据列表、主从表明细Columns、FooterRowCount、OptionsEh
DBComboBoxEhVCL / FMX状态下拉、枚举值选择Items、DropDownBox.ListSource
DBLookupComboboxEhVCL / FMX外键字段选择ListSource、KeyField、ListField
DBDateTimeEditEhVCL日期区间查询Value、EditButton
DBEditEhVCL / FMX带校验的文本输入EditMask、AlwaysShowBorder
DBMemoEhVCL多行备注WantReturns、ScrollBars

2.2 为什么原生 DBGrid 不够用:排序与合计背后的重复劳动

原生 DBGrid 不是不能用,小项目里拖一个出来照样跑,但凡是业务表,用户一定会提三个需求:点列标题排序、看列合计、导 Excel。原生控件这三件事全得手写。排序你得在 OnTitleClick 里拼 SQL 的 ORDER BY,还要记住上次排序的字段和方向;合计你得在自定义画里逐列算 SUM 再画到 Footer 区域;导出最痛苦,老办法是 OLE 调用 Excel 逐格写入,数据量一大直接卡死界面。DBGridEh 把这些做成了开关:标题排序开 dghAutoSortMarking,合计设 Footer.ValueType := vtSum,导出调一句 SaveToXLS,整个工作量从半天缩到十分钟。

2.3 选型时机:VclFmx 包名里的双框架含义和 no source 的取舍

包名里的 VclFmx 表示这一个包同时覆盖 VCL 和 FMX 两套框架,不必像老版本那样分别找 EhLibVCL 和 EhLibFMX 两个压缩包。对需要从 Win32 桌面迁到跨平台的企业来说,这意味着同一套业务代码能编译出 Windows 原生版和 Android/iOS 版,代价是 FMX 版部分属性不生效,具体差异我在第六章会专门列。no source 这个后缀要重点看:它没有 .pas 源码,只有编译好的 .dcu 和 .bpl,好处是装完即用、不需要在 IDE 里重新编译整个控件库,坏处是调试时 F7 跟进去只有 CPU 窗口,别指望看控件内部逻辑。用惯 Lazarus 的人横向对比会明显感觉到差距——Lazarus 的 DBGrid 生态没有 EhLib 这层成熟封装,这也是很多团队最终留在 Delphi 阵营的原因之一。

2.4 组件安装前必须确认的三件事

在动手解压之前,建议先把这三个问题查清楚,能省掉后面大半排查时间。第一,IDE 是 32 位还是 64 位启动,Delphi 13.1 默认以 64 位运行,安装包里的 bpl 必须匹配;第二,项目未来要不要编译 Win64 目标,要的话库路径里 Win64 那层必须一并配置;第三,工程里已经装过的第三方控件有没有和 EhLib 重名的 dcu,比如以前残留的旧版 EhLib,这会导致 IDE 报“找不到 DbGridEh”或编译时用了旧版单元。第三点最隐蔽,很多人排查半天没发现问题,最后发现是库路径顺序不对,老版本 dcu 排在了新版本前面。这三个点确认完,再进入安装步骤。

3. 无源码版安装:把 13.0.015 装进 Delphi 13.1 的库路径与设计期包

3.1 解压 7z 并认准目录布局:dcu、bpl、dcp 各在哪个文件夹

no source 版本没有 Source 目录,整个包里只有编译产物,解压时不要用鼠标右键的“全部提取”,我习惯用命令行带参数解压,能完整保留目录结构。下载到的压缩包文件名里带空格和括号,命令行里要记得转义:

7z x "EhLib.VclFmx.13.0.015(no source).7z" -oD:\Libs\EhLib -y dir /b /s D:\Libs\EhLib | findstr /i "dcu$ bpl$ dcp$"

7z x 表示按原始目录结构解压而不是压平,-o 指定目标根目录,-y 跳过所有覆盖确认。解压完先看 dcu、bpl、dcp 三类文件的分布:dcu 是编译用的单元文件,必须进 IDE 的库路径;bpl 是运行时和设计时的包文件,设计期包要注册进 IDE;dcp 是包编译时生成的符号文件,一般跟着 bpl 走。常见发布布局是 Lib 下按平台分子目录,比如 Lib\Win32\Release、Lib\Win64\Release,每个目录里是各自位的 dcu,Bin 或 Bpl 目录里放 bpl。此时不要急着把整个 EhLib 根目录加进 IDE,库路径只认到含 dcu 的那一层,加错层级后面编译一定会翻车。

3.2 把库路径加到 IDE:Win32 与 Win64 分开配

Delphi 13.1 的库路径是按平台分开维护的,这点最容易忽略。菜单入口在 Tools > Options > IDE > Library,左侧选中某个平台,右侧的 Library path 就是编译时搜索 dcu 的路径列表。包括默认的 Win32 和 Win64,我建议把用得到的平台全部加上对应目录,而不是只加一个 Release 了事:

# 以 Win64 平台为例,在 Options 的 Library path 里追加: D:\Libs\EhLib\Lib\Win64\Release D:\Libs\EhLib\Lib\Win32\Release

这里有个顺序讲究:相同名字的 dcu 如果出现在多个路径里,IDE 按列表先后顺序取最先找到的。所以新加的 EhLib 路径尽量放在列表靠前的位置,避免被旧版本同名文件截胡。加完点 Save 会重新索引一次,这个阶段如果提示“Cannot find unit”,先回到这步检查路径是否精确到 Release 层。另外,如果 IDE 里也开了 Debug 序列化目录,可以顺手加 Lib\Win32\Debug,编译 Debug 配置时代码能更快锁定到对应 dcu,但无源码版 debug 也只是能链接,跟不进源码。

3.3 注册设计期包:Install Packages 里添加 bpl

库路径解决的是编译期问题,组件面板不显示 DBGridEh 还差一步:注册设计期包。菜单入口 Component > Install Packages,点 Add,找到解压目录里带设计期标识的 bpl。设计期包和运行期包的区别是:运行期包供你的 exe 编译后链接使用,设计期包额外负责往 IDE 组件面板上注册图标和属性编辑器。no source 包里 bpl 通常成对出现,文件名带 Design 字样的才是要装的那一个。

Install Packages 对话框 -> Add -> 选择 EhLib 设计期 bpl -> OK

装完组件面板会出现 EhLib 专用页,里面能看到 DBGridEh 等组件。如果 Add 时提示“Cannot load package”,大概率是 bpl 依赖的运行期包不在这台机器的系统路径里。解决办法是把 bpl 所在目录加进系统 PATH,或者把它复制到 Delphi 13.1 的 bin 目录下,再重新 Add。这里不要直接双击 bpl 试图“安装”,那不是 Delphi 的包注册方式。

3.4 安装验证:一分钟拖出 DBGridEh 并编译通过

安装是否成功,最好的验证不是看组件面板里有没有图标,而是新建一个空 VCL 工程,拖一个 DBGridEh 到窗体上,连一个最简 DataSource,按 F9 编译跑起来。具体做法:新建 VCL Forms Application,从 EhLib 页拖 DBGridEh,放一个 DataSource 和一个 FDQuery,FDQuery 连上任意本地表,设置 DataSource.DataSet 和 DBGridEh.DataSource 后编译。

// 验证工程的最小接通代码 FDQuery1.Connection := FDConnection1; FDQuery1.SQL.Text := 'SELECT * FROM ORDERS'; FDQuery1.Open; DataSource1.DataSet := FDQuery1; DBGridEh1.DataSource := DataSource1;

这段代码能编译通过,说明 dcu 路径正确、bpl 加载成功、设计期注册完成,三步全部验证到位。如果编译报“File not found: 'DBGridEh.dcu'”,是库路径问题;如果编译过了但运行起来组件面板是空的,是设计期包没注册成功。这一步不要省,很多人直接拿现有工程打开,报错信息混在一堆业务代码里,反而难定位。

4. 最小落地:配置 DBGridEh 跑通查询、排序、合计与 Excel 导出

4.1 数据链路:FDQuery + DataSource + DBGridEh 的接法

DBGridEh 的数据源模型和原生 DBGrid 完全一致,走的还是 DataSource 中间层,所以现有工程里只要数据链路是标准接法,把网格控件直接替换就能复用。区别在于 DBGridEh 对数据集的字段类型感知更强,比如日期列会识别成日期格式,金额列自动右对齐,这些在原生 DBGrid 里要自己写 CustomDraw。我通常的做法是:FDQuery 只负责 SQL 和打开数据集,DBGridEh 不直接接触 FDQuery,一切通过 DataSource 中转,这样将来换数据集组件(比如从 FDQuery 换到 ClientDataSet)时网格部分完全不用动。

procedure TForm1.FormCreate(Sender: TObject); begin FDConnection1.Params.DriverID := 'SQLite'; FDConnection1.Params.Database := 'D:\data\orders.db'; FDQuery1.Connection := FDConnection1; FDQuery1.SQL.Text := 'SELECT OrderID, CustomerName, Amount, OrderDate FROM Orders'; FDQuery1.Open; DataSource1.DataSet := FDQuery1; DBGridEh1.DataSource := DataSource1; end;

这里 FDConnection1 用的是 SQLite 驱动,只是示例,换成 MySQL、Oracle 只要改 DriverID 和连接参数。要注意 FDQuery1.Open 必须在给 DataSource 赋值之前完成,否则运行时网格拿到的是一个未激活的数据集,界面上一片空白。如果数据集打开失败,先单独跑一下 FDQuery1.Open 看错误信息,别先怀疑控件。

4.2 标题栏排序:两个属性搞定点击排序和排序箭头

原 DBGrid 的标题排序需要处理 OnTitleClick,DBGridEh 里两个属性就够:网格的 OptionsEh 里打开 dghAutoSortMarking,列的 TitleButton 设为 True。dghAutoSortMarking 是全局开关,允许点击列标题自动切换升序降序并显示箭头;TitleButton 是每一列自己的开关,决定这一列标题是否可点击,不想让用户排序的列(比如备注列)关掉这个属性就行。

// 运行时打开全局排序标记 DBGridEh1.OptionsEh := DBGridEh1.OptionsEh + [dghAutoSortMarking]; // 第 0 列允许点击排序,第 1 列强制不可排序 DBGridEh1.Columns[0].TitleButton := True; DBGridEh1.Columns[1].TitleButton := False;

VCL 下本地数据集的排序走 SortLocal,把 SortLocal 设为 True 后点击标题直接在内存里排序,不会再触发 SQL 重新查询,几万行的表也没压力。如果底层数据集不是本地可排序的(比如某些只读结果集),则需要监听网格的 OnSortMarkingChanged 事件,在那里面拼 SQL 重新查询。对绝大多数桌面业务系统来说,SortLocal 就够了,不要一上来就写后台排序。

4.3 Footer 合计:金额列自动求和与中文标签

表格底部出汇总行是财务单据的刚需,DBGridEh 的 Footer 机制比自定义绘制干净得多。先在网格层面把合计行数量设为 1,再对具体列设置 Footer 的值类型和显示文本。值类型用的是枚举 vtSum,这是求和,还有 vtCount、vtAvg 可以处理数量列和平均列。

// 显示一行合计行 DBGridEh1.FooterRowCount := 1; // 第 3 列是金额,显示合计 DBGridEh1.Columns[3].Footer.ValueType := vtSum; DBGridEh1.Columns[3].Footer.Value := '合计:'; // 第 0 列显示总数 DBGridEh1.Columns[0].Footer.ValueType := vtCount; DBGridEh1.Columns[0].Footer.Value := '记录数:';

这里有个细节:Footer 的 Value 属性在 ValueType 非空时不是替代数字,而是显示在数字左侧的标签文本。比如 Value 设为“合计:”,最终单元格显示成“合计: 5280.00”。金额列的显示格式在列的 DisplayFormat 里配,和 Footer 无关。合计值默认对当前数据集里可见行计算,如果你用了过滤或分组功能,它算的是过滤后的集合,这个行为要在需求评审时说清楚,否则业务方会拿它和 SQL 原始 SUM 对比对不上。

4.4 导出 Excel:SaveToXLS 与导出格式的三个细节

导出是最能体现 DBGridEh 价值的场景。调用一行 SaveToXLS 就能把当前网格的可见列和数据写进 .xls 文件,不需要 OLE 启动 Excel,也不会残留后台 EXCEL.EXE 进程。文件名建议带时间戳,避免同一次操作多次导出互相覆盖。

procedure TForm1.btnExportClick(Sender: TObject); var Fn: string; begin Fn := 'D:\exports\orders_' + FormatDateTime('yyyymmddhhnnss', Now) + '.xls'; DBGridEh1.SaveToXLS(Fn); ShowMessage('已导出: ' + Fn); end;

用这个方法有三个具体细节要留意。第一,SaveToXLS 导出的是列定义和数据,Footer 合计行默认不会带出去,如果客户要求 Excel 里也有合计,需要在导出前临时把合计行数据写进数据集,或者导出后在 Excel 里重算,二选一,别指望一个方法全包。第二,隐藏列不会导出,导出前确认没有把不想暴露的字段列设为 Visible 等于 False,否则导出结果里悄悄少一列。第三,如果需要 .xlsx 格式,部分版本提供 SaveToXLSX,但在 no source 包里不确定是否编译进去了,稳妥做法是导出成 .xls,然后在客户端再用工具转一次。表格里的排序状态会跟着导出顺序走,导出前先让网格处于目标排序状态,这比导完再在 Excel 里重新排要省事。

4.5 下拉编辑列:PickList 减少手工输入

业务表格里经常有“状态”这类枚举字段,手输容易出错,DBGridEh 的列级 PickList 能在单元格进入编辑状态时弹出一个下拉列表,值从列表里选,存进去的还是文本本身。这个功能不需要额外放一个 DBComboBoxEh,直接在列的属性面板里往 PickList 添加条目即可,运行时也能动态加:

// 第 2 列是状态列,加入可选值 DBGridEh1.Columns[2].PickList.Add('待审核'); DBGridEh1.Columns[2].PickList.Add('已通过'); DBGridEh1.Columns[2].PickList.Add('已驳回');

如果下拉选项来自另一张表的数据,就别用 PickList 了,改用 DBLookupComboboxEh 或者列的 LookupParams,那支持显示字段和值字段分离。PickList 适合选项固定或只在当前窗口写死的场景;选项会随业务增删的,必须走查找列,否则每次加选项都要改代码。还有一点,PickList 的选项用于编辑,不影响列显示,如果列本身显示的是代码值而你想显示描述文本,那是另一套 Lookup 配置,不要混淆。

5. EhLib 安装与使用的 6 个典型坑:现象、原因、处理

5.1 编译报 File not found,但明明已经加了库路径

现象:新建工程拖入 DBGridEh 后编译,IDE 提示找不到 DBGridEh.dcu,可库路径里明明已经加了目录。原因:库路径加到了顶层目录,而 dcu 实际在下一级平台子目录里,IDE 只会在你给的路径直接搜索,不会递归子目录。处理:把路径精确到含 .dcu 的那一层,比如 Lib\Win64\Release,然后确认选中了当前目标平台,不是只加了 Win32 就在 Win64 下编译。这算是最常见的安装后第一坑,十个里至少有三个是这里翻车。

5.2 32 位编译正常,切到 64 位目标就报找不到单元

现象:默认 Win32 平台编译没问题,把目标平台切到 Win64 后立刻报错,提示大量 EhLib 单元缺失。原因:库路径每个平台是独立维护的,你在 Win32 里加了路径,Win64 里并没有,编译器自然找不到 Win64 版的 dcu。处理:所有用到的平台都单独加一遍,别偷懒只加一个;同时确认包里确实存在 Win64 子目录。有些年份的发布包只带了 32 位库,那种情况就只能在 64 位工程里装回旧版或者放弃 64 位目标。

5.3 no source 版本调试时 F7 一片汇编,完全没法看

现象:业务代码断点正常,一 F7 跟踪进 DBGridEh 内部就变成 CPU 窗口的一堆汇编指令。原因:无源码版本只有 dcu,没有对应的 .pas 源码文件,调试器找不到源码就落到反汇编。处理:这是选择 no source 的必然代价,没有后悔药可吃。可以接受现状;实在需要排查控件内部行为的,给网格触发的事件挂日志,或者把怀疑点放到自己的事件处理函数里逐行验证,不要试图从汇编里读懂排序逻辑。如果团队里有源码强迫症,下次采购控件要换带 Source 的完整版。

5.4 Install Packages 加载 bpl 报 Cannot load package

现象:点 Add 选中 bpl 后 IDE 弹出无法加载的对话框,组件面板里什么都出现不了。原因:bpl 依赖的其他运行期包(比如基础运行库 RTL 或第三方依赖)不在系统路径中,Windows 加载 DLL 是按 PATH 顺序找依赖文件的。处理:把 bpl 所在目录加进系统环境变量 PATH,再把 IDE 完全重启,再重新 Add;或者直接把 bpl 复制到 Delphi 13.1 的 bin 目录下再装。复制到 bin 目录的方式虽然土,但在内部服务器这种不方便改 PATH 的环境里最稳。

5.5 运行时找不到 bpl:exe 拷到别的机器就启动失败

现象:开发机器上编译和运行都正常,把 exe 拷到没有装 Delphi 的客户端机器上,双击提示找不到某个 bpl。原因:你编译时链接了运行时包(linking runtime packages),exe 本身没有打进控件代码,依赖目标机器存在对应 bpl。处理:两种路线二选一。路线一,在 Project Options 里关闭运行时包链接,让控件代码静态编进 exe,交付文件干净;路线二,把运行期 bpl 一起放进 exe 同目录交付,但要注意版本匹配,不匹配照样起不来。多数内部小系统我选静态链接,省去分发依赖的麻烦。

5.6 FMX 下相同代码,Footer 合计不显示或者显示位置异常

现象:VCL 工程里一切正常,桌面编译成 FMX 版本后发现列合并、Footer 显示错乱。原因:FMX 版本的网格底层渲染机制和 VCL 不一致,部分属性虽然编译期存在但设计期/运行期不生效,尤其是依赖画布手动绘制的那些。处理:FMX 项目先以功能跑通为目标,重点验证布局和跨分辨率显示,把复杂合计逻辑放回内存计算结果,不要依赖网格自绘。移动端屏幕窄,Footer 能省就省,改用数据集算好一条汇总记录从界面顶部单独展示,比硬拖 Bottom 更可控。

6. 进阶:VCL 与 FMX 双轨下的差异化调优和验收方法

6.1 FMX 版别照抄 VCL 属性:行高、触摸滚动和虚拟键盘

把 VCL 工程整个搬到 FMX 平台,拖入 DBGridEh 后发现三点差异最明显:行高单位不同,VCL 里像素和字体基线是同一套坐标系,FMX 用的是逻辑单位,同样的 Height 数值在移动端会显得特别挤;触摸滚动和鼠标滚动是两套交互,移动端用户习惯手指拖动,网格的行高要加大默认值的 1.4 到 1.6 倍;输入框聚焦时虚拟键盘弹起会遮住下半屏,DBGridEh 的内嵌编辑器在键盘弹起后不会自动滚到可见区域,需要监听对应事件把滚动位置顶上去。还有一点,FMX 下面的 Excel 导出不要走 OLE 路线,Windows 上勉强可用,换到 macOS 或 Android 直接崩,导出需求统一走文件流方案。你在 Android 上想输出 PDF 也是同理,别在网格层绞尽脑汁,把数据抽出来交给报表组件处理。

6.2 验收习惯:用一个固定数据源自检合计和导出

我自己的习惯是装完控件先建一个“验收工程”,不放业务逻辑,只有一张固定 3 行数据的表和一个 DBGridEh,用来验证每次升级控件版本后行为是否变化。这个工程要满足三个检查点:Footer 合计等于三条数据的 SUM;点击标题排序后再合计,值不变;调用 SaveToXLS 后生成的 xls 用脚本读回来,数值能和界面核对一致。固定数据比随机业务数据好在可预期,任何一次升级导致的排序不稳定或合计偏差都能立刻发现。

-- 验收工程固定数据对应的期望值 SELECT SUM(Amount) AS ExpectedSum FROM Orders;

界面上的 DBGridEh Footer 显示值和这条 SQL 的结果一致,第一关就过了;导出后再用第二道脚本把 xls 里的数字读出来比对,第二关也过。每次给工程升级 Delphi 小版本或者控件包,跑一遍这个验收工程比看发布说明可靠得多。这套验证我现在还在用,虽然只有几行代码,但已经帮我抓过两次版本升级导致的排序箭头方向反转问题。也希望这篇笔记能帮你在装好 EhLib 之后少走几步弯路,把更多时间留在真正业务上。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询