简介:Delphi 12.3环境下的EhLib VCL 11.1.015专业版组件包,是一套面向使用Object Pascal进行数据库应用开发的Delphi程序员的第三方控件集合,主要用于扩展VCL数据控件能力,解决数据密集型桌面应用中的网格展示、编辑、打印与多数据库适配等问题。该版本针对现代Windows应用做了优化修复,提供数据感知网格、报表生成器、数据绑定与编辑控件,并支持InterBase、Firebird、MySQL、Oracle、SQL Server等主流数据库,可显著简化复杂数据界面的构建过程并提升运行性能。压缩包内共2000个文件,以pas源码、dfm窗体、dproj/dpk工程与包文件为主,辅以ico图标、png图片、chm帮助文档及示例数据库等,整体约32.81MB,源码、工程、说明文档与示例一应俱全,便于安装配置、阅读研究和二次开发。目前已有138人学习下载,适合需要在Delphi 12.3中集成成熟第三方数据库控件、缩短数据库应用开发周期的中高级开发者。该专业版还包含商业授权相关组件与完整示例,配合文档可帮助团队快速落地具备专业外观和高性能的数据管理软件,减少底层数据处理与重复编码工作量。
1. EhLib.VCL 11.1.015:一套让 DBGrid 长出多表头、分组和合计的控件包
Delphi 桌面管理类项目做到第三四个报表页,基本都会撞上同一个痛点:原生 TDBGrid 太素,表头只有一行,合计要自己写循环,排序要么拼 SQL 要么翻数据集,导出更是要手工拼 CSV。EhLib.VCL 就是来补这块短板的第三方 VCL 控件包,11.1.015 Professional Edition 覆盖到 Delphi 12.3,装上之后控件面板里多出 TDBGridEh、TDBEditEh、TDBLookupComboboxEh 这一族控件,核心场景从多表头、自动合计、分组统计到导出 Excel 全都归它管。这篇笔记按“为什么选专业版、怎么装到 12.3、核心功能代码怎么写、哪五个坑最容易翻车”的顺序展开,新手能照着落盘,熟手也能对着参数边界判断值不值得投入。
2. 为什么是 EhLib 而不是重写 TDBGrid:专业版到底多给了什么
2.1 先认清拳头产品:TDBGridEh 在原生控件上加了什么
老项目里的“表格”需求从来不只是把数据铺开。进销存要“本月入库明细”两层表头,上面一层是“入库信息”,下面拆成“单号、日期、数量”;财务页要底行合计;业务员列表要点表头就能按列排序。这些需求落在原生 TDBGrid 上,每一件都得写事件:多表头要用OnDrawColumnCell画边框线,合计得在OnCustomDraw或数据遍历里自己累加,排序得分清楚是本地IndexFieldNames还是回 SQL 改 Order By,导出基本没有内置能力。
TDBGridEh 把这些收进了属性里。列对象TColumnEh自带Title和Footer结构,多表头开一个开关,合计行开一个计数,排序有SortLocal,分组有GroupingData。它不是把原生控件包一层壳,而是把网格常见操作重写了一遍绘制和数据逻辑。你在设计期双击列就能打开列编辑器,勾选合计类型、设置显示格式、调整列顺序,运行期这些配置直接生效。
原生是白纸,EhLib 是半成品方案。对大多数 MIS、ERP 后台页面来说,后者的价值在于把“每个页面都要重复写的两百行表格逻辑”压缩成几个属性。这也是我推荐团队优先评估它的原因:它不是万能的,但表格类需求里它覆盖了八成场景。
2.2 Professional Edition 比 Standard 多出的东西:源码、内存表、设计期编辑器
标题里带 Professional Edition,这是商业授权版。常见的交付包里,Standard 或试用版能让你跑起来但会弹版权提示,专业版的核心差异在三块:完整源码、设计期编辑器、以及 TMemTableEh 这类附加控件。
完整源码的实战意义在于调试。表格合并单元格颜色不对、打印线条偏位,这类问题靠猜属性和看文档效率太低;直接翻 Sources 目录下的TDBGridEh.pas,找到绘制函数看断点,几十分钟就能定位是哪个像素偏移。我一般拿到包第一件事不是拖控件,而是用 IDE 的 “Find in Files” 搜FooterValueType的实现,确认它枚举值在哪个单元,这样后面写代码时知道该 uses 什么。
设计期编辑器是省时间的另一大头。右键 TDBGridEh 弹出的列设计器里,可以直接为某列加 Footer、设fvtSum、填ValueField,运行前就能看到效果预览。专业版的 TMemTableEh 则是内存表控件,临时汇总、过滤、分组比重新建 ClientDataSet 方便,配合网格做报表中间层很顺。
再说直白一点:标准版可以把控件装上用,但改不了内部行为;专业版把黑匣子拆开摆在桌面上。项目里已经有大量历史代码、又不想被控件厂商牵着走的时候,这条差异就是预算决策的关键。
2.3 与 DevExpress/TMS 的选型边界:什么时候不该无脑上 EhLib
讲完优势,也得讲边界。Delphi 控件里 DevExpress QuantumGrid 是重型选手,功能确实全,但学习曲线陡,一套皮肤下来界面风格统一要额外花时间调;TMS FlexGrid 偏表格底层,灵活但很多能力要靠自己堆事件。EhLib 居中:它专注“数据表格本身”,多表头、合计、分组、排序、导出全覆盖,但没有图表、没有复杂卡片视图、没有日历导航这类扩展。
我的选型判断是:页面主体是数据网格、字段几十个、交互主要是查和导,就用 EhLib;项目里要求界面像 Web 后台那样有卡片、树、联动筛选器,那上 DevExpress 更划算;如果只是只读表格,原生 TDBGrid 加两个事件也能顶,没必要引入第三方依赖。
另一个现实因素是维护成本。EhLib 的源码是 Pascal,团队里只要有人能读 Delphi 基础代码,出问题敢改;DevExpress 这类大套件遇到版本兼容问题,很多时候只能等官方更新。对维护周期长的进销存类系统,“敢改源码”比“功能多”更重要。
3. 在 Delphi 12.3 里装好 EhLib 11.1.015:从 RAR 解压到控件面板出现
3.1 解压之后的目录门道:Sources、Packages、Common 各管什么
先做一件事:把 RAR 解压到一个纯英文路径下,比如D:\Dev\EhLib_11,路径里不要带中文和空格。这不是玄学,是 dcc32 编译器和部分 IDE 插件在带中文路径下会偶发 “File not found”,报错位置还特别隐晦,不值得赌。
解压后先看目录结构,不要急着双击 install.bat。常见的布局里会有 Sources、Packages、Common、Docs、Demo 这几个目录,各管一摊:
- Sources 是控件核心源码,TDBGridEh 的
.pas文件都在这里,安装后要把它加进 IDE 的 Library path,编译时找不到.dcu八成是漏了这一步。 - Packages 是按编译器版本分目录的包工程,
Delphi12目录下放着.dpk和.bpl工程文件,是编译安装的入口。 - Common 是公共工具单元,一些版本的数据导出插件、辅助函数会依赖它,建议也放进搜索路径。
- Demo 是官方示例,很多属性组合和坑点其实是照 Demo 调出来的,值得留。
这里有个常见误区:把 Packages 目录加进搜索路径而不是 Sources。IDE 能找到.dpk但编译你的业务工程时找不到TDBGridEh.pas生成的.dcu,报错只差一个单元名,排查却要多花半小时。
3.2 先编译运行时包还是设计时包:顺序错了会怎样
安装顺序是新手最容易翻车的地方。正确顺序永远是:先编译运行时包,再编译并安装设计时包。运行时包是控件逻辑本体,设计时包是让控件出现在 IDE 工具面板上的壳,壳依赖体,反着装就会出现“工具面板能看见 TDBGridEh,拖到窗体就报 Class not found”的情况。
Windows 下 install.bat 做的事情,拆开看其实就三步:找到 Delphi 12.3 的安装目录,调用 dcc32 编译运行时.dpk,再把设计时.dpk编译出的.bpl注册进 IDE。我一般不用一键脚本,因为它在某些系统上会静默跳过个别包,手动两步更可控:
# 以 Delphi 12.3 默认安装目录为例 # 第一步:编译运行时包(注意先 cd 到对应版本的 Packages 目录) cd /d D:\Dev\EhLib_11\Packages\Delphi12 "C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\dcc32.exe" -B EhLib.dpk # 第二步:编译并注册设计时包 "C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\dcc32.exe" -B -JP dclEhLib.dpk这里的-B是强制全部重建,避免旧的.dcu干扰;-JP是让 dcc32 生成 bpl 并做注册。如果命令行编译中间报单元找不到,先把D:\Dev\EhLib_11\Sources和D:\Dev\EhLib_11\Common追加到 dcc32 的-U参数后面,等价于给编译器临时加搜索路径。
手动编译还有个好处:报错信息能实时看到。比如提示缺少某个jcl或dcl基础库,说明你本机 Delphi 的公共包版本和 11.1.015 的编译条件不完全匹配,这时候直接查包名再去 IDE 里装对应运行时包,比脚本一把梭快得多。
3.3 把库路径挂进 IDE,并实测控件落地的检查清单
编译安装完成后,还有最后一步:把 Sources 和 Common 挂进 IDE 的全局搜索路径。路径不对,控件面板正常,但你的工程一编译就报 “TDBGridEh not found” 或 “Unit not found”。
在 IDE 里打开 Tools > Options > Language > Delphi > Library > Library path,新增这两行:
D:\Dev\EhLib_11\Sources D:\Dev\EhLib_11\Common加完路径最好重启一次 IDE,让设计时包重新加载。然后建一个全新的 VCL 空工程,按下面清单验证安装结果:
| 验证项 | 通过标志 |
|---|---|
| 工具面板出现 EhLib 选项卡 | 能拖出 TDBGridEh,不报 Invalid class |
| 编译空工程 | 无 “TDBGridEh not found” 或 “.dcu 找不到” |
| 右键网格打开列设计器 | 能看到列集合,能修改 Title Caption |
接着跑最小代码,确认控件真能出数据:
procedure TForm1.FormCreate(Sender: TObject); begin // 用 FieldDefs 快速建一个内存数据集,避免连数据库 with ClientDataSet1.FieldDefs do begin Clear; Add('Name', ftString, 10); Add('Amount', ftInteger); end; ClientDataSet1.CreateDataSet; ClientDataSet1.AppendRecord(['电梯维保', 12000]); // 数据源和网格相互绑定 DataSource1.DataSet := ClientDataSet1; DBGridEh1.DataSource := DataSource1; end;这段代码里FieldDefs.Add的三个参数分别是字段名、类型、长度,ftString必须给 Size,否则建表会报错。跑起来后窗口能显示一行“电梯维保 / 12000”,说明控件安装和路径配置都通了。
4. 让表格自己干活:多表头、行合计、分组排序的代码级实现
4.1 多表头:MultiTitle=True 之后,一个标题里塞两行
报表页里最常见的需求是两层表头:顶层一个“员工信息”,底层拆成“姓名、部门”。EhLib 实现这个只要一步开 MultiTitle,然后用竖线分隔两层标题:
// 开启多表头模式,TColumnEh 的标题才会解析竖线分隔符 DBGridEh1.MultiTitle := True; DBGridEh1.Columns[0].Title.Caption := '员工信息|姓名'; DBGridEh1.Columns[1].Title.Caption := '员工信息|部门'; DBGridEh1.Columns[2].Title.Caption := '业绩数据|销售额';竖向分隔符必须是英文|,中文全角或顿号都不会触发换行。同一个顶层名称的列,运行时会被绘制成合并单元格,也就是“员工信息”跨姓名和部门两列;“业绩数据”独立成组。这是一个纯属性开关,不需要碰任何绘制事件,多表头和拖动列宽也能共存。
这里要注意列的索引问题。Columns[0]是按列集合当前的排列顺序索引的,如果设计期调整过列序,数字索引可能不再是你以为的那一列。后面避坑章会专门讲怎么用字段名定位列,这里先带上一个更稳的写法:尽量在设计期列编辑器和字段绑定一起处理,运行期不要频繁用数字索引改 Caption。
4.2 合计行:FooterRowCount 与 fvtSum 的两个必设属性
底行合计是财务页的命根子。EhLib 的 Footer 行设计得很直接,先开合计行区域,再指定某列的合计类型和统计字段:
// 合计行默认不显示,FooterRowCount 至少要 1 DBGridEh1.FooterRowCount := 1; // 对“销售额”这一列做求和,ValueType 枚举在 EhLib 的常用单元里 DBGridEh1.Columns[2].Footer.ValueType := fvtSum; DBGridEh1.Columns[2].Footer.ValueField := 'Amount'; DBGridEh1.Columns[2].Footer.FieldName := 'Amount';ValueType的可选值包括fvtSum、fvtAvg、fvtCount、fvtMax、fvtMin,对应求和、均值、计数、最大、最小。ValueField是参与统计的字段名,FieldName决定页脚显示文本的字段来源,实际项目中这两个最好保持一致,避免出现“算的是 Amount 显示的是 Qty”的情况。
列本身的DisplayFormat属性会同时影响 Footer 里的数字格式。如果字段值是浮点数,记得设成#,##0.00,否则合计结果会显示成一大串小数。还有一点:当数据集为空时,fvtSum默认显示 0,而fvtCount显示 0 也是正常的,不要试图在空表时把 Footer 藏起来,那属于额外逻辑。
4.3 分组与排序:不写一行 SQL,把明细摊成“带小计的抽屉”
分组是 TDBGridEh 另一个招牌能力。开启分组面板后,运行期用户可以把列头直接拖进分组条,按字段折叠数据;代码里也可以用属性固定分组字段:
// 显示顶部“分组拖拽区”,运行期可拖入列表头 DBGridEh1.GroupingData.ShowGroupingPanel := True; // 固定按部门分组 DBGridEh1.GroupingData.GroupFieldName := 'Dept'; // 分组默认折叠,减少滚动长度 DBGridEh1.GroupingData.DefaultGroupExpanded := False; // 点击列标题本地排序,不产生 SQL 回绕 DBGridEh1.SortLocal := True;SortLocal := True的作用是让点击列标题时直接在当前数据集上做内存排序,适合已经加载到本地的数据。如果你连的是远程 SQL 数据库且数据量大,不要开它,否则每点一次表头就全表拉一遍,性能会很难看。那种场景应该把排序交给后端 Order By,EhLib 里对应的是服务器端排序模式,本地只负责显示。
分组这里有个容易漏的点:分组字段在数据集里的值如果不连续,同一个值会出现多次分组。比如“部门”数据是“A、B、A、A”,内存数据集没有按 Dept 排序时,A 会被分成两个组,看起来像数据重复。凡是做分组展示,先让数据集按分组字段排好序,再开分组,显示才正常。
5. 避坑:EhLib 11.1.015 在 Delphi 12.3 下的 5 个常见翻车现场
5.1 现象:编译报错 “TDBGridEh not found” 或 “File not found: dclEhLib.bpl”
这是安装后最常见的问题。控件面板里明明有 TDBGridEh,新建窗体也能拖上去,但一编译整个工程就报找不到类。
原因一般不在控件本身,而在两个点:一是 Library path 里只加了 Packages 没加 Sources,IDE 在设计期能找到 bpl,但编译业务代码时找不到TDBGridEh.pas对应的 dcu;二是运行时包没编译成功,设计时包强行安装,IDE 里显示正常,编译器却缺底层单元。
解决分两步走:先把D:\Dev\EhLib_11\Sources和Common都加进 Tools > Options > Language > Delphi > Library > Library path,顺序要放在其他第三方库前面;然后回到 Packages\Delphi12,按“运行时包在前、设计时包在后”的顺序重新编译一遍。多数“not found”都会在这一轮后消失。
5.2 现象:导出 Excel 打开全是 “???” 或乱码
网格里中文显示正常,用SaveToExcel导出的 xls 文件用 Excel 打开后中文全变成问号,英文数字正常。
原因是老式 .xls 导出通道按 ANSI 编码写文件,简体中文环境下代码页一冲突就坏;另外数据集里字段若是 AnsiString 而非 WideString,导出时宽字符会被截断。这个问题跟控件版本有关,但 11.1.015 在默认参数下依然会踩。
我的后悔药是:不硬磕 Excel 导出,改成 UTF-8 带 BOM 的 CSV,Excel 直接识别,既不乱码也不依赖 OLE:
var SL: TStringList; begin SL := TStringList.Create; try SL.Add('姓名,销售额'); // 真实项目中这里遍历 DBGridEh1.DataSource.DataSet 逐行拼数据 SL.SaveToFile('report.csv', TEncoding.UTF8); // UTF-8 带 BOM,Excel 正确识别中文 finally SL.Free; end; end;TEncoding.UTF8在 Delphi 2009 以后可用,12.3 自然支持。注意TStringList.SaveToFile带编码参数时会自动写 BOM,Excel 打开 .csv 就能按 UTF-8 解析,这是绕开乱码最稳定的路径。
5.3 现象:编译 dpk 时报“内存错误”或 Access Violation
安装控件包时 dcc32 崩了,错误信息类似“内存错误”或 Access violation,注册表也写不完整。
这个报错多数和 EhLib 无关,和编译环境有关:解压路径带中文、杀毒软件实时扫描临时文件、IDE 里残留了上一个版本的 dcu 缓存,都会让编译器踩到异常地址。
我的处理顺序是这样的:先解压到纯英文短路径;退出 IDE,删除 Packages\Delphi12 目录下所有*.dcu和__history文件夹;然后管理员身份运行 IDE 或命令行重新编译。如果还报,就关掉杀毒软件的文件监控再试一次。这一步解决了我遇到过的九成编译崩溃。
5.4 现象:列设计器调整顺序后,表头字幕和列内容对不上
代码里用Columns[0]设置了标题,但运行后发现标题串到了相邻列上,多表头模式下更明显。
原因是列集合的索引和可见顺序不一致。列设计器里拖动列后,物理索引没变但显示顺序变了,运行期再用固定数字索引给 Title 赋值,就把标题赋给了错误的列对象。
解决是改用字段名定位列,而不是索引:
var Col: TColumnEh; begin Col := DBGridEh1.Columns.FindColumnByFieldName('Dept'); if Col <> nil then Col.Title.Caption := '组织|部门'; end;FindColumnByFieldName是按字段名在列集合里查找,列怎么拖都不会找错。返回的TColumnEh对象判空后再用,避免字段名写错时直接访问空指针。这也是我在所有报表代码里的统一习惯。
5.5 现象:分组打开后,数据行“消失”了
设置GroupingData.GroupFieldName之后,网格里只剩下几个分组标题,明细行没了,第一反应是数据被清空了。
这通常是两个原因叠加:分组默认是折叠状态,行被收进“抽屉”里;或者数据集没有按分组字段排序,相同值的行分散在多处,被拆成多个组,看起来内容变少。
先验证数据没丢:检查ClientDataSet1.RecordCount,数量不变就说明只是折叠。再把默认展开开回来,并把数据集先按分组字段排序:
DBGridEh1.GroupingData.DefaultGroupExpanded := True; // 先全部展开确认数据在 ClientDataSet1.IndexFieldNames := 'Dept'; // 按分组字段排好序 DBGridEh1.SortLocal := True;数据量小的时候用IndexFieldNames即可;数据量大或远端数据集,排序逻辑放到 SQL 层。分组功能本身不删数据,但折叠状态和未排序会制造“丢数据”的假象,先展开、先排序,再谈优化。
6. 进阶:过滤行与自检,把 EhLib 调成自己的表格工作台
6.1 用 STFilter 行内过滤替代手写 Edit 组件
很多项目做筛选的习惯是:窗体上方摆一排 Edit 和 ComboBox,点“查询”后重新取数。数据量不大时,更轻的做法是用 TDBGridEh 自带的 STFilter 行内过滤,不需要额外控件:
// 打开每列表头下方的过滤行区域 DBGridEh1.STFilter.Visible := True; // 本地过滤:直接在当前数据集上执行 DBGridEh1.STFilter.Local := True;STFilter.Visible决定网格上方是否显示过滤输入条,每列对应一个小漏斗按钮,点开能输入关键字或范围;STFilter.Local让过滤在当前数据集内完成,适合几万行以内的内存数据。远程大表不要开 Local,否则每次过滤都会全量拉数据,性能扛不住。
这个能力和分组面板配合,基本能把一个报表页做成小型的自助查询工具,用户自己拖分组、自己过滤、自己导出,开发只需要把数据准备好。
6.2 写一个最小自检流程,验证分组、合计、导出链路
第三方控件换版本后,我最怕的是旧代码在细节上悄悄改变行为。所以现在养成的习惯是:每次接入新版本,先写一个自检按钮,把核心功能断言一遍:
procedure TForm1.btnSelfCheckClick(Sender: TObject); begin // 自检一:合计行是否开启 Assert(DBGridEh1.FooterRowCount >= 1, '合计行未启用'); // 自检二:多表头模式 Assert(DBGridEh1.MultiTitle, '多表头未启用'); // 自检三:导出文件能否生成 DBGridEh1.SaveToExcel('selfcheck.xls'); Assert(FileExists('selfcheck.xls'), '导出失败'); // 自检四:分组面板可用 Assert(DBGridEh1.GroupingData.ShowGroupingPanel, '分组面板未开启'); ShowMessage('自检通过'); end;Assert在 Delphi 的 Debug 配置下默认开启,发布编译会关闭,所以这段代码可以安全留在工程里当回归测试用。实际项目里可以把四项断言再细化,比如检查合计值是否为预期求和结果、导出文件大小是否大于某个下限,这样版本升级后点一次按钮就能发现行为漂移。
我自己的交付习惯是:任何第三方控件包拿到手,先建一个最小空工程跑通核心链路,再进入业务代码。原因很简单,版本兼容问题的报错往往是“内存错误”“找不到类”这类黑匣子信息,不先把控件自身排除掉,出了问题根本分不清是控件、是数据库、还是业务逻辑的锅。EhLib 这套多表头、合计、分组、排序、导出的组合,是当前 VCL 项目里我维护得最顺的表格方案,希望帮到你。
本文还有配套的精品资源,点击获取