简介:本资源是面向Delphi开发者的一套完整EhLib 11.0.21第三方控件库,专为Delphi 12.3(D12)环境适配编译,适用于中高级Windows桌面应用开发人员,解决UI增强、数据网格优化、报表导出及多语言支持等常见企业级开发需求。压缩包共含2000个文件,主体为518个dfm窗体设计文件、293个pas核心单元源码、196个dproj工程配置及170个dpk包定义文件,辅以大量res资源、ico图标与doc/docx说明文档,整体体积68.95MB,结构规范、模块清晰,便于直接集成或源码级二次开发。已有87人学习下载,资源包含完整安装流程、示例工程(含tutorial2、Project1等)、多格式图标资源(bmp、png、gif、jpg)及本地化支持文件(rus、gbk),特别适合需要快速落地高兼容性界面组件的Delphi项目团队。
1. EhLib 11.0.21 不是“又一个 VCL 控件包”,它是 Delphi 12.3 下少数能真正接管数据呈现边界的底层增强层
在 Delphi 12.3 的 IDE 中拖入一个TDBGrid,你立刻会意识到:原生网格对空值显示、行高自适应、列冻结、多级表头、导出 Excel 格式控制——全靠手写OnDrawColumnCell和一堆Canvas.TextOut补丁。而 EhLib 11.0.21 的TEhDBGrid一上手就默认支持带图标状态列、鼠标悬停行高亮、Ctrl+Click 多列排序、右键弹出列配置菜单,且所有行为不依赖第三方 DLL 或运行时注入。它不是封装层,而是直接重写了 VCL 数据绑定管道中TDataSet到TControl的映射逻辑,把TField的DisplayFormat、EditMask、OnGetText等钩子全部接管进自己的TEhDataLink实现里。这意味着你在 Delphi 12.3 中用TEhDBGrid绑定TFDQuery时,日期字段自动按ShortDateFormat渲染、数值字段小数位实时响应DisplayFormat变更、Null 值统一显示为[空]而非空白格——这些都不是样式设置,是数据通道级的语义透传。适合正在将老旧 BDE/ADO 项目迁移到 FireDAC + Windows 11 高 DPI 环境的团队,尤其当你发现TStringGrid在 150% 缩放下文字模糊、TDBCtrlGrid无法嵌套TEdit子控件时,EhLib 是目前唯一提供完整DPIAware=True兼容且源码完全开放的方案。
2. EhLib 11.0.21 的安装与 Delphi 12.3 兼容性验证:从 .dpk 编译到 IDE 集成的四步闭环
EhLib 11.0.21 并非即插即用的.bpl插件,其核心价值恰恰在于可编译、可调试、可定制。Delphi 12.3 的 RTL 已移除部分旧版Classes.pas符号(如TList.Sort的Compare参数签名变更),直接安装旧版.dpk会报E2003 Undeclared identifier: 'Compare'错误。必须先完成源码级适配,再走标准组件注册流程。
2.1 源码补丁:修复 Delphi 12.3 RTL 兼容性断点
进入解压后的EhLib\Source目录,定位EhLib.pas文件。在TEhDataLink.Sort方法中,原代码使用TList.Sort(Compare)形式,需替换为TList.Sort(TComparer<TObject>.Construct(Compare))。具体修改如下:
// 原始代码(Delphi 10.4 及之前) FList.Sort(Compare); // Delphi 12.3 适配后代码 FList.Sort(TComparer<TObject>.Construct( function(const Left, Right: TObject): Integer begin Result := Compare(Left, Right); end ));提示:此修改仅影响
TEhDataLink内部排序逻辑,不影响外部调用接口。Compare函数签名未变,因此所有继承TEhDataLink的控件(如TEhDBGrid)无需额外修改。
同理,在EhLib\Source\EhLibDB.pas中搜索TStringList.Sort调用,将其替换为TStringList.Sort(TComparer<string>.Default)。该补丁确保 EhLib 所有集合类在 Delphi 12.3 的泛型比较器框架下正确运行。
2.2 .dpk 编译:生成 D12 版本的运行时与设计时包
EhLib 11.0.21 提供多个.dpk文件,关键路径如下:
EhLibD12.dpk:Delphi 12.3 运行时包(含EhLib.pas,EhLibDB.pas等核心单元)EhLibDsgnD12.dpk:设计时包(含EhLibDsgn.pas,注册组件到 IDE 工具栏)
打开 Delphi 12.3 IDE →File → Open→ 选择EhLibD12.dpk→ 右键点击包名 →Compile。若编译通过,再打开EhLibDsgnD12.dpk→ 同样执行Compile→Install。此时 IDE 底部状态栏应显示Package EhLibDsgnD12 installed successfully。
注意:若
Install失败并提示Cannot find unit 'EhLib',说明EhLibD12.dpk未成功编译或未加入Search Path。需确认EhLibD12.dpk的Contains列表中已包含EhLib.pas,且Options → Directories/Conditionals → Search Path中添加了EhLib\Source路径。
2.3 IDE 集成验证:检查组件面板与对象查看器可用性
安装成功后,重启 Delphi 12.3。新建一个 VCL Forms Application → 切换到Tool Palette→ 查找EhLib页签。应可见以下核心组件:
TEhDBGrid(增强型数据网格)TEhGroupBox(支持折叠/展开的分组框)TEhPanel(支持圆角、渐变背景的面板)TEhButton(带图标、悬停效果的按钮)
在窗体上拖入TEhDBGrid→ 选中控件 → 查看Object Inspector→ 展开EhLib分类 → 检查是否存在OptionsEh、HeaderButtons、FooterButtons等特有属性。若这些属性可编辑且无灰色禁用状态,证明设计时集成完成。
2.4 运行时兼容性测试:用 FireDAC 连接 SQLite 验证中文显示与空值处理
创建最小验证工程:
- 放置
TFDConnection、TFDQuery、TDataSource、TEhDBGrid TFDConnection.Params设置:DriverID=SQLite;Database=.\test.dbTFDQuery.SQL.Text := 'SELECT ''张三'' AS name, NULL AS age, 123.45 AS salary FROM dual';TDataSource.DataSet := FFDQuery; TEhDBGrid.DataSource := DataSource1;
运行程序,观察TEhDBGrid第二行age列是否显示[空](而非空白)、salary列是否显示123.45(而非科学计数法)、name列中文是否清晰无锯齿。若全部符合,则 Delphi 12.3 + EhLib 11.0.21 + FireDAC + SQLite 的基础链路已打通。
| 测试项 | 预期结果 | 失败原因定位点 |
|---|---|---|
| 组件面板无 EhLib 页签 | 未执行EhLibDsgnD12.dpkInstall | 检查Tools → Options → Environment Options → Delphi Options → Library → Library Path是否包含EhLib\Design |
TEhDBGrid属性不可见 | EhLibD12.dpk未编译成功 | 查看Messages窗口是否有E2003类错误 |
| SQLite 中文显示为乱码 | TFDConnection.Params缺少CharSet=UTF8 | 在Params中添加CharSet=UTF8并调用Connected := True |
NULL值列显示为空白格 | TEhDBGrid.OptionsEh中eoShowNulls未启用 | 将OptionsEh的eoShowNulls设为True |
3. TEhDBGrid 深度配置:从列样式控制到子控件间距的像素级干预
TEhDBGrid的强大不在于功能堆砌,而在于每一处 UI 行为都暴露了可编程入口。当标准TDBGrid无法满足「销售报表中金额列右对齐、负数红色、小数位动态跟随币种」这类需求时,TEhDBGrid提供了三层控制粒度:列级格式、单元格级绘制、子控件级布局。
3.1 列级格式:用TEhDBGridColumn的DisplayFormat与Alignment实现动态数值渲染
TEhDBGrid的列对象TEhDBGridColumn继承自TCustomGridCol,但扩展了DisplayFormat、EditMask、Alignment等属性。以金额列为例:
// 假设 Grid1 已绑定数据集,第 2 列为 salary 字段 with Grid1.Columns[2] do begin Alignment := taRightJustify; // 文字右对齐 DisplayFormat := '#,##0.00'; // 千分位,两位小数 // 关键:动态绑定 CurrencySymbol OnGetCellText := procedure(Sender: TCustomGrid; ACol, ARow: Integer; var AText: string) begin if (ARow > 0) and (Sender.DataSource.DataSet.FieldByName('currency').AsString = 'CNY') then AText := '¥' + AText else if Sender.DataSource.DataSet.FieldByName('currency').AsString = 'USD' then AText := '$' + AText; end; end;逻辑说明:
OnGetCellText在每次单元格绘制前触发,AText是DisplayFormat格式化后的原始字符串。此处根据同行currency字段值动态拼接货币符号,避免在 SQL 中硬编码。Alignment属性直接影响Canvas.TextOut的 X 坐标计算,无需手动调整Rect.Left。
3.2 单元格级绘制:重写OnDrawCell实现负数红色与条件高亮
TEhDBGrid的OnDrawCell事件比原生TDBGrid多传入ADrawState: TGridDrawState参数,可精确判断当前单元格是否为选中、聚焦、只读等状态:
procedure TForm1.Grid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var Field: TField; Value: Double; begin if (ARow > 0) and (ACol = 2) then // 仅处理 salary 列(索引2) begin Field := Grid1.DataSource.DataSet.Fields[ACol]; if Field is TNumericField then begin Value := Field.AsFloat; if Value < 0 then begin Grid1.Canvas.Font.Color := clRed; Grid1.Canvas.Brush.Color := $F0F8FF; // 浅蓝底色 end else begin Grid1.Canvas.Font.Color := clBlack; Grid1.Canvas.Brush.Color := clWindow; end; // 调用父类默认绘制,复用 EhLib 的文本居中逻辑 inherited; Exit; end; end; // 其他列走默认绘制 inherited; end;参数说明:
State是TGridDrawState集合类型,包含gdSelected、gdFocused、gdFixed等标志。此处未判断gdSelected,是因为TEhDBGrid默认选中行使用独立SelectionColor,若需覆盖选中样式,需在OnDrawCell开头添加if gdSelected in State then ...分支。
3.3 子控件间距:通过TEhDBGrid.OptionsEh控制行高、列间隙与标题高度
TEhDBGrid的OptionsEh属性是一个TEhGridOptions记录,其中eoUseFixedHeight、eoUseFixedWidth控制行列尺寸是否固定。但真正影响「子控件间距」的是RowHeights和TitleHeight:
// 设置行高为 24 像素(默认 18),解决高 DPI 下文字拥挤 Grid1.OptionsEh.eoUseFixedHeight := True; Grid1.RowHeights[0] := 24; // 标题行高 Grid1.RowHeights[1] := 24; // 数据行高(索引1起为数据行) // 设置列间隙:ColumnGap 控制列与列之间的像素距离 Grid1.ColumnGap := 2; // 设置标题高度:TitleHeight 影响标题栏整体高度 Grid1.TitleHeight := 26; // 关键:启用 eoShowHorzLines 使水平线在行高增加后仍对齐 Grid1.OptionsEh := Grid1.OptionsEh + [eoShowHorzLines];提示:
RowHeights是动态数组,RowHeights[0]对应标题行,RowHeights[1]对应第一行数据,RowHeights[2]对应第二行数据……若数据行数超过Length(RowHeights),TEhDBGrid会自动扩展数组并复制最后一项值。因此生产环境建议初始化SetLength(Grid1.RowHeights, 1000)避免频繁内存分配。
4. EhLib 11.0.21 的导出与打印实战:绕过 Windows GDI+ 限制生成高清 PDF
Delphi 原生TDBGrid导出 Excel 依赖 OLE 自动化,导致 Windows Server 环境下服务崩溃;打印预览则受限于TPrinter的 GDI+ 渲染精度,在 200% DPI 下文字发虚。TEhDBGrid内置ExportToExcel和PrintGrid方法,但其底层调用TExcelApplication仍有兼容风险。更可靠的方式是利用 EhLib 的TEhGridExport类直接生成二进制 Excel 流,再通过TIdHTTP上传至轻量级 PDF 服务。
4.1 使用 TEhGridExport 生成 .xlsx 流并保存本地文件
TEhGridExport不依赖 Excel 安装,直接写入 OOXML 格式:
uses EhLibExport; procedure TForm1.ExportToXLSX; var Export: TEhGridExport; FileStream: TFileStream; begin Export := TEhGridExport.Create(nil); try Export.Grid := Grid1; // 指向 TEhDBGrid 实例 Export.Options := [eoExportHeaders, eoExportFooter, eoExportHiddenColumns]; // 导出表头、页脚、隐藏列 Export.HeaderFont.Name := 'Microsoft YaHei'; Export.HeaderFont.Size := 10; Export.DataFont.Name := 'Microsoft YaHei'; Export.DataFont.Size := 9; // 生成内存流 Export.ExportToStream; // 保存为文件 FileStream := TFileStream.Create('report.xlsx', fmCreate); try Export.Stream.Position := 0; FileStream.CopyFrom(Export.Stream, Export.Stream.Size); finally FileStream.Free; end; finally Export.Free; end; end;逻辑说明:
ExportToStream方法将网格内容序列化为IStream接口,Export.Stream指向该内存流。CopyFrom直接复制二进制数据,避免TStringStream的编码转换损耗。生成的.xlsx在 Excel 2016+ 和 LibreOffice Calc 中均可正常打开,且公式、合并单元格、条件格式均保留。
4.2 打印优化:用 PrintGrid 的 PageSetup 参数规避 Windows 打印缩放失真
TEhDBGrid.PrintGrid方法接受TPrintGridOptions参数,其中PageSetup可精确控制纸张方向、边距、缩放:
procedure TForm1.PrintGridWithScale; var PrintOptions: TPrintGridOptions; begin PrintOptions := []; PrintOptions := PrintOptions + [poPrintHeaders, poPrintFooter, poFitToPage]; // 关键:设置 PageSetup 强制 100% 缩放,禁用 Windows 自动 DPI 缩放 with Grid1.PrintGridOptions.PageSetup do begin PaperSize := psA4; Orientation := poPortrait; TopMargin := 1000; // 单位:twips(1 inch = 1440 twips) BottomMargin := 1000; LeftMargin := 1000; RightMargin := 1000; Scale := 100; // 百分比,100=原始尺寸 end; Grid1.PrintGrid(PrintOptions); end;参数说明:
Scale := 100是绕过 Windows 打印子系统 DPI 插值的关键。若设为0(默认),Windows 会根据打印机 DPI 自动缩放,导致 120 DPI 打印机输出模糊;设为100则强制使用网格原始像素尺寸,由打印机固件完成最终渲染,保证文字锐利度。TopMargin等单位为twips,1 twip = 1/1440 inch,因此1000≈ 0.7 inch,符合国内常用打印边距。
4.3 高清 PDF 生成技巧:将 TEhDBGrid 截图为 PNG 后调用 wkhtmltopdf
当需要生成带公司 Logo、页眉页脚的正式 PDF 报表时,TEhDBGrid的DrawTo方法可将网格渲染为TBitmap:
function TForm1.GridToPNG: string; var Bitmap: TBitmap; TempFile: string; begin TempFile := GetTempFileName(GetTempPath, 'EhGrid', '.png'); Bitmap := TBitmap.Create; try Bitmap.SetSize(Grid1.Width, Grid1.Height); // 注意:此处需确保 Grid1.Visible=True Grid1.DrawTo(Bitmap.Canvas.Handle, 0, 0); Bitmap.SaveToFile(TempFile); Result := TempFile; finally Bitmap.Free; end; end; // 调用 wkhtmltopdf 命令行(需提前安装) procedure TForm1.GeneratePDF; var PNGFile, PDFFile: string; Cmd: string; begin PNGFile := GridToPNG; PDFFile := ChangeFileExt(PNGFile, '.pdf'); Cmd := Format('wkhtmltopdf --page-size A4 --margin-top 20 --margin-bottom 20 "%s" "%s"', [PNGFile, PDFFile]); WinExec(PAnsiChar(UTF8Encode(Cmd)), SW_HIDE); end;提示:
Grid1.DrawTo要求控件已渲染到屏幕,因此需确保Grid1.Visible := True且窗体已显示。若在服务端无界面环境使用,可改用TEhDBGrid.PaintTo方法配合离屏TBitmap,但需手动处理滚动条位置和虚拟列偏移。
本文还有配套的精品资源,点击获取