简介:本资源是 EhLib 控件库 12.0 Build 12.0.039 的完整开源源码包,专为 Delphi/C++Builder 开发者设计,解决数据库界面开发中重复造轮子、代码冗长、跨平台适配难等痛点,尤其适用于需快速构建高交互性数据表格、离线编辑、多端部署的企业级桌面与移动应用开发场景。压缩包含 2000 个文件,主体为 1936 个 .hpp 头文件(含全平台 VCL/FMX/LCL/WinForms 兼容接口)、22 个 .doc/.docx 用户手册(含俄英双语开发指南与版本演进说明)、12 个 .sql 示例脚本及配套文档,总大小 334.48MB。目前已有 341 人学习下载。开发者可直接编译运行全部控件源码,深入理解 TDBGridEh 的就地编辑与导出机制、TMemTableEh 的内存树形结构实现、TPrintDBGridEh 的报表缩放逻辑,并基于丰富文档快速掌握多级下拉、页脚合计、断网离线同步等核心功能的定制方法。
1. 为什么这么多年过去,还有人在到处找EhLib的完整源码包
1.1 一个流传多年的组件库,到底是什么来头
先聊点背景。EhLib这个组件库,在Delphi和C++ Builder圈子里混过几年的人基本都听过。它最早由EhLib团队开发,主打的是对原生DBGrid的增强替代,后来逐渐扩展出内存表、报表、下拉列表、筛选器等一系列实用功能。如果你用过Delphi自带的TDBGrid,再切到DBGridEh,那种“原生的怎么这么难用”的对比感会特别强烈。
标题里写的是“EhLib.VclFmx 12.0 Build 12.0.039 FS 完整源码版.7z”,拆开看其实信息密度很高:
- VclFmx代表这个版本同时覆盖VCL和FMX两套框架,不能用老眼光看待,很多老项目还留在VCL上,新项目已经开始用FMX跨平台,一套组件能两头兼顾,这是很多人选择它的重要原因。
- 12.0 Build 12.0.039是具体的版本号,EhLib的版本迭代节奏不算快,每到一个大版本,修复的问题和新增的组件特性都有明确的release note。
- FS是Full Source的缩写,也就是完整源码版。这一点在Delphi组件圈子里非常关键,因为很多商业组件只给DCU或编译好的安装包,出问题没法跟进到源码层去排查,而完整源码意味着你可以自己编译、自己调试、甚至按需裁剪。
适合看这篇内容的人,我理解主要是这几类:还在用Delphi维护旧系统的老开发,准备在新项目里引入更强力网格组件的中级工程师,以及被“表格显示、行编辑、分组汇总、打印预览”这些需求反复折磨的技术负责人。无论你是哪种,下面这些内容应该都能帮你省下不少折腾时间。
1.2 12.0.039这个版本号,放到现在依然能打吗
先说结论:如果你正在维护一个不算特别新的Delphi项目,12.0系列完全够用,而且它构建于一个相对稳定的功能基线之上,不太会出现装了之后一大堆组件报错的情况。
从功能上看,12.0这代的核心模块已经相当成熟:
- DBGridEh是绝对主力,支持多选、自动调整列宽、下拉筛选、按钮列、图片列、进度条列、分组视图、树形视图、行高自适应等。
- MemTableEh提供进程内的临时数据集,很多需要本地缓存、排序、过滤的场景都可以用它。
- Reports相关组件可以从数据集直接生成报表,支持打印预览,对于在Delphi里做进销存、ERP这类系统的人来说很顺手。
- 工具类组件如DataGroupingEh、PivotGridEh、PlannerEh等,属于锦上添花型,用好了能省大量自绘代码。
版本号递增本身不意味着会有翻天覆地的变化,但从旧版本升级过来的人通常能明显感知到:网格的绘制性能更快了,高DPI显示下的表现更稳了,对较新Delphi版本的支持也更完整。如果你的项目还在用老版本EhLib,且你正在被某些诡异的重绘问题困扰,升级到12.0.039这个build可以算是一个低风险的选项。
2. 拿到完整源码包之后的第一件事:解压、编译和安装,顺序不能乱
2.1 先别急着双击安装,先检查你的Delphi环境
很多人从网上下到EhLib.VclFmx 12.0 Build 12.0.039 FS 完整源码版.7z,解压之后第一反应是找install按钮或者直接打开包里的.dpk点编译。这个习惯在大版本不匹配的情况下很容易翻车,轻则报一堆找不到文件的错,重则把IDE的组件库路径搞乱。
正确的打开方式分三步:
- 确认Delphi版本与源码包要求的对应关系。EhLib对IDE版本是有要求的,编译器版本不匹配时,即使勉强编译通过,也可能会出现设计期组件无法显示、运行期访问冲突这类问题。
- 解压到稳定路径。我自己习惯放到
D:\Components\EhLib这种纯英文、无空格的目录下,尽量避免中文路径和带空格路径,否则有些编译脚本会莫名其妙失败。 - 确认源码目录结构完整。一个正常的EhLib源码包至少应包含
Common、VCL、FMX、Lib等子目录,以及对应各个Delphi版本的dpk文件。如果解压后发现缺目录,宁可去重新找一份完整的包,也不要凑合着只装一部分,否则后面用到某个组件时会出现运行期找不到单元的错误。
2.2 编译顺序为什么有讲究:先运行期包,后设计期包
安装Delphi组件,核心逻辑是先编译运行期包(Runtime Package),再编译设计期包(Design-Time Package)。运行期包是程序运行时会用到的代码,设计期包则是让组件出现在IDE面板上、允许你在窗体上拖放的工具。
很多第一次装EhLib的人会犯同一个错误:直接双击dclEhLib这种设计期包去编译,结果弹出的错误是找不到EhLib的运行期包。原因很简单,设计期包依赖运行期包的输出,你没先把底层编出来,上层自然找不到引用。
推荐顺序:
- 编译
EhLib主运行期包,按需选择对应版本,例如EhLib120.bpl。如果你的项目同时使用VCL和FMX,两个框架的包都需要编。 - 编译
MemTableEh、Reports等扩展运行期包,这些包依赖主包,但单独拆出来方便你按需加载,不需要报表功能时可以不引用对应包。 - 编译设计期包,比如
dclEhLib120.bpl、dclMemTableEh120.bpl等。编译完设计期包后,IDE的工具面板里通常会自动出现EhLib标签页。 - 验证安装:新建一个VCL项目,拖出一个
TDBGridEh到窗体上,如果能正常显示且没有报错,就说明主流程已经通了。再建一个FMX项目,同样拖一次,确认FMX侧的包也正常。
2.3 库路径(Library Path)配置:这一项最容易被忽略
编译完成并不代表一劳永逸。运行期包会被注册到IDE里,但源码单元的搜索路径不会自动加入。很多人出现过这样的情况:项目能打开,但编译时提示找不到EhLib.VCL单元。
原因就是没有配置Library Path。在IDE的Tools > Options > Environment Options > Delphi Options > Library里,把EhLib源码的主目录、VCL子目录、FMX子目录都加进去。加完之后建议重启IDE,让路径缓存刷新。
提示:如果你的项目使用git管理,并且团队有多个成员,记得把EhLib的公共安装路径约定清楚,写进README。否则每个人装的路径不一样,提交的项目文件里包含不同的搜索路径,很容易出现“我这能编译,你那报错”的经典问题。
2.4 编译过程中常见的报错与对策
我把实际安装过程中最常遇到的几个报错列出来,每一条都是亲身踩过的坑:
| 报错现象 | 根本原因 | 解决办法 |
|---|---|---|
找不到EhLib.VCL | Library Path未配置 | 检查源码目录是否加入搜索路径 |
包编译时提示Unit xxx was compiled with a different version of ... | IDE库路径里存在多个EhLib版本 | 清理掉旧版本路径,只保留当前版本 |
| 设计期包编译失败,依赖项不存在 | 忘记先编译运行期包 | 严格按运行期包到设计期包的顺序来 |
| FMX项目编译时提示缺少FMX相关文件 | 只装了VCL包 | 检查FMX运行期包是否已编译并安装 |
| 高DPI屏幕上组件显示模糊 | 老版本EhLib未适配DPI | 升级到12.0以上,或在DPR里调用Application.HighDPISettings相关配置 |
这些坑都算不上难解决,但如果你不按顺序来,排查起来会绕很多弯路。我见过有人在网上发帖问“为什么装了EhLib之后整个IDE都打不开了”,最后发现是强行安装了不兼容版本的包导致IDE内部组件注册出错。所以再次强调:安装前确认版本,安装时遵循编译顺序,安装后验证双框架。
3. DBGridEh使用深度拆解:别把增强网格用成普通网格
3.1 为什么我说DBGridEh值得替换原生DBGrid
原生TDBGrid在Delphi里存在了几十年,稳定性没话说,但功能确实有些跟不上现代桌面应用的需求。比如:
- 列头筛选需要自己写弹出框,默认没有。
- 多选模式只能选中矩形区域,不方便做行级多选。
- 数据着色、字体定制、单元格按钮、下拉列表都需要大量自绘代码。
- 大数量滚动时重绘效率一般。
- 打印、导出Excel、分组汇总基本属于“从零开始”的工作量。
DBGridEh并不是把这些功能硬塞给你,而是在原生网格的基础上提供了一套“开箱即用但可按需关闭”的增强机制。换句话说,你不用写一堆自定义绘制代码,只要在对象监视器里配置几个属性,就能达到过去几百行代码才能实现的效果。
这也是我推荐“替换”而不是“并存”的原因。如果项目是全新启动,直接用DBGridEh是成本最低的选择;如果是老项目迁移,逐窗体替换的改动也不算大,因为DBGridEh模仿了原生网格的大部分接口,已有的数据源绑定、列设置、事件代码基本能直接沿用。
3.2 让网格真正好用的几个核心交互设置
用DBGridEh有一段时间后,你会发现决定它好不好用的往往不是组件本身,而是你有没有把那几个关键属性配好。我的建议是,进入正式开发前先整体设定一套默认风格,避免每个窗体各配各的,界面效果五花八门。
列头筛选(Filter)
DBGridEh的列头筛选是它最拉风的功能之一。启用方式很简单:
- 设置
DBGridEh1.OptionsEh := DBGridEh1.OptionsEh + [dghFilterMenu]。 - 运行时列头会出现一个下拉箭头,用户可以按列内容筛选。
- 进一步配合
STFilter相关属性,可以定义筛选字段类型、下拉列表数据来源、日期范围控件等。
这套机制在查询类窗口里非常实用。以前你需要在查询条件区摆放一堆Edit和ComboBox,现在直接让用户在网格列头上操作,界面简洁很多。不过要注意,筛选功能本质上是在数据集层做过滤,如果数据源是SQL查询,建议判断一下是否需要服务端过滤,而不是每次都把所有数据拉下来再本地过滤。
行多选操作
用dghMultiSelect选项可以开启行级多选。选中后,可以通过DBGridEh1.SelectedRows拿到选中行的记录对象,或者通过SelectedList拿到列表。在批量审核、批量删除、批量导出这类场景里,这个功能能省非常多事。
注意:多选状态下,如果你调用了数据集的
DisableControls或对数据集做了Refresh,选中状态可能会丢失。需要批量操作时,建议在操作前把选中的主键值保存到一个临时列表,操作完成后再恢复UI状态。
单元格拖拽与列自动适配
dghColumnResize、dghColumnMove、dghAutoFitColWidths这几个选项分别控制列宽调整、列移动、列宽自动适应。我的建议是默认打开自动适配列宽,但在中文长文本较多的情况下,自动适配的计算结果有时会让列过宽,所以可以结合DBGridEh1.AutoFitColWidths的全局开关和单个列的MinWidth、MaxWidth来约束。
行高自适应
现在很多屏幕都是高分屏,内容量大的单元格如果不换行,显示效果会非常局促。设置RowHeight、AutoRowHeight相关属性后,可以让网格根据文本长度自动调整行高。但要注意,自动行高与固定列宽在某些情况下会互相影响,建议在开发阶段多用模拟数据压测一下。
3.3 数据编辑与校验:不该只在数据库层面做
DBGridEh的单元格编辑能力,原生网格都有,它的优势在于“编辑配套功能”更完善。比如:
- 下拉列表编辑时,可以直接绑定查找数据源,显示名称但存主键值。
- 日期编辑时,不需要你自己放一个DateTimePicker,网格内置的日期下拉框可以直接用。
- 点击按钮列时,可以触发自定义事件,适合“行内操作”这种交互模式。
- 单元格多行编辑时,支持一个简单的编辑器弹出窗口,对长文本编辑很友好。
我特别想提一下“编辑校验”这件事。大部分人都会在数据库层的约束里做数据合法性校验,这是底线,但很多时候等数据库报错再提示用户,体验已经晚了。更好的做法是:
- 在
DBGridEh1.OnUpdateData或字段的OnValidate事件里做前置校验。 - 校验不通过时,调用
Abort或设置RaiseError,阻止该行写入数据库。 - 同步在界面上给出明确的错误提示,并让焦点回到错误单元格。
这样能把大多数录入错误拦截在UI层,减少数据库的无效请求,也让用户感觉系统“很灵敏”。这个思路不止适用于EhLib,在任何数据录入界面都适用。
4. MemTableEh、报表组件与常用工具:不止是网格的附属品
4.1 MemTableEh:临时数据集的最佳选择
很多人在用EhLib时只盯着DBGridEh,忽略了一个隐藏主角——MemTableEh。它本质上是一个内存数据集,可以在不连接数据库的情况下直接创建表结构、插入数据、做排序筛选。在以下这些场景里,它比SQLite临时表、ClientDataSet都要顺手:
- 从多个数据源汇总数据后,展示到一个网格里。
- 在内存中做二次加工,比如计算汇总行、拆分结果集。
- 界面上的草稿数据,用户点保存时才一次性写库。
- 报表数据源,先整理好数据集再交给报表组件。
MemTableEh的用法和TClientDataSet很像,但因为它和DBGridEh同源,两者配合时的细节处理更默契。创建内存表的典型代码大致是:
var mt: TMemTableEh; begin mt := TMemTableEh.Create(nil); try mt.FieldDefs.Add('ID', ftInteger); mt.FieldDefs.Add('Name', ftString, 50); mt.FieldDefs.Add('Amount', ftFloat); mt.CreateDataSet; mt.AppendRecord([1, '示例一', 100.5]); mt.AppendRecord([2, '示例二', 200.75]); mt.First; // 此时可以将mt绑定到DBGridEh上展示 finally mt.Free; end; end;这套API很直白,不需要额外引入复杂概念。需要注意的一点是,MemTableEh做大数据量操作时,内存占用会随数据量线性增长,如果一次性塞入几百万行,建议评估一下是否有必要,或者考虑分页拉取。
4.2 分组、汇总与打印输出:网格和报表的配合
DBGridEh的分组视图是我个人非常喜欢的功能。开启分组后,可以把某个字段拖拽到分组栏,网格会自动按字段值分组展示,并逐组显示汇总行。这个效果特别适合“按类别看销售数据”“按部门看人员列表”这类需求。
实现分组显示的步骤如下:
- 在DBGridEh上启用
Grouping相关选项。 - 设置要分组的字段,比如
DBGridEh1.GroupFieldNames := 'Category'。 - 按需设置汇总字段,例如在
OnGroupGetSummaryText事件中计算金额合计数。
分组视图在界面上很直观,但在代码层面它只是对数据集做分组索引。真实场景里,如果你的数据来自数据库,建议在SQL层面也做一次排序,保证分组顺序和数据库顺序一致,避免出现乱序。
至于打印输出,EhLib的报表模块提供了比较完整的方案。你可以基于MemTableEh或直接基于查询数据集,生成表格类型的报表,再配合打印预览控件直接输出或导出PDF。这套流程最适合内部管理系统,不需要像专业报表工具那样精细设计,但胜在集成简单、改动小。
4.3 其他容易被忽略但值得一试的组件
- PivotGridEh:数据透视网格,适合做多维统计。虽然和Excel数据透视表的操作逻辑不完全一样,但对于“行维度、列维度、统计值”这种经典结构,它能帮你快速搭出汇总页面。
- PlannerEh:日程计划组件。如果项目里有排班、预约、计划管理这类模块,用它比在网格里手动拼界面省事太多。
- DataGroupingEh:专门做数据分组和聚合的引擎,和DBGridEh配合使用可以更好地控制分组层级与汇总逻辑。
- ImportExportEh:提供导入导出功能,常见格式包括Excel、文本、HTML等。这个模块我用得很频繁,特别是给客户导出Excel报表时,它可以控制样式、列宽、合并单元格。
每个组件的详细代码写出来篇幅太长,这里不展开了,但如果你在项目规划阶段就能预见到“未来可能需要这些能力”,建议在安装EhLib时把对应包一并编译进来,省得后面升级时再折腾一遍。
5. 性能坑位与排查经验:大数据量下别让界面卡成PPT
5.1 数据加载与滚动性能的根源
EhLib的网格在中小数据量下表现很好,但到了10万行以上,如果不做任何优化,某些操作确实会变得卡顿。不过这个锅一半要甩给使用方式,一半才轮到组件本身。
卡顿的根源通常在于:
- 数据集一次性加载了过多数据。比如直接
SELECT * FROM 大表,数据都在本地,网格再智能也扛不住海量记录的内存占用和重绘开销。 - 每次滚动都触发单元格级事件,比如在
OnGetCellParams里做复杂计算、写日志、查询数据库,这种写法会成倍放大滚动开销。 - 数据感知控件联动太多。网格和其他数据感知控件绑到同一个数据集上,数据集滚动时所有控件同步刷新,效率自然会下降。
- 自动列宽、自动行高等功能在超大列数或超大文本场景下计算量激增。
- 没有使用
BeginUpdate/EndUpdate批量操作,在批量修改、批量插入时都会导致网格不必要的多次重绘。
5.2 提升大数据量网格交互的几条实操建议
结合我自己的项目经验,下面这几条效果最明显:
- 服务端分页。永远不要试图一次性给网格灌入几十万行数据。数据库端分页后,只把当前页几百行数据返回给用户,界面流畅度会完全不一样。如果你嫌手写分页SQL麻烦,可以用数据库的OFFSET/FETCH或者第三方ORM的分页能力。
- 用
BeginUpdate/EndUpdate包住批量修改。对数据集做循环操作时,在循环外调用DisableControls,循环结束后再EnableControls,减少网格的重复刷新。 - 关闭不需要的视觉特效。关闭平滑滚动、动画效果等视觉选项,在低配置机器上能明显提升操作跟手度。
- 慎用自动行高。如果表格里有很多长文本列,自动行高会让网格为每一行计算文本高度,数据量一大就是性能灾难。建议长文本列改为固定行高,并用单元格提示(Hint)或点击弹出详情的方式展示全文。
- 延迟加载图片列。如果网格里有图片列,不要把图片一次性全部赋给列,而是在滚动或可见时再加载,或者使用缩略图缓存。
5.3 异步加载与局部刷新的实践思路
服务端分页虽然好用,但有些场景用户还是希望一次看到大量数据,比如在内存里做二次过滤。这时可以考虑异步加载方案:
- 先用后台线程从数据库拉取完整数据集。
- 拉取过程中界面显示进度条或转圈动画。
- 数据到达后,写入MemTableEh,再绑定到DBGridEh展示。
这样不会阻塞UI线程,用户在使用其他功能时数据也在后台加载。完成后的体验接近“秒开”,哪怕底层数据要跑几秒也没关系。
另一个有用的技巧是局部刷新。很多系统都有“刷新”按钮,如果一刷新就把整个数据集关闭重开,界面会闪烁,滚动位置也会丢。更好的做法是:
- 采用
DataSet.Refresh或者更精确的Locate+RefreshRecord方式。 - 如果是多用户环境,宁可增加一个“刷新时间”字段,定时只对比增量数据。
- 刷新前记录当前行的主键,刷新后
Locate回原位置。
这些优化都不是EhLib特有的,但结合EhLib做出来的效果确实更好,毕竟它的网格本身在高DPI、复杂绘制上的表现优于很多自助拼装方案。
6. 完整源码版的版权与商用注意事项,以及我的一些想法
6.1 开源不等于免费商用,Full Source不等于可以随意分发
这一点我必须在文章里单独拿出来说,因为EhLib属于商业组件,虽然有试用版,但“完整源码版”通常对应的是商业授权用户的权益。你在网上下载到的源码包,如果来源不明,请务必先确认授权范围,再决定能否用于商业项目。
从技术角度讲,完整源码的价值在于:
- 可以跟随自己的项目做定制修改。
- 可以在组件内部打日志排查问题。
- 可以裁剪不需要的功能,减小最终程序的体积。
- 可以在升级IDE版本时自行适配编译。
但从法律角度讲,这些操作通常都建立在“你已经合法获得授权”的前提下。很多商业组件的许可协议里会明确禁止在没有授权的情况下将源码用于商业软件分发。所以我的建议是:如果是个人学习、技术研究,怎么折腾都没问题;如果是公司项目商用,请走正规渠道购买授权或确认项目所在组织的合规要求。
6.2 版本升级与维护建议
无论你是从网上下载的源码包,还是通过正规渠道订阅的版本,我都建议养成一个习惯:对组件源码做本地版本管理。在解压后,立刻把原始包翻录到一个git仓库里,做好初始commit。后续如果做了定制改动,可以在单独的branch里维护,方便和官方新版本对比合并。
在项目层面,尽量不要把EhLib的版本随意升级。大版本升级前,至少要做这些事:
- 替换到测试环境,跑一遍全量自动化测试,重点看网格渲染、数据编辑、打印导出这三块。
- 留意Deprecated或行为变更的API,在release notes里通常有说明。
- 如果项目对最终文件大小敏感,关注一下编译后的体积变化。
- 升级后重启IDE,确认设计期组件正常,再动手改代码。
6.3 最后分享一点自己的体会
陆陆续续用EhLib好多年,从早期的版本一路用过来,最大的感受是:它属于那种“平时不显山露水,但一旦用惯了就很难回去”的组件。很多你觉得原生Delphi做起来很费劲的事,比如列头筛选、分组汇总、Excel导出、内嵌图表,EhLib都替你铺好了路。
当然它也不是没有短板。比如它在移动端FMX上的表现虽然够用,但和原生移动端控件比仍然有差距;又比如它的报表模块灵活度不如专门的报表工具,复杂的模板设计还得靠代码控制。但至少在我接触过的进销存、ERP、MIS这类桌面管理软件里,它确实是综合性价比很高的一套选择。
如果你手头的项目正好也需要一个能打的数据网格,并且你手上有12.0 Build 12.0.039这个版本的完整源码包,不妨先照着上面的步骤装一套,把DBGridEh的基本配置摸熟。等你把它的分组、筛选、导出这些能力都用上之后,大概率会回来感谢当年的自己。
本文还有配套的精品资源,点击获取