EhLib VCL在Delphi 12.3中的集成与DBGrid增强实战
2026/8/30 18:08:07 网站建设 项目流程

简介:在桌面数据库开发中,数据网格控件是构建高效界面的关键。原生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 换成 EhLib

1.1 原生 DBGrid 在真实业务下的短板

如果你只用过原生TDBGrid,可能觉得它也没那么难用:能显示数据、能编辑、能滚动。但一放到真实业务里,需求很快会把它的底裤扒干净。列头想点击排序?没有,得自己在OnTitleClick里写 SQL 再重查。表头下拉筛选?没有,只能靠查询区几个 Editor 组合条件。想在最下面来一行合计、平均、计数?没有,得用DBGrid的 Footer 自己绘制。单元格里想直接下拉选“启用/停用”这种固定值?也没内置,你得额外放TDBComboBox或者在OnSetEditText里绕。数据要导出到 Excel?原生控件连基础的 XLS 导出都没有,只能自己拼 CSV 或接 OLE。

单个功能缺失都能忍,加在一起就是灾难。一个稍微像样的进销存、ERP、报表系统,表格如果没有排序、筛选、统计、冻结列、下拉编辑、导出打印这一整套能力,开发成本会高到让你怀疑人生。EhLib 的价值恰恰在于它把这些高频能力全部内置到TDBGridEh里,绝大多数需求不再需要你写额外代码。

1.2 它不是单个控件,而是一整套数据表格方案

很多新人以为 EhLib 就是一个加强版 DBGrid,用起来才发现它已经长成了一整套 VCL 数据控件组:

  • TDBGridEh:核心网格控件,原生 DBGrid 的增强替代。
  • TDBLookupComboboxEhTDBNumberEditEhTDBDateTimeEditEh:配套的编辑控件,专门配合网格做单元格编辑。
  • TDBGridEhExportExcelTDBGridEhExportTextTDBGridEhExportHTML等:数据导出组件。
  • TPrintDBGridEh:网格打印预览组件,能直接出报表。
  • TMemTableEhTDataSetDriverEh:内存表与数据集驱动,用于缓存更新、本地筛选、大数据量分页处理。
  • TSQLBuilderEh等辅助组件:处理 SQL 构建相关场景。

也就是说,你从界面上放一个TDBGridEh开始,到筛选、统计、编辑、导出、打印、性能优化,基本都在同一套体系内解决,不用东拼西凑。

1.3 为什么选 Professional Edition

我这次用的是11.1.015 (Professional Edition),不是试用版也不是老版本。Professional 版对 Win32/Win64 都提供完整源码或编译好的包,支持导出 Excel、打印预览等完整功能,也没有试用版的试用期限制和功能裁剪。对于商业项目,我建议直接确认许可证是否覆盖你和客户的使用范围,别等交付阶段再补授权手续。

下面是直观对比,方便你判断要不要换:

功能点原生 TDBGridTDBGridEh
列头点击排序需手写内置排序标记与逻辑
列头下拉筛选STFilter,自动筛选或自定义
统计行/合计Footer + SumList
单元格固定下拉值PickList / 编辑按钮
冻结列仅通用固定列FrozenCols 直接设置
导出 Excel/HTML/文本一行代码调用
打印预览TPrintDBGridEh

2. 安装不是解压 rar 就完事:Delphi 12.3 下正确集成 EhLib 的流程

2.1 解压后先看目录结构,别急着把文件拖进 IDE

拿到EhLib.VCL 11.1.015 (Professional Edition).rar,解压后不要直接全选复制到 Delphi 的 Library 路径。先花几分钟看目录:

  • Source:控件所有单元源码和工程文件,也是后面要加进 Library Path 的核心目录。
  • Demo:官方示例工程。我强烈建议先跑一遍 Demo,它能直观告诉你这套控件到底能干什么,也方便你验证安装是否正确。
  • Help:帮助文档。
  • DocsReadme等:版本说明、安装说明、授权说明。

