
简介EhLib 10.0.031 是面向 Delphi 11 开发者的第三方组件库资源适合需要快速构建图形处理、数据库应用与报表系统的中高级开发者使用。该版本已在 Delphi 11.1.5 环境下验证可正常安装运行核心价值在于提供图像查看与格式转换、多数据库连接与查询、报表设计预览打印、图表可视化以及工具栏菜单等界面增强组件并附带完整源码便于二次开发与功能扩展。压缩包共 890 个文件以 302 个 dfm 窗体文件、299 个 pas 源码单元、70 个 res 资源文件、55 个 dpr 工程文件及 30 个 dcu 编译单元为主另含 doc、chm 帮助文档与示例数据库整体约 24.63MB安装程序位于 install 文件夹内。目前已有 886 人学习下载读者可据此获得一套可直接集成到 Delphi 11 项目的组件源码与配套文档用于理解组件实现原理、按项目需求裁剪修改并借助示例快速上手图形、数据库与报表相关功能。1. EhLib 10.0.031 在 Delphi 11 里到底能省多少事上周有个做设备管理系统的朋友发来一段录屏一个用 Delphi 11 编译的老项目表格控件滚动到第 3000 行时开始卡顿筛选一列要等两秒导出 Excel 直接卡死。他问我有没有必要换控件库。我让他先别急着重构把 EhLib 10.0.031 挂上去试一轮——这个版本对 Delphi 11 的适配是完整的装完替换掉原来的 TDBGrid同一份数据源、同一套字段绑定滚动和筛选的体感差异当场就能看出来。EhLib Delphi 这套组件在国内的 Delphi 圈子里属于「老牌但低调」的存在它不解决业务逻辑专治数据感知控件的显示与交互网格、树、下拉、打印、导出都是围绕数据集做文章。适合谁手上有一堆 VCL 老项目、不想大改架构、又想让表格体验跟得上现在的用户预期的人。这篇不聊虚的从安装到参数到翻车点按我实际拆包复现的顺序走一遍。2. 装进 Delphi 11包结构、编译顺序与第一个网格2.1 先看清包里有什么别急着点安装拿到 EhLib 10.0.031 的包第一件事不是双击而是把目录结构过一遍。常见做法是分三层Common放跨版本共享的单元Delphi11放该版本专用的包工程和编译产物Demos放示例。真正要编译的是.dpk设计期包和对应的运行期包运行期包必须先编设计期包依赖它。我一般会先把整个目录复制到非系统盘、路径不含中文和空格的目录下比如D:\Libs\EhLib10031因为 Delphi 的包搜索路径对空格和中文的容忍度很低路径里带一个空格后面报「找不到单元」能查到你怀疑人生。包工程里通常能看到类似EhLib110.dpk运行期和EhLib110D.dpk设计期这样的命名数字对应 Delphi 版本。编译顺序固定先运行期、再设计期。设计期包编译成功后点 Install组件面板上才会出现对应页签。这里有个细节如果之前装过旧版 EhLib务必先在 IDE 的「Install Packages」里把旧的设计期包卸载掉再删掉旧的.bpl否则两个版本的设计期包同时注册组件面板会出现重名项拖到窗体上编译能过、运行时却报类找不到这种玄学问题八成是残留包导致的。2.2 编译与安装的可复现步骤下面这套流程我在 Delphi 11 上走过不止一次按顺序执行基本不会出岔子。命令行的部分用msbuild更稳避免 IDE 里手动点编译时被缓存干扰。# 1. 进入运行期包所在目录路径按实际调整不要带空格 cd /d D:\Libs\EhLib10031\Delphi11 # 2. 先编译运行期包Release 配置Win32 目标 msbuild EhLib110.dproj /p:ConfigRelease /p:PlatformWin32 /t:Build # 3. 再编译设计期包 msbuild EhLib110D.dproj /p:ConfigRelease /p:PlatformWin32 /t:Build # 4. 确认输出目录里生成了 .bpl 和 .dcp dir /b *.bpl *.dcp逻辑说明/t:Build是完整重建比增量编译更能暴露路径缺失问题/p:PlatformWin32必须显式给Delphi 11 默认可能停在 Win64而很多老项目的第三方依赖只有 32 位版本平台对不上会在链接阶段报一堆符号未解析。第 4 步是自检.bpl是运行期二进制包.dcp是编译期需要的符号文件两个都在才算编对了。如果只出.dcp不出.bpl多半是包工程里的Requires列表引用了本机不存在的包打开.dpk源码看requires段逐个核对。编译通过后在 IDE 里Component → Install Packages → Add选中设计期.bpl组件面板出现 EhLib 页签即成功。接着建一个最小验证工程放一个TFDConnection或TADOConnection连到任意测试库放一个TDataSource再拖一个TDBGridEh绑上去DataSource指过去Columns里点「Add All Fields」。能正常显示数据、能点列头排序说明基础链路通了。这一步别省后面所有高级功能都建立在这个最小闭环上。2.3 搜索路径与单元引用装完包不等于工程能编译。新建的工程如果直接uses DBGridEhIDE 可能报找不到单元原因是库路径没配。在Tools → Options → Language → Delphi → Library里把D:\Libs\EhLib10031\Common和对应版本的编译单元输出目录加进Library pathWin32 和 Win64 分开配。我习惯把这两个路径也写进项目的.dproj里作为相对路径备份团队协作时别人拉代码不用再手动配一遍。单元引用上网格用DBGridEh下拉用DBLookupComboboxEh打印相关在PrinterEh一族单元里按需引用别一股脑全uses进来拖慢编译。3. 网格参数怎么调从列宽到大数据量渲染3.1 列、标题与自适应宽度TDBGridEh的属性多到让人第一眼发怵但真正高频的就那么几组。列级配置在Columns集合里每个TColumnEh有Width、Title.Caption、Alignment、ReadOnly、Visible。标题多行显示靠Title.TitleButton和Title.ToolTips标题换行则设Title.WordWrap : True并给足Title.RowCount。自适应宽度是我用得最多的AutoFitColWidths : True让列宽按内容撑开但它对超长文本不友好会把列撑到屏幕外所以通常配合Columns[i].MaxWidth设上限常见做法是文本列给 300、备注列给 400超过就靠ShowHint或单元格内省略号处理。行高和字体要一起调只改一个会显得挤。RowHeight默认偏小中文环境下我一般设到 22 到 26 之间同时把Font.Size提到 9 或 10Title.Font.Style加粗。这里有个容易忽略的点RowHeight设了但RowLines没开视觉上还是平的想要分隔线得把Options里的dgRowLines打开。这些属性在对象观察器里点一遍就能看到效果但建议最终固化成代码方便多窗体复用// 统一网格外观放在窗体创建后调用 procedure TForm1.SetupGrid(Grid: TDBGridEh); begin Grid.Options : Grid.Options [dgRowLines, dgColLines, dgTitles, dgIndicator]; Grid.RowHeight : 24; // 中文行高低于 20 会挤 Grid.TitleHeight : 28; // 标题行单独给高放两行标题时够用 Grid.Font.Size : 9; Grid.Title.Font.Style : [fsBold]; Grid.AutoFitColWidths : True; // 先自适应再用 MaxWidth 兜底 Grid.FrozenCols : 1; // 冻结首列横向滚动时定位用 end;参数说明dgIndicator是行首指示列配合IndicatorOptions可以显示当前行标记FrozenCols冻结左侧若干列宽表横向滚动时首列通常是编号或名称始终可见这个在设备台账类界面里几乎是刚需。AutoFitColWidths打开后每次数据刷新都会重算列宽数据量大时有额外开销如果表格是只读展示、列宽固定建议关掉它改用显式Width省下的时间在万行级数据上能感觉到。3.2 大数据量下的渲染与分页取舍EhLib 本身不做数据分页它渲染的是数据集当前可见的部分所以「卡不卡」很大程度取决于数据集怎么取。我踩过的坑是有人把TFDQuery的FetchOptions.Mode设成fmAll一次性把十万行拉进内存然后怪网格慢。正确做法是让数据集按需取fmOnDemand配合合理的RowsetSize比如 200网格滚动时再增量取。EhLib 的网格在滚动时会触发数据集的移动只要数据集支持单向游标这个链路是顺的。另一个影响体感的是Options里的dgEditing和dgAlwaysShowEditor。编辑模式下每个单元格都可能创建编辑控件行数多时开销明显。只读展示的界面把dgEditing去掉滚动会顺很多。还有DrawMemoText、ShowMemoText这类和备注字段相关的开关备注列如果不需要在格子里展开关掉能省一次文本测量。这些不是玄学是实打实的绘制路径差异我在一个两万行的日志查看界面上对比过关掉编辑和备注展开后首屏渲染时间从肉眼可感的停顿降到基本无感。3.3 排序、筛选与数据集联动列头点击排序依赖数据集的排序能力网格只负责发信号。TDBGridEh的Options里dgColumnResize、dgColumnMove管交互排序则要看Title.SortMarker和数据集自身的IndexFieldNames或Sort属性。常见做法是在OnTitleBtnClick里根据点击列切换升序降序然后设置数据集的排序字段再Refresh。如果底层是TClientDataSet用IndexFieldNames最快如果是TFDQuery改ORDER BY需要重新打开查询代价大通常改用内存排序或服务端分页。筛选方面EhLib 提供了STFilter即dgFilterRow那套在列头下方生成筛选行Columns[i].STFilter.Visible : True打开STFilter.CaseInsensitive控制大小写。它生成的是类似LIKE的条件最终怎么落到 SQL 取决于你接的OnSTFilterChanged事件。我一般不在客户端拼 SQL而是把筛选条件收集起来交给服务端接口避免把整表拉到本地过滤。这里提醒一句筛选行打开后网格的可用高度会减少RowHeight和TitleHeight要重新算否则底部会出现半行被裁掉的情况视觉上很别扭。4. 导出、打印与下拉三个最容易被低估的模块4.1 导出到 Excel 的两种路径EhLib 的导出能力是很多人选它的直接原因。常见两条路一是走DBGridEhExportAsXls这类单元直接把网格内容和格式写成 xls二是走DBGridEhExportAsText、DBGridEhExportAsHtml等轻量格式。xls 路径对格式保留较好列宽、标题、合并单元格能带过去但依赖 Excel 文件格式的兼容性目标机器没装 Office 也能生成文件因为写的是二进制格式而非调用 COM。我一般用下面这种写法把导出封装成一个函数界面层只传网格和文件名uses DBGridEhExportAsXls; procedure ExportGridToXls(Grid: TDBGridEh; const FileName: string); var Exp: TDBGridEhExportAsXLS; begin Exp : TDBGridEhExportAsXLS.Create(nil); try Exp.FileName : FileName; // 目标路径确保目录可写 Exp.Grid : Grid; // 绑定的网格 Exp.ExportAllRecords : True; // 导出全部而非仅可见行 Exp.TitleFromGrid : True; // 标题取网格列标题 Exp.Execute; // 同步执行大表建议放线程 finally Exp.Free; end; end;参数说明ExportAllRecords是关键默认可能只导当前可见区域用户以为导全了其实只导了一屏这是最常见的投诉来源。TitleFromGrid为真时用网格列标题为假则用字段名中文界面下必须为真。Execute是同步的几万行导出会卡界面稳妥做法是丢到TThread里跑导出期间禁用按钮并给个进度提示。导出路径要提前校验目录存在且可写UAC 环境下往Program Files下写会静默失败这个坑我见过不止一次。4.2 打印与预览的页面参数打印模块围绕TDBGridEh的PrintOptions展开phGrid、phTitle、phFooter这些子选项控制打印哪些部分。页面设置走PrintOptions.PageOrientation选横向还是纵向Margins设边距。宽表打印几乎一定要横向并且要开PrintOptions.Title.FillTitle让每页重复标题行否则翻到第二页用户就不知道哪列是哪列。预览用TDBGridEhPreview或对应的预览窗体先预览再打印别直接调打印机。一个实际经验打印前把网格的Options临时调整成适合打印的状态比如隐藏指示列、去掉筛选行打印完再恢复比在打印选项里逐项排除更省事。纸张大小和缩放比例在不同打印机驱动下表现不一致PrintOptions.Scale设成 90 到 95 之间通常能避免最右列被裁具体值要拿目标打印机实测没有通用答案。4.3 下拉与查找字段的绑定TDBLookupComboboxEh是 EhLib 里使用频率仅次于网格的控件。它和普通下拉的区别在于能直接绑查找字段显示值和存储值分离。配置要点DataField指向本表的查找字段KeyField和ListField指向查找源ListSource指向查找数据集。常见翻车是查找数据集没打开就绑运行时下拉为空或者KeyField类型和DataField类型不一致一个是整型一个是字符串选中后存进去的值对不上。我一般在下拉控件的OnDropDown里确保查找数据集Open并在窗体创建时校验两个字段的DataType是否匹配不匹配就在设计期改别留到运行时。5. 避坑清单安装、编译、运行时的五条血泪记录5.1 设计期包装了但组件面板不出现现象.bpl编译成功Install 也点了组件面板找不到 EhLib 页签。原因多半是设计期包注册的单元没被 IDE 识别或者旧版残留包占用了同名注册项。解决先在 Install Packages 里卸载所有 EhLib 相关包关闭 IDE删掉%APPDATA%下对应版本的包缓存Delphi 会缓存已注册包列表再重新 Install 一次。还不行就检查.dpk里contains段是否包含设计期单元缺了就不会注册面板页。5.2 编译报「Unit not found」但路径明明配了现象库路径加了工程还是报找不到DBGridEh。原因通常是平台不匹配——路径只加到了 Win32工程却在编 Win64或者反过来。解决在 Library 设置里把 Win32 和 Win64 的路径分别配全别指望一个路径通吃。另一个隐蔽原因是路径末尾多了反斜杠或中间有空格Delphi 的路径解析对这两种情况都不宽容逐字符核对一遍。5.3 网格滚动卡顿数据量并不大现象几千行数据滚动时明显掉帧。原因往往不是网格本身而是数据集每次移动都触发额外查询或者AutoFitColWidths在滚动时反复重算。解决关掉AutoFitColWidths改固定列宽检查数据集的AfterScroll事件里有没有做重查询把Options里的编辑相关开关按需关闭。用TStopwatch在OnDrawColumnCell里打点能快速定位是绘制慢还是取数慢。5.4 导出 Excel 打开提示格式不符现象导出的文件 Excel 能打开但弹「文件格式与扩展名不匹配」。原因多是导出单元版本和文件扩展名对不上比如用 xls 导出器却存成.xlsx。解决扩展名和导出器严格对应xls 导出器就存.xls。如果必须给 xlsx换对应的导出单元或走其他路径别靠改扩展名糊弄Excel 的兼容提示虽然能点掉但用户第一眼就失去信任。5.5 打印最右列被裁掉现象预览正常实际打印少一列。原因是打印机可打印区域比纸张小边距加缩放没算进去。解决把PrintOptions.Scale降到 90 左右边距适当收窄并在目标打印机上实测一次。不同驱动对边距的解释有差异同一份设置换台机器可能又裁所以打印功能交付前一定要在客户实际环境里打一张样张这一步省不得。6. 进阶把网格配置沉淀成可复用的运行时方案做到这里单个窗体的网格已经能用了但项目里往往有几十个表格界面逐个手配属性既慢又容易不一致。我的习惯是把常用配置抽成一个工具单元用 RTTI 或直接赋值的方式批量套用再留几个「风格档位」应对不同场景。下面这段是简化后的思路核心是把「只读展示」「可编辑录入」「大数据浏览」三类界面的差异固化下来调用方只传一个枚举。type TGridStyle (gsReadOnly, gsEditable, gsLargeData); procedure ApplyGridStyle(Grid: TDBGridEh; Style: TGridStyle); begin // 公共部分行线、标题、行高统一 Grid.Options : Grid.Options [dgRowLines, dgColLines, dgTitles]; Grid.RowHeight : 24; Grid.TitleHeight : 28; case Style of gsReadOnly: begin Grid.Options : Grid.Options - [dgEditing]; Grid.AutoFitColWidths : True; // 只读界面追求一屏看全 end; gsEditable: begin Grid.Options : Grid.Options [dgEditing]; Grid.AutoFitColWidths : False; // 编辑时列宽固定避免输入时跳动 end; gsLargeData: begin Grid.Options : Grid.Options - [dgEditing, dgAlwaysShowEditor]; Grid.AutoFitColWidths : False; Grid.FrozenCols : 1; // 大表冻结首列便于定位 end; end; end;这段的价值不在代码本身而在「把经验变成默认值」。新界面创建时调一次省掉逐项点属性的时间也避免了这个窗体行高 22、那个 26 的不一致。参数上要注意FrozenCols在列数很少时设 1 没有意义调用前判断一下Columns.Count。另外这套配置只覆盖外观和交互开关数据集的取数策略FetchOptions、分页大小仍然要按业务单独定别指望一个函数包打天下。验证方法我一般用两步一是拿一个万行级的测试表分别用三种风格打开记录首屏时间和滚动流畅度确认gsLargeData确实比默认配置快二是导出同一份数据用 Excel 打开核对行数和列标题确认ExportAllRecords生效。这两步走完基本能排除大部分「装上了但不好用」的情况。说个自己的教训早些年我图省事装完包直接往老工程里拖控件结果旧版残留包和新版打架查了大半天才发现是包缓存没清。从那以后我每次装这类设计期组件都强制走一遍「卸载旧包 → 清缓存 → 编运行期 → 编设计期 → 最小工程验证」的流程一步不跳。这套流程看着笨但省下的排查时间远比多花的那几分钟值。希望帮到你。本文还有配套的精品资源点击获取