
简介在桌面数据库开发中数据网格控件是构建高效界面的关键。原生DBGrid虽然基础可用但在排序、筛选、统计和导出等高频需求上力不从心常需编写大量额外代码。EhLib作为一套成熟的VCL数据表格增强方案通过TDBGridEh等组件将上述能力内置化能显著提升开发效率。本文基于Delphi 12.3环境详细介绍了EhLib VCL的安装配置流程包括库路径设置、设计期包编译与授权文件部署并结合实际案例演示了列头排序、STFilter筛选、SumList合计、冻结列以及单元格下拉编辑的实现方法。同时针对工程迁移中的控件丢失、多版本冲突等问题给出了排查思路并分享了大数据量下的性能调优技巧为使用Delphi进行数据库应用开发的工程师提供一份实用的参考指南。 做 Delphi 桌面数据库开发的几乎没人能绕开 EhLib.VCL。前段时间我把一个库存管理老项目从 Delphi 10.4 迁到 Delphi 12.3界面上大量表格操作原生的 DBGrid 根本撑不住于是又把EhLib.VCL 11.1.015 (Professional Edition)这套控件翻出来装上。原本以为解压 rar、配个库路径、编译一下就完事实际折腾下来发现目录结构、设计期包、许可证、旧工程迁移这些环节每步都有坑。这篇就把我在 Delphi 12.3 上集成并使用 EhLib 的完整记录整理出来给准备装这套控件的同行作参考也聊聊数据网格增强组件到底该怎么选、怎么用、怎么调优。1. 为什么项目里我始终给 DBGrid 换成 EhLib1.1 原生 DBGrid 在真实业务下的短板如果你只用过原生TDBGrid可能觉得它也没那么难用能显示数据、能编辑、能滚动。但一放到真实业务里需求很快会把它的底裤扒干净。列头想点击排序没有得自己在OnTitleClick里写 SQL 再重查。表头下拉筛选没有只能靠查询区几个 Editor 组合条件。想在最下面来一行合计、平均、计数没有得用DBGrid的 Footer 自己绘制。单元格里想直接下拉选“启用/停用”这种固定值也没内置你得额外放TDBComboBox或者在OnSetEditText里绕。数据要导出到 Excel原生控件连基础的 XLS 导出都没有只能自己拼 CSV 或接 OLE。单个功能缺失都能忍加在一起就是灾难。一个稍微像样的进销存、ERP、报表系统表格如果没有排序、筛选、统计、冻结列、下拉编辑、导出打印这一整套能力开发成本会高到让你怀疑人生。EhLib 的价值恰恰在于它把这些高频能力全部内置到TDBGridEh里绝大多数需求不再需要你写额外代码。1.2 它不是单个控件而是一整套数据表格方案很多新人以为 EhLib 就是一个加强版 DBGrid用起来才发现它已经长成了一整套 VCL 数据控件组TDBGridEh核心网格控件原生 DBGrid 的增强替代。TDBLookupComboboxEh、TDBNumberEditEh、TDBDateTimeEditEh配套的编辑控件专门配合网格做单元格编辑。TDBGridEhExportExcel、TDBGridEhExportText、TDBGridEhExportHTML等数据导出组件。TPrintDBGridEh网格打印预览组件能直接出报表。TMemTableEh、TDataSetDriverEh内存表与数据集驱动用于缓存更新、本地筛选、大数据量分页处理。TSQLBuilderEh等辅助组件处理 SQL 构建相关场景。也就是说你从界面上放一个TDBGridEh开始到筛选、统计、编辑、导出、打印、性能优化基本都在同一套体系内解决不用东拼西凑。1.3 为什么选 Professional Edition我这次用的是11.1.015 (Professional Edition)不是试用版也不是老版本。Professional 版对 Win32/Win64 都提供完整源码或编译好的包支持导出 Excel、打印预览等完整功能也没有试用版的试用期限制和功能裁剪。对于商业项目我建议直接确认许可证是否覆盖你和客户的使用范围别等交付阶段再补授权手续。下面是直观对比方便你判断要不要换功能点原生 TDBGridTDBGridEh列头点击排序需手写内置排序标记与逻辑列头下拉筛选无STFilter自动筛选或自定义统计行/合计无Footer SumList单元格固定下拉值无PickList / 编辑按钮冻结列仅通用固定列FrozenCols 直接设置导出 Excel/HTML/文本无一行代码调用打印预览无TPrintDBGridEh2. 安装不是解压 rar 就完事Delphi 12.3 下正确集成 EhLib 的流程2.1 解压后先看目录结构别急着把文件拖进 IDE拿到EhLib.VCL 11.1.015 (Professional Edition).rar解压后不要直接全选复制到 Delphi 的 Library 路径。先花几分钟看目录Source控件所有单元源码和工程文件也是后面要加进 Library Path 的核心目录。Demo官方示例工程。我强烈建议先跑一遍 Demo它能直观告诉你这套控件到底能干什么也方便你验证安装是否正确。Help帮助文档。Docs、Readme等版本说明、安装说明、授权说明。源码目录下通常能看到一堆.dpk文件命名规律一般是带dcl前缀的是设计期包不带的是运行时包对应不同 RAD Studio 版本文件名里会带版本标识比如EhLib120.dpk、dclEhLib120.dpk这类。选 Delphi 12.x 对应的那一组不要手滑打开其他版本的包去编译。2.2 配置 Library Path32 位和 64 位都要加在 Delphi 12.3 中打开Tools Options Language Delphi Library左侧有平台选项常见的是32-bit Windows和64-bit Windows。把解压后的Source目录分别添加到这两个平台的Library path中。这一步的作用是让 IDE 在编译时能找到 EhLib 的.dcu文件和单元源码。你可能会问32 位平台配置我能理解为什么 64 位也要加因为 Delphi 12.3 的 IDE 本身是 32 位进程但你的目标平台可能是 Win64。运行期包需要在 Win64 下编译链接 EhLib 的 64 位版本找不到.dcu就会报File not found: DBGridEh.dcu。所以两个平台都加避免后面切换 Target Platform 时一头雾水。另外注意搜索路径的排序如果你机器里还装了旧版 EhLib或者 Delphi 默认路径下有同名.dcu最好把 11.1.015 的 Source 路径放在前面避免编译器先找到旧版本的文件。2.3 编译并安装设计期包配置完库路径接下来打开设计期包。在 IDE 的Project Manager或直接File Open打开Source下带dcl前缀、对应 Delphi 12.x 的 dpk 文件。打开后先确认 dpk 的Requires列表里引用的运行时包路径正确。右键工程选Build把设计期包编译出来。右键工程选Install让 IDE 注册组件。如果Install按钮是灰的通常是这个 dpk 并不是设计期包或者编译报错没通过。先看Messages窗口里的输出。常见报错是找不到某个单元这时回到第 2.2 节检查库路径是否配置到位。还有个容易忽略的点Delphi 12.3 在C:\Program Files\...这类目录下写输出文件如果 IDE 不是以管理员权限启动编译生成的.bpl可能写不到目标目录导致 Install 时报文件访问被拒绝。遇到这种情况用管理员身份重启 IDE或者把 dpk 的输出目录改到当前用户的临时目录再重新编译安装。2.4 安装成功后的验证方法组件安装完成别急着写业务代码先做三个快速验证新建一个 VCL Forms 应用打开组件面板找到EhLib页签确认能看到TDBGridEh、TPersistent相关组件。往 Form 上拖一个TDBGridEh不改任何属性先编译运行确认不报找不到.dcu或.bpl的错误。随手打开官方 Demo 工程编译运行直接看效果。我见过不少同行装完后不验证直接打开旧工程一打开表单就提示找不到TDBGridEh再回头折腾安装。先跑 Demo 能省出大量排查时间。注意EhLib 组件安装后第一次在窗体上放置控件时可能弹出版权或授权提示对话框。Professional 版会检查授权文件中登记的版本和用户信息。这个提示正常说明授权状态已加载但如果编译工程时报缺少授权文件就需要按文档把授权文件放到指定目录而不是去代码里绕关闭。3. 上项目最先用的核心功能筛选、统计行、冻结列与单元格下拉装好控件后我通常用一个“商品库存表”的案例来验证功能商品编码、名称、分类、库存数量、单价、金额、状态。这 7 个列基本覆盖了日常开发的大部分场景下面逐个说怎么用 EhLib 实现。3.1 列头排序与筛选下推的方式选择原生 DBGrid 想点击列头排序得自己在OnTitleClick里写 SQL 重新查询用 EhLib 可以简化DBGridEh1.OptionsEh : DBGridEh1.OptionsEh [dghAutoSortMarking]; DBGridEh1.SortLocal : True;dghAutoSortMarking会在列头显示排序箭头点击列头触发排序。SortLocal : True表示数据在本地 DataSet 中排序适合TClientDataSet这类支持索引的数据集。如果数据量不大、一次性加载这种方案最简单。筛选方面最常用的是STFilterDBGridEh1.STFilter.Visible : True; DBGridEh1.STFilter.Local : True; DBGridEh1.STFilter.Autofilter : True;设置后列头下方会多出一行筛选框每列有下拉箭头可以直接点选值或输入过滤条件。Local : True表示本地过滤本质是 EhLib 在 DataSet 上应用Filter或OnFilterRecord你不用写 SQL 就能看到筛选结果。但如果数据量大比如百万级建议把Local设为False在OnFilterRecord里只做展示层过滤或者干脆把筛选条件拼进 SQL 做服务端查询。本地筛选在处理大数据量时每过滤一次就要全表扫一遍卡顿是必然的。3.2 统计行与合计SumList 才是计算核心要给网格底部加合计行很多人第一反应是写循环累加其实 EhLib 原生支持DBGridEh1.FooterRowCount : 1; DBGridEh1.SumList.Active : True; DBGridEh1.Columns[5].Footer.ValueType : fvtSum; // 金额列 DBGridEh1.Columns[5].Footer.Value : 合计; DBGridEh1.Columns[4].Footer.ValueType : fvtCount; // 库存数量列统计个数SumList.Active : True是这里最容易漏的一步。如果只设置Footer.ValueType而不激活SumList底部的合计不会自动算出来页面上只会显示你手动塞进Footer.Value的文字。Footer.ValueType支持fvtSum求和、fvtAvg平均、fvtCount计数、fvtMax最大值、fvtMin最小值。实际项目中我经常给合计行再加一行“平均”只要把FooterRowCount : 2第二行的ValueType设置成fvtAvg即可。3.3 冻结列让关键信息固定不动表格横向滚动时商品编码和商品名称这两列最好始终可见。EhLib 里一行搞定DBGridEh1.FrozenCols : 2;这样前两列会固定横向滚动时其他列移动这两列保持不动。注意FrozenCols最好不要超过表格列数的三分之一否则右侧显示区太窄反而影响体验。3.4 单元格下拉值与行内快捷编辑“状态”列只有“启用/停用”两个固定值用PickList最方便DBGridEh1.Columns[6].PickList.Add(启用); DBGridEh1.Columns[6].PickList.Add(停用);运行时点击该列单元格右侧会出现下拉箭头直接选择。如果你还需要在编辑时弹出复杂选择窗体可以给列加EditButtonsvar Btn: TEditButtonEh; begin Btn : DBGridEh1.Columns[2].EditButtons.Add; Btn.Style : ebsGlyphEh; // 显示小按钮 Btn.Caption : ...; Btn.OnClick : SelectCategory; end;这里SelectCategory是自定义事件可以在其中弹出一个分类选择窗体选完后把值写回当前字段。这种交互比让用户手动输入分类编码要可靠得多。3.5 行高亮与搜索面板业务表一旦超过几十行当前行是哪一行经常看不清。打开当前行高亮能明显提升体验DBGridEh1.OptionsEh : DBGridEh1.OptionsEh [dghRowHighlight];另外EhLib 的SearchPanel也很好用DBGridEh1.SearchPanel.Visible : True;启用后表格顶部会出现一个搜索框用户输入字符即可在可见列内快速定位匹配记录。这个功能在单据明细、商品列表里非常实用。4. 报表周边Excel 导出、打印预览和格式化的实际姿势4.1 一行代码导出 Excel但要注意调用位置EhLib 的导出能力是很多人选择它的直接原因。在uses里加入DBGridEhImpExp然后SaveDBGridEhToExportFile(TDBGridEhExportExcel, DBGridEh1, D:\报表\库存表.xlsx, True);第三个参数是文件名第四个True表示导出为xlsx格式False则导出为老版xls。这个函数会根据网格当前显示的列、字段、样式直接生成 Excel 文件表头、数据、合计行都会被带过去。有几个细节我需要提醒导出的列范围默认是网格当前可见列。如果想导出指定列先配置DBGridEh1.Columns的Visible属性。导出前最好关掉或确认STFilter的筛选状态。因为用户可能已经筛选过数据导出的是筛选结果还是全量数据取决于你业务上的需求别默认。如果目标是xlsx某些旧版 Office 环境可能打不开需要确认客户环境实在不行导出xls兼容性更广。导出按钮点击后界面会短暂卡顿数据量大时建议放到后台线程并通过DBGridEh1的快照数据导出避免用户在导出过程中修改数据源导致不一致。另外很多人出现“导出 Excel 乱码”的问题多半是把SaveDBGridEhToExportFile的导出类型写成了文本类组件比如TDBGridEhExportText然后用.xlsx扩展名保存。EhLib 的文本导出是给 CSV、TXT 用的并不是真正的 Excel 二进制文件。4.2 打印预览与分页打印需求我一般用TPrintDBGridEh组件来处理PrintDBGridEh1.DBGridEh : DBGridEh1; PrintDBGridEh1.SetParam; PrintDBGridEh1.Preview;Preview会打开内置的预览窗口用户可以在里面调整缩放、翻页、直接打印。SetParam是按当前网格的列宽、字体等参数生成打印样式。实际使用中有几个经验中文显示乱码或字号偏小先检查PrintDBGridEh1的字体设置最好在BeforePrint事件里统一指定中文字体。数据量很大时如果不设置分页参数所有行可能挤在一张纸上。建议设置每页行数或者在数据源层面分批加载。打印列宽和屏幕列宽经常不一致打印前用SetParam并按纸张宽度重新计算列宽比例。4.3 用 OnGetCellParams 做条件颜色和重点标识业务表格里“库存数量低于安全值”的行标红是特别常见的要求。EhLib 的事件里加判断就行procedure TForm1.DBGridEh1GetCellParams(Sender: TObject; Column: TColumnEh; AFont: TFont; var Background: TColor; State: TGridDrawState); begin if (Column.FieldName 库存数量) and (Column.Field.AsInteger 10) then begin Background : $00D7D7FF; // 浅红 AFont.Style : AFont.Style [fsBold]; end; end;这个事件每个单元格绘制时都会触发所以里面尽量只做简单判断和赋值不要做字符串拼接、数据库查询这类耗时操作否则表格滚动时会明显掉帧。5. 从老工程迁移到 12.3 的那些坑控件丢失、包冲突与许可证5.1 为什么 IDE 每次打开工程都提示丢失控件搜索热词里有一条很典型“delphi 控件版本问题 导致 每次进入ide都丢失控件需要重新放置保存后还是那样”。这个问题我在迁移工程时也踩过而且往往不是 EhLib 本身的问题而是环境里存在多个版本残留。具体表现是用 Delphi 12.3 打开一个旧工程Form 上放了TDBGridEh但 IDE 提示找不到这个类有的控件会变成灰色块。重新从面板拖一个放上去保存关闭后再打开又丢了。根因通常有三个工程.dproj文件的搜索路径里显式指定了旧版 EhLib 的dcu目录打开工程时编译器优先用旧包而旧包与 Delphi 12.3 不兼容导致 IDE 无法解析控件。操作系统的PATH或 IDE 的包列表中同时存在多个版本的设计期.bpl比如 10.4 的dclEhLib110.bpl和 12.3 的dclEhLib120.bplIDE 加载了错误的那个。控件安装时没有输出到 IDE 的默认 BPL 目录而是自定义目录但自定义目录没有被加入系统的 DLL 搜索路径IDE 启动时加载不到。排查路径先看Project Options Delphi Compiler Search path把旧版 EhLib 路径全部删掉确保只保留 11.1.015 的 Source 路径。打开Tools Options Language Delphi Library检查有没有多个 EhLib 版本路径删除过时的。打开Component Install Packages查看已安装包列表卸载所有旧版dclEhLib...只保留当前版本。重启 IDE再打开工程。如果你的工程文件是版本管理工具里的旧工程改完.dproj后建议检查一下是否被版本管理工具回滚别保存了半天第二天同事一拉代码又变成旧配置。5.2 从 Delphi 7 / 2007 工程迁过来别直接用旧 dcu网上搜索热词里还有“ehlib delphi 7 下载”说明还有不少老工程在用 Delphi 7。从 Delphi 7 迁移到 Delphi 12.3不仅仅是控件版本问题还牵扯到编译器的 Unicode 变化Delphi 7 时代string默认是AnsiStringDelhi 12.3 默认是UnicodeString。如果代码里把string转PChar再转回来或者直接按字节操作字符串会出现中文乱码或长度错误。EhLib 各版本 API 总体兼容但某些函数、属性名在 11.x 里调整过。老代码里如果直接调用了内部单元或私有方法升级后大概率编译不过。从 Delphi 7 的 32 位工程迁到 Delphi 12.3 的 Win64指针大小、结构体对齐方式都会变化涉及记录类型或 Windows API 调用时要重新核对。针对这类工程我的建议是先用一个临时分支把 EhLib 升级到 11.1.015只做最小改动编译通过再逐个表单检查功能。不要一次性把所有 DBGrid 都换成 DBGridEh风险太大。5.3 Professional 版授权文件的正确部署Professional 版有版权检查机制安装后第一次使用如果提示“License not found”或“Unregistered”通常是因为许可证文件没放到正确位置。官方一般会把授权文件放在压缩包的某个目录里或者提供注册工具。把授权文件复制到 EhLib 安装目录或用户目录下重启 IDE 即可。不要尝试去绕授权或者删掉检查代码商业开发中授权合规必须重视否则后续维护和交付都有风险。6. 大数据量下的性能调优和几个易忽略的界面细节6.1 查询与数据集层面把筛选下推到数据库EhLib 本身能处理几万行的数据但如果数据量到几十万甚至百万网格再流畅也只是把压力后置了。我见过不少项目SQL 上来就是SELECT * FROM 表然后靠 DBGridEh 本地筛选用户一查询整个客户端内存飙到几百 MB滚动卡成 PPT。正确做法是在数据源层做控制SQL 只 SELECT 必要字段不要SELECT *。字段越少数据传输和内存占用越少。把排序、筛选、分页都下推到数据库。EhLib 的STFilter可以作为 UI 输入但事件回调里要拼 SQL 的参数化条件而不是把所有行拉下来本地过滤。如果必须一次性加载用TClientDataSet建好索引再配合SortLocal : True和STFilter.Local : True体验会好很多。利用TMemTableEh和TDataSetDriverEh做缓存更新批量提交回数据库。数据量大的场景我一般会做一个分页查询方案每页 200 条翻页时重新从数据库取当前页。这样 UI 响应快也避免了内存暴涨。6.2 网格绘制层面的优化有些性能问题不在数据源而在绘制层。以下几点是我实测效果明显的尽量减少OnGetCellParams里的复杂逻辑。这个事件在每个单元格绘制时都会触发里面做个字符串拼接、正则匹配整表几百行时就能感觉到卡。关闭不必要的特效。如果行数多把DBGridEh1.OptionsEh里的dghRowHighlight这种逐格高亮效果去掉或者改为简单的选中行高亮。合理设置RowHeight和列宽。很多表格卡顿是因为行高、列宽在尺寸变化时频繁重绘。固定行高能减少布局计算量。“子控件间距”这个搜索热词对应的其实是网格中列间距、单元格边距的调整。EhLib 中可以通过DBGridEh1.Columns[i].Width和全局的DBGridEh1.GridLineWidth配合来调视觉间距但不要把边距设得过大否则单元格内容显示不全还会增加绘制开销。6.3 那些用了就回不去的小配置最后分享几个提高使用体验但很多人不知道的小细节空数据提示数据集没有记录时网格默认是空白一片。设置一个提示文案会友好很多。DBGridEh1.EmptyDataInfo.Active : True; DBGridEh1.EmptyDataInfo.TextHint : 暂无数据;显示行号在DBGridEh1.IndicatorOptions里启用gioShowRowIndicatorEh和gioRecNoColumn左侧会显示行号列方便定位数据。支持 CtrlF 查找启用SearchPanel后用户可以直接在网格里查找关键字替代外部查询框。列宽自适应双击列头右侧分隔线可以自动调整列宽这个交互用户很熟悉无需额外代码。但如果列很多一次性调整所有列宽可以用 DBGrid本文还有配套的精品资源点击获取