简介这是面向 Delphi 11 开发者的 EhLib 10.0.031 组件库内置数据网格、报表设计、图像处理、图表分析等模块可有效扩展原生控件能力适合中高级开发者在数据库应用、管理信息系统等场景中提升构建效率。资源包共 890 个文件以 dfm 窗体文件、pas 单元源码、res 资源、dpr 工程文件为主并含 dcu 编译单元、chm 帮助和 doc 文档整体体积 24.63MB结构清晰便于按需取材。已有 885 人参与学习下载。此版本已在 Delphi 11.1.5 下安装验证install 目录内置安装程序同时附带完整源代码开发者既能直接部署也可深入修改控件行为或增加自定义功能。配套示例和文档覆盖数据库连接、报表输出、图表联动等典型场景报表支持导出 PDF、HTML、Excel有助于快速上手并减少重复开发调试成本。1. 为什么 Delphi 11 项目还在用 EhLib网格控件的成熟度与习惯问题做 Delphi 桌面开发的人几乎都绕不开一个问题项目里默认的 TDBGrid 太“素”了不光是外观不好看连常见的过滤、分组、统计合计都要自己写事件。EhLib 这个 Delphi 网格控件库就是拿来补这一块的——它目标明确让 DBGrid 类表格直接支持列标题过滤、标题栏分组、合计行、单元格下拉、多选导出 Excel 等能力不需要你额外拼拼凑凑。我手里这份 EhLib 10.0.031 For Delphi 11对应的是 Delphi 11 下的 VCL 版本实际使用中省掉的代码量相当可观。它适合谁适合正在维护老项目、想把界面升级但又不想换掉现有 TDataSet 体系的开发者也适合新项目直接用它做主表格把精力留给业务逻辑。下面从安装、运行到踩坑按我实际拆这版组件包的顺序给你过一遍。2. 安装与编译检查目录结构、Install.bat 与托盘图标2.1 解压后先别急着双击安装脚本先看目录结构拿到 EhLib 10.0.031 的压缩包解压后第一件事不是运行 Install.bat而是把目录结构翻一遍。这个包通常分几个关键目录源码目录含各版本 Delphi 对应的 .dpk 工程文件、已编译的 BPL/DCP 目录、Demo 目录和帮助文档目录。Delphi 11 对应的源码子目录名一般带版本特征比如带 RS 前缀的文件夹直接对应 IDE 的安装路径下的 Library 文件夹。我第一次装的时候没注意直接双击了根目录的 Install.bat结果脚本找错了编译器版本弹了一串找不到 Package 的错。后来养成习惯先把目录列表展开看一遍确认哪个子目录对应 Delphi 11再动安装脚本。目录/文件作用我的处理方式Lib\RSSDelphi 11 对应的源码与包工程直接从这里找 .dpkBin已编译的 BPL/DCP用于确认版本号若与源码不一致则重新编译Demo官方示例工程排查问题时先看对应 Demo 的配置Install.bat一键安装脚本只作为默认入口异常时改用 IDE 手动编译这里补充一个判断依据EhLib 的免费版和旧版本包在 Delphi 11 下编译时最容易出现“找不到 dclEhLib 包”的问题多数是因为 IDE 的 Library 路径里没有把源码目录加进去。所以我现在的做法是不管用不用 Install.bat都会先在 IDE 的 Tools Options Library 里确认源码路径存在否则后面打开窗体设计器时会有人为制造的“黑匣子”感——明明包装上了但组件面板里就是不出图标。2.2 安装脚本的实际执行路径与参数理解我一般在 Windows 下用命令行执行安装方便看完整输出不用管 IDE 的日志窗口。打开“开发者命令提示符”或用普通管理员终端切到解压目录执行cd /d D:\Dev\Components\EhLib\10.0.031 Install.bat执行前注意这条命令需要管理员权限因为要往 IDE 的安装目录里写 BPL 文件另外当前终端的工作目录必须是解压根目录脚本里大多用相对路径找 .dpk。跑完脚本后提示“Done”并不代表万事大吉还要返回 IDE 里确认两件事Component Install Packages 列表里是否出现 EhLib 相关的设计期包以及组件面板Tool Palette里搜索框输入 Eh 能不能搜到 TDBGridEh。大多数“装完没反应”的情况都是脚本压根没找到 Delphi 11 的注册表路径直接跳到下一步了。如果 Install.bat 中途报“F1027 Unit not found”之类的错常见原因不是包坏了而是 IDE 的 Library 路径里缺少公共依赖目录比如旧版本组件包留下的 DCP 目录。解决方法是打开 IDE 的 Library 配置把解压根目录里的 Lib 子目录加进去然后重新 Build All。这块很玄学的一点是顺序会影响结果——源码目录要在 BPL 输出目录之前。2.3 托盘图标与设计期授权的确认方法安装成功后先在项目里随便放一个 TDBGridEh再放一个 TDataSource把 DataSource 接上此时看 IDE 的组件面板或对象树里有没有托盘图标组件左上角小图标带绿色小勾来判断设计期授权是否正常。10.0.x 系列对 Delphi 11 的支持比较完整如果组件显示为灰色或编译报“Component class not found”基本可以判断是设计期包没加载而不是控件本身有问题。我习惯用一段最简代码做安装自检新建一个 VCL 工程放一个 DBGridEh然后在 FormCreate 里打印版本号procedure TForm1.FormCreate(Sender: TObject); begin Caption : EhLib DBGridEh1.VersionInfo.Version; end;这段代码不复杂但能一次性验证三件事设计期控件是否可用、运行期包是否正确打进 exe、版本号是否与 10.0.031 一致。看到标题栏显示 10.0.031 就放心继续。注意VersionInfo 属性在包编译选项不对时可能会丢此时编译能过但运行流编译报错需要回查包输出目录权限。3. 把数据接进来连接、列配置与统计行列出的最小可运行工程3.1 用内存数据集搭一个最小复现场景很多 Delphi 开发者拿到新组件后第一件事不是接数据库而是先拿内存数据集跑通流程。EhLib 的优势就在于它处理的是 TDataSet 抽象不挑数据源。我常用 TClientDataSet 搭最小可运行工程代码清爽又不用装数据库procedure TForm1.FormCreate(Sender: TObject); var Cds: TClientDataSet; begin Cds : TClientDataSet.Create(Self); Cds.FieldDefs.Add(OrderNo, ftString, 16); Cds.FieldDefs.Add(Amount, ftCurrency); Cds.FieldDefs.Add(Status, ftString, 4); Cds.CreateDataSet; Cds.AppendRecord([D2024001, 128.50, 已支付]); Cds.AppendRecord([D2024002, 98.00, 待处理]); Cds.AppendRecord([D2024003, 256.00, 已支付]); Cds.First; DataSource1.DataSet : Cds; DBGridEh1.DataSource : DataSource1; end;逻辑说明这段代码先创建内存数据集并显式定义三个字段的类型和长度避免后续 EhLib 列类型推断出错。AppendRecord 是快速录入测试数据的简写方式参数顺序与 FieldDefs 声明顺序一致。最后把 DataSource 指向数据集DBGridEh 再指向 DataSource完成最基本的绑定。参数说明ftString 的 16 表示字符长度ftCurrency 是金额类型带上它之后 EhLib 的合计行默认会按数值格式汇总不会出现字符串拼接的尴尬Status 字段用 ftString 而不是布尔类型是为了后面演示过滤菜单时更直观。如果你要套自己的业务表把 FieldDefs 换成实际字段名即可。3.2 列配置为什么我建议在设计期把 Columns 写死在 DBGridEh 里可以像普通 DBGrid 一样让它自动生成列但我建议你在设计期就打开 Columns 编辑器把列逐一定义清楚。原因很直接自动生成列时字段类型和显示标题的默认值经常不如意而且如果数据集字段顺序调整了界面跟着乱跳。下面这段代码是运行期清空并重配列的示例DBGridEh1.Columns.Clear; with DBGridEh1.Columns.Add do begin FieldName : OrderNo; Title.Caption : 订单号; Width : 90; end; with DBGridEh1.Columns.Add do begin FieldName : Amount; Title.Caption : 金额; Width : 100; Footer.ValueType : Sum; Footer.FieldName : Amount; end;逻辑说明先清空默认列再手动添加两列。第一列绑定订单号字段宽度 90 像素第二列绑定金额字段并设置了底部分组统计行Footer的汇总类型为 Sum。这里的 ValueType 是 EhLib 特有的属性不设置就只是一个空行设置了后运行时会自动对数据集当前过滤范围内的数值求和。参数说明Footer.FieldName 必须与当前列的 FieldName 一致否则合计值会从别的字段取值。Sum 是内置统计类型内部通过 Field 的 AsFloat 累加如果字段是字符串类型这里会报类型转换错。Width 单位是像素标题栏按中文显示时建议留 20% 余量不然“订单号”三个字会被截断。3.3 让合计行随过滤条件联动起来这是 EhLib 比较关键的一个特性也是很多人没发现的默认情况下 Footer 统计的是整个数据集不是你筛选后的数据。如果你在列标题上做了过滤统计行不会自动只算过滤结果。要让合计行和过滤联动需要设置DBGridEh1.FooterRowCount : 2; DBGridEh1.FooterParams.FillStyle : cfstSolid; DBGridEh1.OptionsEh : DBGridEh1.OptionsEh [dghFooterMultiRow];逻辑说明FooterRowCount 设为 2表示底部预留两行统计行其中一行显示当前过滤结果合计另一行可以显示全部数据合计这样能直观对比筛选前后的变化。FillStyle 控制统计行的底色填充可选值里 cfstSolid 是纯色填充配合 FooterColor 使用。OptionsEh 是 EhLib 的增强选项集合dghFooterMultiRow 是启用多行统计列的关键开关不打开的话即使 FooterRowCount 设了 2 也不会出现多行效果。参数说明这个多行统计的语义比单个 Sum 要复杂一点第一行的 ValueType 仍然以当前过滤集为准第二行若想显示全量合计需要把对应列的 Footer.ValueType 设为全局统计类型比如用 dghFooterGlobalSum 相关的选项。这块我一开始翻过车以为多行就是叠加显示结果发现第二行始终是 0后来查文档才知道全局合计需要单独指定。3.4 从 Demo 工程抄配置最快熟悉路径如果你不想从零配一遍直接打开包里的 Demo 目录找一个叫 GridTester 或类似名字的工程不同版本目录名略有差异编译运行后能看到过滤、分组、排序、合计、树形展示全开的效果。我对照 Demo 工程看过之后才发现自己手动配置漏掉了一个重要属性AutoFilterMenu 相关选项默认不是全开的标题栏上的过滤小图标需要靠 OptionsEh 里的 dghFilterMenu 开启。这一步留到第 4 章细说。4. 免写 SQL 的交互能力自动过滤、标题分组与单元格按钮的配置4.1 打开标题栏过滤菜单一个选项的事EhLib 最让开发省心的地方是标题栏自带过滤下拉菜单。数据库层面不用写 WHERE控件内部会把当前条件作用于数据集。开启方式是DBGridEh1.OptionsEh : DBGridEh1.OptionsEh [dghFilterMenu]; DBGridEh1.Filtered : True;逻辑说明OptionsEh 是 EhLib 的增强选项集合dghFilterMenu 表示允许在列标题上显示过滤按钮点击后弹出条件选择。这里的 Filtered 属性必须设为 True它和数据集自身的 Filtered 不太一样——EhLib 用它来标识“当前网格有激活的过滤条件”如果不打开即使弹出了过滤菜单选择条件后也不会应用。参数说明过滤菜单里默认支持“等于 / 不等于 / 包含 / 大于 / 小于”等比较条件对字符串字段常用“包含”对数值字段建议用“介于某区间”。此时建议配合 Dataset 的 IndexFieldNames 或排序机制使用否则在数据量超过几万行时会出现明显卡顿。我一般会给大数据集加上 IndexFieldNames : OrderNo让过滤走索引而不是全表扫。4.2 标题栏分组让数据按字段折叠标题栏分组是另一个高频需求效果类似 Excel 的分组透视。用户把列标题拖到网格上方的分组区域数据就会按该字段分组组之间可以折叠展开。这个功能默认不显示分组区域需要设置DBGridEh1.GroupPanelVisible : True; DBGridEh1.TitleParams.GroupColMarked : True;逻辑说明GroupPanelVisible 决定分组拖拽区是否显示在上方TitleParams.GroupColMarked 会让被分组的列标题上出现标记图标提醒用户当前列已作为分组字段。配合下面的事件可以控制双击组标题时的展开折叠行为。参数说明标题分组依赖数据集排序如果数据没有按分组字段排好显示上会出现同组数据分散的情况。所以实际操作中要把 DBGridEh1.SortLocal 设为 True或者直接在 TDataSet 的 IndexFieldNames 里指定分组字段。一个常见误用是设置 SortLocal 后本地排序会自动调用数据集的 Sort 方法此时如果数据集是只读模式会抛出异常。4.3 用单元格按钮代替双击事件业务里经常需要“查看详情”按钮EhLib 可以在单元格里嵌入按钮不需要你手动放一个 TButton 再对齐位置。我用 TitleBtnClick 事件来实现标题按钮的点击处理procedure TForm1.DBGridEh1TitleBtnClick( ADataCol: Integer; AButton: TTitleButtonEh); begin if AButton tbtFilter then begin // 用户点击了过滤按钮这里只记录日志实际过滤由控件内部处理 Log(列 IntToStr(ADataCol) 触发了过滤菜单); end else if AButton tbtGroup then begin // 用户点击分组按钮切换当前列的折叠状态 DBGridEh1.ApplyGrouping(True); end; end;逻辑说明TitleBtnClick 是标题栏按钮的统一回调ADataCol 是列索引AButton 是按钮类型枚举。tbtFilter 对应过滤按钮tbtGroup 对应分组按钮。通过判断枚举值可以在外部做一些联动比如过滤时刷新另一个 Grid 的统计项分组时调整其他面板的可见性。参数说明ApplyGrouping(True) 是 EhLib 提供的快捷方法传入布尔值表示是否在网格上方显示分组面板。如果你希望在运行时动态创建“查看详情”按钮则需要用到 OnDrawColumnCell 事件但这个事件绘制的是单元格内容和标题按钮不是一回事。两处不要混用。4.4 下拉列表列的配置细节单元格下拉列表也是 DBGridEh 的亮点用 PickList 实现最简单with DBGridEh1.Columns[2] do begin PickList.Clear; PickList.Add(待处理); PickList.Add(已支付); PickList.Add(已取消); EditStyle : esPickList; end;逻辑说明指定第三列为下拉列表样式用户在编辑时不会直接输入自由文本而是从 PickList 的预设值中选择。EditStyle 的值设为 esPickList 后控件在进入编辑状态时自动显示下拉列表。参数说明注意 PickList 是 TStrings 类型这里用 Clear 和 Add 填充顺序会影响下拉显示顺序。esPickList 编辑样式适合枚举类字段如果你需要可输入也可选择应改为 esAutoDropDown。还有个细节如果数据集不是可编辑状态下拉列表会直接变成灰色。5. 避坑清单升级网格控件后最容易翻车的五个场景5.1 现象整数列显示成带小数点的金额导入 10.0.031 后我把原来 DBGrid 里的整数字段直接映射到 DBGridEh运行后发现数量列显示成“1.00”而不是“1”。原因是 EhLib 根据字段类型做隐式格式转换整型字段在某些区域设置下被当成浮点处理。解决方法是显式设置列的 DisplayFormat 属性DBGridEh1.Columns[0].DisplayFormat : 0;这行代码把格式化模板改为整数格式不再输出小数点。顺带提醒Currency 类型的字段建议用 #,##0.00 的模板避免出现“1.2”这种不规整的显示。5.2 现象滚动大数据集时卡顿明显我在一个两万行左右的订单表上测试过滤 排序滚动明显掉帧CPU 占满一个核。排查后发现这不是 EhLib 的网格绘制问题而是数据集没有索引过滤时走全表扫描。解决路径先给数据集加索引再打开网格的缓存绘制选项Cds.IndexFieldNames : OrderNo;OrderDate; DBGridEh1.OptionsEh : DBGridEh1.OptionsEh [dghClearSelection];IndexFieldNames 的字符串语法是字段列表分号分隔dghClearSelection 代表每次滚动后清空选中状态减少刷新开销。这块算是我踩过的比较典型的性能坑不是组件库的问题而是用组件的姿势问题。5.3 现象导出 Excel 后第一行是空的用 DBGridEh 自带的导出功能导出到 Excel打开文件发现第一行没有列标题数据直接从第二行开始。原因是列标题的 Caption 与 FieldName 不一致导出器默认按字段名生成表头而字段名里如果带下划线或非英文字符Excel 会做兼容处理。解决方法是导出前指定要用 Title.CaptionDBGridEh1.ExportAsText : False; EhDBGridExportor1.Grid : DBGridEh1; EhDBGridExportor1.ExportToExcel;逻辑说明EhDBGridExportor 是 EhLib 配套的导出器组件把它的 Grid 属性指向当前网格然后直接调用 ExportToExcel。导出内容默认优先使用 Title.Caption 作为 Excel 表头前提是标题列的 Caption 已设置。我在项目里的经验是导出前先把所有列的 Title.Caption 检查一遍否则后续调格式很痛苦。5.4 现象运行时找不到“dclEhLib”设计期包编译项目时报错“Cannot load package dclEhLib”但安装脚本明明提示成功。这个现象多半是 IDE 里同时残留了旧版组件包新包和旧包的类名冲突。解决方法是在 Component Install Packages 里把旧版本 EhLib 的卸载掉重启 IDE再手动添加新版本的 BPL。注意卸载包之前要先把工程里的相关控件引用删掉否则 IDE 打开窗体时会提示找不到类。5.5 现象分组统计行的合计值翻倍计算设置分组后Footer 里的 Sum 值变成了数据实际数值的两倍。这个翻车现场我印象很深原因是我在数据集上同时加了 Aggregate 字段求和又在 Grid 的 Footer 里做了 Sum两个求和逻辑叠加。解决办法是砍掉一个要么用数据集自己的 Aggregate 并隐藏统计列要么全部交给 Grid 的 Footer 处理。我的习惯是统一让 EhLib 的 Footer 处理因为它天然跟随过滤和分组不需要额外同步。6. 再进一步把 Grid 的列状态落盘让每次打开都井然有序DBGridEh 有一个容易被忽略的实用功能把列宽、排序方向、过滤条件、分组状态保存到 Ini 文件下次打开程序时一键恢复。这个功能对维护型项目特别有用用户调好的列宽不用每次重排。我用下面的代码在窗体关闭时保存状态var Ini: TIniFile; begin Ini : TIniFile.Create(ChangeFileExt(Application.ExeName, .ini)); try DBGridEh1.SaveGridLayoutInIni(Ini, GridMain, False); finally Ini.Free; end; end;逻辑说明SaveGridLayoutInIni 是 DBGridEh 的实例方法第一个参数是 Ini 文件对象第二个参数是保存的节点名多个 Grid 可以用不同节点避免相互覆盖第三个参数表示是否保存列宽以外的高级设置False 表示只保留常规布局。恢复时用 LoadGridLayoutFromIni 反向调用即可。参数说明保存节点的命名建议和业务表单绑定比如“订单列表”、 “对账明细”这样同一个 Ini 文件可以容纳多个 Grid 的状态。官方 Demo 里对这种用法有完整示例建议直接抄比自己造轮子稳。从那以后我每次升级组件库版本都会强制走一遍测试集先跑安装自检、再跑最小数据集过滤合计、最后检查列状态保存是否正常。这套流程排掉了 90% 的隐性故障希望帮到你。本文还有配套的精品资源点击获取