ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Delphi XE8下DBGridEh控件安装与升级实战指南

Delphi XE8下DBGridEh控件安装与升级实战指南 简介面向 Delphi 开发者的 EhLib 控件库资源包覆盖 Delphi 7 至 XE8 多版本环境解决 DBGridEh 等增强型网格组件在桌面数据库项目中的安装与适配问题适合需要快速增强表格编辑、展示能力的开发者。压缩包共 1401 个文件约 42.15MB包含 166 个 pas 源文件、284 个 dcu 编译单元、183 个 hpp 头文件以及 31 个 bpl 运行期包同时配有安装程序、dpk 工程文件和若干示例窗体可按开发环境直接选用对应模块。资源附引导式安装说明运行 EhLibInstaller.exe 选择当前 Delphi 版本即可部署已在 Delphi 7 下验证通过针对 Windows 7/8 与 64 位系统可能出现的权限和 bpl 加载问题也给出具体注意事项包括以管理员身份运行、将 EhLib 路径加入系统 PATH 变量等排错思路可帮助减少环境配置上的弯路。已有 553 人浏览学习适合数据库应用、报表界面开发及需要维护多版本 Delphi 项目的中高级开发者参考。1. 项目背景为什么到今天还要聊DBGridEh和Delphi Xe8先说个真实场景。前阵子我接手一个老客户的项目他们的进销存系统还是Delphi 7写的界面上一排DBGridEh表格控件跑得挺稳但客户提了个需求要在Windows 10的新机器上部署还想用上64位编译。这就尴尬了Delphi 7压根不支持64位客户又不愿意全面重写——几万行业务代码说重写就重写那是要出人命的。最后方案定下来升级到Delphi Xe8控件继续用DBGridEh。你可能觉得奇怪Xe8都是2015年的老版本了现在都出到Delphi 12了怎么还有人往回折腾但实际情况是在制造业、医疗、政务、财务这类行业里Delphi写的老系统生命力极其顽强。尤其是DBGridEh配ADO这套组合几乎是国内Delphi开发者做管理信息系统的标配。Grid要能冻结列、要能合并单元格、要能树形展示、要能在单元格里嵌下拉框和日期控件原生TDBGrid做不到这些DBGridEh就是为这个而生的。这次项目做完我把DBGridEh在Xe8下的安装、迁移、踩坑过程完整记录了一遍。如果你也恰好被困在“老项目要升级但没有完整技术文档”的处境里这篇内容应该能帮你省下至少一个周末的折腾时间。2. EhLib控件库整体设计与版本选型思路2.1 一个控件库撑起一套UI框架EhLib不是一个单独的控件而是一整套VCL控件库核心是DBGridEh但配套的还有DBLookupComboboxEh、DBEditEh、DBDateTimeEditEh、DBComboBoxEh、DBMemoEh这一票兄弟控件。它们统一了数据感知控件的交互风格比如下拉框支持自动补全日期控件支持空值显示“请选择”这些在原生控件里都要自己写一堆代码才能实现。这次升级过程中我最大的体会是换版本不是换一个DLL那么简单而是一个生态的切换。DBGridEh的代码量非常大官方源码解开后光.pas文件就几十个里面涉及大量VCL底层接口的调用。所以千万不要试图直接把老版本的DCU拿过来用编译器版本对不上轻则提示“Unit not found”重则直接报非法内存访问。2.2 版本支持矩阵从Delphi 5到Xe8意味着什么EhLib的版本支持范围非常宽早期版本从Delphi 5一路支持到最新的RAD Studio。标题里说的“支持到Xe8”指的是EhLib对应版本中包含了针对XE8的编译器和RTL适配层。Delphi版本推荐的EhLib版本备注Delphi 7EhLib 4.x / 5.x经典搭配资料最多Delphi 2007EhLib 5.x老项目常见Delphi 2010 / XEEhLib 6.x开始支持Unicode完善Delphi XE8EhLib 7.x / 8.x支持64位编译Delphi 10.4EhLib 9.x / 10.x / 11.x新版官方持续更新这次项目用的是Delphi Xe8 EhLib 8.x实测稳定。如果你想用EhLib 11往Xe8上怼思路是对的——新版控件通常保持向后兼容但要注意新版可能使用了更新的语言特性导致在Xe8上编译不过。遇到这种情况要么换回旧版要么手动改源码我这次就踩了这个坑后面细说。2.3 选型时为什么放弃DevExpress留用EhLib比较戏剧性的是这个项目原来的开发者在一张表里用了DevExpress的cxGrid另外十几张表全是DBGridEh。升级的时候客户问能不能顺便统一了。我看了下代码DevExpress那套需要额外的运行时包、额外的授权文件而且cxGrid和DBGridEh的API完全不兼容——原来写在DBGridEh的OnGetCellParams事件里的那些格式化逻辑平移过去几乎等于重写。最后我的建议是统一保留DBGridEh把那张cxGrid的表也改回DBGridEh。理由很简单一是团队对这个控件更熟二是DBGridEh在普通二维表展示上完全不输cxGrid三是避免了引入更多依赖。DevExpress不是不好但老项目升级的第一原则是“减少变量”不要借升级的机会顺手搞技术栈迁移那是另一个项目该干的事。3. 核心细节解析DBGridEh那些值得深挖的硬核能力3.1 数据展示层的高级玩法DBGridEh最让我服气的一点是它把数据显示层该有的能力几乎都做全了。列标题多行显示、表尾统计行FooterRow、自动适应列宽、下拉列表过滤AutoFilter、单元格合并MergeColumns、树形结构展示TreeView模式这些功能在配置层面基本开箱即用。这里重点说一下单元格合并。做报表的人应该深有体会客户要求“相同值的列要合并单元格”这在原生TDBGrid里你得自己处理Canvas绘制工作量巨大。DBGridEh里只需要设置DBGridEh1.OptionsEh : DBGridEh1.OptionsEh [ghGrouping]然后在DBGridEh1.Columns[i].MergeCells : True运行起来就是自动合并而且带边框和焦点处理效果非常接近Excel。注意合并是针对整列生效的如果你只想合并某几行得配合OnMergeColumns事件自己判断行号。3.2 编辑控制单元格级的下拉和自动补全DBGridEh在编辑控制上把DBLookupComboboxEh和DBGridEh的联动做得很顺。比如做单据录入界面客户要求在“物料编码”列里直接下拉选择物料选中后自动带出规格、单位。用原生控件你得放一个DBNavigator再加一个DBLookupComboBox在表格上方切换记录时还要担心焦点丢失。DBGridEh的做法是在列的EditButtons里添加一个按钮按钮的Style : ebsDropDown然后指定DropDownForm或者DropDownBox。我比较常用的是配置Columns[i].PickList直接把一个静态列表塞进去DBGridEh1.Columns[2].PickList.Add(A类); DBGridEh1.Columns[2].PickList.Add(B类); DBGridEh1.Columns[2].PickList.Add(C类);这样用户点进单元格就会自动弹出一个下拉列表无需写任何事件代码。更复杂的需求比如“根据A列的值动态决定B列的下拉选项”可以在OnCellDataChanged里动态改另一列的PickList实测响应速度非常快基本无感知。3.3 打印与导出能力报表导出Excel不写一行代码DBGridEh的导出功能是我决定“不换控件”的最重要原因。DBGridEh.PrintDBGridEh方法可以不需要第三方报表控件就完成网格内容的打印和预览这在做单据打印时非常方便。导出Excel更是好用只要这一行DBGridEh1.SaveDBGridEhToExportFile(TDBGridEhExportAsUnicodeText, output.txt);如果想要真正的.xls格式用TDBGridEhExportAsXLS。实测Xe8 EhLib 8.x导出到Excel 2003格式没问题列宽、合并单元格、FooterRow都能带过去。另外注意导出xlsxExcel 2007格式在EhLib 8.x里支持得不太好如果你客户一定要求.xlsx建议用另一个方案走OLE方式让Excel自己填充数据。4. 实操过程在Delphi Xe8下安装DBGridEh的完整记录4.1 安装前准备源码、IDE版本、路径规划开始前先把本机环境理清楚。我建议在干净的虚拟机或者至少独立用户目录下做。需要准备Rad Studio XE8完整安装建议打上最新Update补丁EhLib对应版本的源码包我这次用的8.x从官方GitHub下载一个专门存放第三方控件的目录比如D:\Components\EhLib一个容易翻车的点安装路径不要带空格和中文。Delphi的库路径处理在某些老版本里对空格支持有bug虽然Xe8修了一些但保险起见全英文路径最省心。4.2 编译安装包运行install.bat的正确姿势EhLib源码包里每个版本都带install.bat或者Install目录下的批处理脚本。双击运行之前先打开看看里面内容确认是针对哪个IDE版本的。Xe8对应的是install_xe8.bat。运行前建议把Delphi的IDE完全关掉包括BDS进程。脚本执行完正常情况下它会自动把编译好的包.bpl复制到系统目录或者IDE的bin目录并把源文件路径写进注册表。但这不是100%可靠我遇到过一次脚本执行成功但IDE里怎么都找不到控件的情况。原因是用管理员权限运行时脚本写入了HKEY_LOCAL_MACHINE而Delphi IDE以普通用户运行时读的是HKEY_CURRENT_USER。解决方式用和IDE相同的权限级别运行脚本或者干脆手动在IDE里配置库路径。手动配置路径的步骤如下打开Delphi Xe8菜单Tools Options Environment Options Delphi Options Library - Win32在Library Path里添加EhLib源码目录比如D:\Components\EhLib\Library注意还要包含Library\Delphi\XE8这类子目录再到Component Install Packages里检查有没有EhLib相关的运行时包没有就点Add找到dclEhLibXXXX.bpl设计期包添加进去重新打开一个Form工具栏上应该能看到DBGridEh那一排控件图标4.3 编译顺序与依赖关系如果你只装了DBGridEh但运行时不加载其他EhLib兄弟控件编译时可能会提示找不到EhLibXXXX.dcu。这是因为EhLib的包之间存在依赖安装时应该把包按顺序编先编译运行时包EhLibXX.bpl再编译设计期包dclEhLibXX.bpl。千万不能跳过运行时包直接装设计期包否则设计期包加载时就报“Cant load package”。我习惯的做法是打开EhLib.dpk运行时包项目在IDE里右键Build编完后再编译dclEhLib.dpk然后右键Install。如果编译过程中报找不到DCU多半是库路径没配全对照4.2节把路径补充完整再试。4.4 64位编译的注意点Xe8最大的价值之一是原生支持64位。但DBGridEh在32位和64位下的编译单元是分开的。安装完32位版本后记得在Project Manager里把目标平台切换到Win64然后重新编译一次包。这一步很容易被忽略——很多人只装了32位然后新建一个64位项目时发现DBGridEh怎么都拖不上去。在64位下要注意指针类型转换。DBGridEh部分自定义事件里用了TDateTime和TStream的回调这些在64位下字节对齐要求更高如果只是使用已经编译好的包基本没坑。怕的是你为了修bug改到了源码内部改完32位正常64位崩溃——这就是典型的指针强转问题建议改源码时遵循官方代码里已有的写法不要自己发明类型转换。5. 常见问题与排查技巧实录5.1 编译报错与DCU版本不一致最常见的问题项目编译时提示“Unit DBGridEh was compiled with a different version of XXXX”。这个错误90%的原因是你项目里引用了一个旧版本的DBGridEh.dcu而IDE当前库路径里指向的是新版本。排查方式按下编译快捷键看输出窗口里找“Search path”那段打印确认实际加载的.pas/.dcu来自哪个目录。我的经验是一个机器上不要同时装两个版本的EhLib。如果需要同时开发多个项目而它们依赖不同版本最稳妥的做法是分别建Windows用户账户、分别装IDE或者用虚拟机隔离。同机多版本即使能装也极易出现“昨天能编译今天不行”灵异事件。5.2 运行时数据刷新异常TClientDataSet的坑这个跟DBGridEh本身关系不大但却是DBGridEh配合数据源时最容易踩的雷。热搜里有条TClientDataSet的CloneCursor函数是干什么的——我知道有人想问为什么DBGridEh刷新后多出了一个数据集CloneCursor是把游标记录位置共享给另一个TClientDataSet它们共享同一份数据但可以拥有不同的过滤和排序状态。如果你在DBGridEh的OnGetCellParams事件里做动态格式化而这个事件的触发又和主从表结构绑定千万注意不要在事件里执行ClientDataSet.Close/Open否则可能触发游标失效导致“Cursor not currently on a row”之类的运行时报错。如果一定要在主从结构下动态刷新某列的数据推荐用DBGridEh1.InvalidateColumn强制刷新某一列而不是刷新整个数据集。5.3 中文乱码与字符集适配Xe8的Unicode支持已经很完善了但老项目的数据源/数据库可能还是GB2312或GBK编码。DBGridEh显示乱码时先分清是数据源层面就乱还是Grid显示层乱。用ShowMessage(FieldByName(name).AsString)打出来如果也是乱的说明问题在数据库连接和数据集之间跟Grid无关。如果数据源正常但Grid显示乱检查DBGridEh1.Columns[i].Title.Caption的字体设置以及Form的Font.Charset是否设成了DEFAULT_CHARSET。有些老代码喜欢把Font.Charset设成GB2312_CHARSET在XE8的Unicode模式下反而会触发字体映射异常建议统一改成DEFAULT_CHARSET。5.4 与其他控件库的冲突排查装了DevExpress、TMS之类的库再装EhLib有时会提示“Package ... contains unit ... which is also contained in package ...”。这是不同控件库命名冲突。大多时候发生在vcl相关单元比如DBGridEh和cxGrid都带了一个DBGrid的注册类。解决方式在Component Install Packages里选择性启用不要一次装太多或者用Project Options Packages里的Runtime Packages设置为“Build with runtime packages”把不需要的包排除掉。6. 经典业务场景实操结合热词看DBGridEh的周边玩法6.1 读取Excel数据并展示到DBGridEh热词里有delphi 读取excel我就顺手把这一套流程写在DBGridEh的场景里吧。老项目最常干的事就是把Excel表导入数据库然后Grid展示。最快的方式是走ADO连接Excel文件Jet/ACE引擎再把数据读进临时表Grid绑定上去// 假设Excel里第一行是标题 ADOTmp.ConnectionString : ProviderMicrosoft.ACE.OLEDB.12.0; Data SourceC:\data.xlsx; Extended PropertiesExcel 12.0;HDRYES;IMEX1;; ADOTmp.CommandText : SELECT * FROM [Sheet1$]; ADOTmp.Open; // 等价于打开数据集 DataSource1.DataSet : ADOTmp; DBGridEh1.DataSource : DataSource1; DBGridEh1.AutoFitColWidths : True;这段代码跑起来Excel表格直接映射到Grid。注意IMEX1是给混合类型列用的防止“数字被读成文本”或“文本被截断”。6.2 局域网消息联动Grid刷新另一个热词是delphi 局域网 从一个程序 发消息给 另一个程序 sendmessage。在业务系统里A客户端新增了一条数据B客户端DBGridEh界面需要实时感知并刷新。除了轮询也可以用Windows消息。发送端SendMessage(HWND_BROADCAST, WM_USER 1024, 0, 0);接收端在Form里重载WndProc或者用消息映射收到消息后调用DBGridEh1.DataSource.DataSet.Refresh。但这个方案有个前提——双方必须跑在同一台机器消息是窗口级的跨机器得用Socket或者数据库触发器。如果你的项目是C/S架构客户端和数据库不在一起推荐用简单的用ADO重新查询别折腾消息。6.3 禁用U盘防止数据外泄热词里还出现delphi 禁用u盘这属于DBGridEh周边业务安全需求。在网格类管理软件里禁止U盘是为了防止用户直接把Grid导出的Excel拷走。Xe8里禁用U盘不复杂在FormCreate里写一句// 比较硬核的写法是注册表策略这里给个简单的API方式 if not CheckU盘Allowed then MessageBox(Handle, 当前环境禁止使用U盘, 提示, MB_OK);更彻底的方案是调用Windows APISetupDiGetDeviceRegistryProperty枚举存储设备把U盘设成禁用。但这是Windows驱动层面的操作风险较大不建议在业务系统里直接做。一般配合管理员的组策略就够了。其实防君子不防小人U盘禁了还有网盘真要泄密怎么都拦不住。6.4 判断周六日DBGridEh高亮非工作日的做法delphi如何判断是周六日这个热词放在DBGridEh场景里更实用——比如排班表里周六日列要高亮显示。实现方式是DBGridEh1.OnGetCellParams事件procedure TForm1.DBGridEh1GetCellParams( Sender: TObject; Column: TColumnEh; AFont: TFont; var Background: TColor; State: TGridDrawState); var ADate: TDateTime; begin if Column.FieldName WorkDate then begin ADate : Column.Field.AsDateTime; if (DayOfWeek(ADate) 1) or (DayOfWeek(ADate) 7) then begin AFont.Color : clRed; Background : $00F0F0F0; // 浅灰底 end; end; end;这段代码刷新时自动生效不用手动调用InvalidateOnGetCellParams每次绘制都会触发。如果数据量大上万行这个事件会被频繁调用注意别在里面写数据库查询。6.5 控制WebBrowser缩放一套界面两种数据展示还有webbrowser 控制放大缩小这个我实测过跟DBGridEh组合的场景Grid展示明细数据客户还要一个“预览网页样式报表”的按钮网页里嵌入同样的数据而且支持Ctrl滚轮缩放。实现上用TWebBrowser打开本地HTML模板数据用JavaScript渲染缩放用IOleCommandTarget接口var CmdTgt: IOleCommandTarget; vaIn, vaOut: OleVariant; begin WebBrowser1.ControlInterface.QueryInterface(IOleCommandTarget, CmdTgt); vaIn : 10; // 缩放百分比增量 CmdTgt.Exec(PGUID(nil), 63, OLECMDEXECOPT_DONTPROMPTUSER, vaIn, vaOut); end;这个场景说明DBGridEh在系统里往往不只是“一个表格控件”它是一整个管理系统数据展示的入口周边联动需求非常多。7. 从Xe8看向未来老项目升级的几条经验总结项目交付后我复盘了一下这次升级的决策链想分享几条实际经验。第一老项目用DBGridEh升级到Xe8方案是成立且值得推荐的。Xe8对老代码的兼容性在Delphi历史上算是比较友好的一个版本不仅支持32位也引入了64位支持DBGridEh从7.x开始对Xe8做了完整适配。如果你手里有Delphi 7/2007的老项目与其硬着头皮继续在旧环境里修修补补不如趁早迁到Xe8后面再升级也有个中间跳板。第二不要为了控件本身去升级而是为了场景去升级。客户要的是“能在新电脑上运行”“能处理大数据量”“能导出Excel”这些需求的背后是64位内存访问和Unicode支持——这才是升级真正的动机。控件只是船业务需求的河才是你要过的。第三升级前先在仓库里做一个“控件兼容性验证分支”。我当时花了半天时间专门写了个测试项目把DBGridEh每项核心功能都拖进Form跑一遍验证无误后才开始动主项目代码。这个预防针值得打它避免了在主项目里改到一半发现控件不兼容进退两难的状况。最后再给一个小技巧。DBGridEh的宿主Form在Xe8里如果感觉滚动有点卡特别是大批量数据时试试在FormCreate里加这么一句DBGridEh1.OptionsEh : DBGridEh1.OptionsEh - [ghThumbTracking];把这个选项去掉滚动条拖动时的实时刷新就关掉了松手才刷新流畅度提升非常明显。这个取舍要看业务场景——如果客户需要在拖动滚动条时实时看到数据变化那就保留如果只是快速浏览去掉体验反而更好。这次从接手需求、环境污染排查、控件安装到最后的代码迁移整个流程走下来我最大的体会是老项目升级技术难度还在其次对历史包袱的判断和取舍才是核心能力。保持克制减少变量一次只改一个维度——这就是我从DBGridEh在Xe8这次实战里学到的最值钱的东西。本文还有配套的精品资源点击获取
返回列表