源码目录下通常能看到一堆.dpk文件,命名规律一般是:带dcl前缀的是设计期包,不带的是运行时包;对应不同 RAD Studio 版本,文件名里会带版本标识,比如EhLib120.dpkdclEhLib120.dpk这类。选 Delphi 12.x 对应的那一组,不要手滑打开其他版本的包去编译。

2.2 配置 Library Path:32 位和 64 位都要加

在 Delphi 12.3 中打开Tools > Options > Language > Delphi > Library,左侧有平台选项,常见的是32-bit Windows64-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 文件。打开后:

  1. 先确认 dpk 的Requires列表里引用的运行时包路径正确。
  2. 右键工程,选Build,把设计期包编译出来。
  3. 右键工程,选Install,让 IDE 注册组件。

如果Install按钮是灰的,通常是这个 dpk 并不是设计期包,或者编译报错没通过。先看Messages窗口里的输出。常见报错是找不到某个单元,这时回到第 2.2 节检查库路径是否配置到位。

还有个容易忽略的点:Delphi 12.3 在C:\Program Files\...这类目录下写输出文件,如果 IDE 不是以管理员权限启动,编译生成的.bpl可能写不到目标目录,导致 Install 时报文件访问被拒绝。遇到这种情况,用管理员身份重启 IDE,或者把 dpk 的输出目录改到当前用户的临时目录,再重新编译安装。

2.4 安装成功后的验证方法

组件安装完成别急着写业务代码,先做三个快速验证:

  1. 新建一个 VCL Forms 应用,打开组件面板,找到EhLib页签,确认能看到TDBGridEhTPersistent相关组件。
  2. 往 Form 上拖一个TDBGridEh,不改任何属性先编译运行,确认不报找不到.dcu.bpl的错误。
  3. 随手打开官方 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这类支持索引的数据集。如果数据量不大、一次性加载,这种方案最简单。

筛选方面,最常用的是STFilter

DBGridEh1.STFilter.Visible := True; DBGridEh1.STFilter.Local := True; DBGridEh1.STFilter.Autofilter := True;

设置后列头下方会多出一行筛选框,每列有下拉箭头,可以直接点选值或输入过滤条件。Local := True表示本地过滤,本质是 EhLib 在 DataSet 上应用FilterOnFilterRecord,你不用写 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('停用');

运行时点击该列单元格,右侧会出现下拉箭头,直接选择。如果你还需要在编辑时弹出复杂选择窗体,可以给列加EditButtons

var 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.ColumnsVisible属性。
  • 导出前最好关掉或确认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 提示找不到这个类,有的控件会变成灰色块。重新从面板拖一个放上去,保存关闭后再打开,又丢了。

根因通常有三个:

  1. 工程.dproj文件的搜索路径里显式指定了旧版 EhLib 的dcu目录,打开工程时编译器优先用旧包,而旧包与 Delphi 12.3 不兼容,导致 IDE 无法解析控件。
  2. 操作系统的PATH或 IDE 的包列表中同时存在多个版本的设计期.bpl,比如 10.4 的dclEhLib110.bpl和 12.3 的dclEhLib120.bpl,IDE 加载了错误的那个。
  3. 控件安装时没有输出到 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默认是AnsiString,Delhi 12.3 默认是UnicodeString。如果代码里把stringPChar再转回来,或者直接按字节操作字符串,会出现中文乱码或长度错误。
  • 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 := TrueSTFilter.Local := True,体验会好很多。
  • 利用TMemTableEhTDataSetDriverEh做缓存更新,批量提交回数据库。

数据量大的场景,我一般会做一个分页查询方案:每页 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里启用gioShowRowIndicatorEhgioRecNoColumn,左侧会显示行号列,方便定位数据。

  • 支持 Ctrl+F 查找:启用SearchPanel后,用户可以直接在网格里查找关键字,替代外部查询框。

  • 列宽自适应:双击列头右侧分隔线可以自动调整列宽,这个交互用户很熟悉,无需额外代码。但如果列很多,一次性调整所有列宽,可以用 `DBGrid

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

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

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

立即咨询