简介:面向使用 Delphi XE7 至 XE13(Florence)进行桌面与业务系统开发的 DevExpress VCL Controls v25.1.6 完整源码包,覆盖数据表格、图表、导航、仪表盘、可视化报表、编辑器、网格和界面布局等常用组件,也支持 MVVM 等现代架构,适合需要快速交付专业应用的中高级 Delphi 程序员。压缩包共 2000 个文件、640.38MB,以 cpp/h 与 pas/dfm 源码为主体,附带 png 图标资源、txt/xml 配置说明,以及 chm/pdf/docx 帮助文档,便于查看示例、查阅用法和做源码级二次开发。随包提供的 DxAutoInstaller 可自动完成组件注册与配置,省去逐个安装控件的繁琐步骤。资源内含 Ribbon、Office12 风格视图、自定义表格绘制、就地编辑器等示例工程,可帮助开发者理解界面交互与数据展现的实现方式,结合完整源码可进一步按项目需求拆解与定制。目前已有 399 人学习下载,适合作为 Delphi 桌面开发控件选型、源码研读与二次开发参考。
1. DevExpress VCL Controls v25.1.6:Delphi 老将的一整套界面生产力工具
做 Delphi 桌面维护久了,你会发现最耗时的不是业务逻辑,而是把界面做得能让客户点头。筛选、汇总、层级树、导出 Excel、风格统一,这些用原生 VCL 都得从零搭,一套下来至少一两周。DevExpress VCL Controls v25.1.6 这套资源,覆盖 Delphi XE7 到 Delphi 13.1(Florence),把表格、树、日期、工具栏、皮肤这些高频需求一次补齐,还附带完整源代码和 DxAutoInstall 自动安装器。
我把它定位成业务界面的最后一块拼图:不管你是刚学习+Delphi 的新手,还是 Lazarus 转过来的老手,最终都会卡在同一个问题上——编译器效率再高,控件生态跟不上,交付速度就上不去。v25.1.6 最实在的贡献,是把表格、编辑、布局、导出这一整套动作变成拖拽绑定。适合做 ERP、进销存、后台管理系统的 Windows 桌面开发者,也适合想用 cxGrid 替换 TDBGrid、又不想重写业务层的老工程维护者。
2. 先把家底盘明白:cxGrid、cxTreeList 与完整源码能带来什么
2.1 cxGrid:数据展示、过滤、分组一把抓
cxGrid 是这套控件里使用率最高的组件,没有之一。它把一个网格拆成视图和数据控制器两层,视图管显示,控制器管数据,两者解耦之后,同一个数据源可以挂多个视图。典型用法是订单列表左半边是明细网格,右半边是客户维度分组汇总,这在 TDBGrid 里要写一堆事件,在 cxGrid 里只是再加一个 DBTableView 并绑定同一个 DataSource。
真正拉开体验差距的是过滤、分组和汇总。网格顶部一行自动筛选,列头拖拽即可分组,底部放统计行,这些全部内置。参数很直观,用代码设置也就是三个属性的事:
cxGrid1DBTableView1.OptionsView.FilterRow := True; // 开启自动筛选行 cxGrid1DBTableView1.OptionsView.GroupByBox := True; // 开启分组栏 cxGrid1DBTableView1.OptionsView.Footer := True; // 开启底部汇总区FilterRow 决定每列下方是否出现筛选输入框;GroupByBox 负责把要分组的列拖到分组栏上;Footer 开启底部的汇总区域,配合 Columns 的 Summary 项显示合计、最大值、最小值。这三个选项对着做分析型报表尤其有用,客户要的“按客户分组看金额”这类需求,基本不需要写代码。
2.2 cxTreeList、cxDateEdit 与编辑器一族
然后是树和编辑器。cxTreeList 不是简单地把 TreeView 换壳,它支持多列、节点拖拽、按需加载,适合做组织架构、商品分类这类层级数据。cxDateEdit 是我见过最省心的日期控件,既能下拉日历又能直接键入,通过 Properties 控制日期格式和是否显示时间:
cxDateEdit1.Properties.DateFormat := 'yyyy-mm-dd'; // 统一日期显示格式 cxDateEdit1.Properties.ShowTime := False; // 只要日期不要时间DateFormat 决定用户看到的文本格式,ShowTime 控制是否出现时分秒选择。千万别小看这两行,很多报表查询条件里日期框会带出 00:00:00 的默认时间,查询范围一展开就乱套,日期条件里带上这个设置能省掉后续大量的数据脏匹配。类似的,cxTextEdit、cxSpinEdit、cxMemo 覆盖文本、数字、多行文本三类基本场景,属性结构一致,写通用代码时不需要像原生控件那样分别处理。
2.3 完整源码的价值:改 bug、学架构、拒绝黑匣子
资源包带的是 Full Source,这一点在很多场景下比控件本身更值钱。以前遇到 cxGrid 焦点框绘制异常,按 F7 跟进绘制方法翻了几行,定位到主题导致画笔状态问题,改一行源码重新编译 .bpl 就解决。没有源码时这种问题只能换控件或绕路,代价完全不同。
附带的好处是学架构。TcxGrid 的事件分发、TdxBarManager 的动作路由、dxLayoutControl 的布局计算,都是高水平的 VCL 框架设计样本。看过一遍以后,自己写业务组件时会不自觉地沿用它的模式。网上不少人搜 devExpress source code,多半想要一份离线可编译的完整源码,或者研究某个控件的绘制实现,这份资源把 Source 目录直接摊开,属于拿到就能干活的那种。
2.4 版本跨度与选型理由:XE7 到 13 的兼容逻辑
为什么要认准 v25.1.6?因为这个版本把编译器适配做完了。Delphi XE7 是 2014 年的编译器,Delphi 13.1 是最新主版本,中间隔着十来个大版本差异,DevExpress 能在这种跨度上同时编译通过,靠的是大量条件编译指令和独立的 .inc 文件。选版本最忌讳无脑追新,然后回到老工程上一编译就把 IDE 搞崩。
我的建议是:主开发机用 Delphi 13.1 就用 v25.1.6 全量包,维护老 XE7 工程的同事保留同一套源码、编译目标改为对应 IDE 版本。控件版本统一,工程文件不会因为升级控件而大面积改动。这一条在多人团队里尤其重要,后文避坑章节会专门展开。
3. 安装动作拆解:DxAutoInstall 自动注册与 IDE 验证三步走
3.1 安装前核对四个前置条件
先说最容易被忽略的:装控件前先关掉 Delphi IDE。DxAutoInstall 会往 IDE 的注册表写包信息、更新库路径,IDE 开着时这些操作经常写不进去,结果安装过程一路绿灯,重启后控件面板里却什么都没有,这是典型的翻车现场。
第二,以管理员身份运行。DxAutoInstall 要写 BPL 目录,如果 Delphi 装在默认 Program Files 路径下,没有管理员权限会部分失败,报错还不明显。第三,解压路径不要有中文和空格,路径里一旦带中文,后续编译 .dpk 时 .inc 文件里的相对路径很容易对不上,报错还特别隐晦。第四,确认机器上有没有旧版 DevExpress VCL,有就先卸载,避免同名的 .bpl 互相冲突。
3.2 DxAutoInstall 的三个步骤:选版本、选目录、执行安装
解压开后目录通常是三块:Source 目录放全套 .pas、.dpk、.inc 源码,Bin 目录放预编译好的实例和运行时包,根目录放 DxAutoInstall.exe 自动安装器。
运行 DxAutoInstall 后会看到版本选择界面。第一步选 Delphi/RAD Studio 版本号,这一步含糊不得——选成 Delphi 12,装到 Delphi 13 里,后果是 IDE 看起来装了包,实际编译时一直报 Package not found。第二步指定源码路径,指向 Source 目录。第三步点执行或 Install。如果工具支持多选组件集,我一般只勾需要的子库:cxGrid 相关、dxBarManager 相关、dxSkins 皮肤相关,其余先不装,这样 IDE 启动速度会快很多,BPL 注册也不会把所有包全堆上去影响稳定性。
cd /d D:\DevTools\DevExpressVCL\Bin dxautinstall.exe我习惯在资源管理器里右键以管理员身份运行,但命令行方式同样可行。注意先 cd 到 Bin 目录再执行,因为工具要读取同级目录下的配置文件,从其他目录启动有时会找不到对应版本的包列表。
3.3 安装后验证三件事
装完先别急着写业务代码,按这三步走:
打开 Delphi,在组件菜单下的安装包列表里,看到 DevExpress VCL 相关的 .bpl 就说明设计时包注册成功。这一步看到的是注册到 IDE 的包集合,缺少它们时控件面板是空的,但工程能正常打开,容易误判为安装失败。
新建一个 VCL Forms 工程,往窗体上拖一个 cxGrid。如果控件面板里有 DevExpress 分类标签并且能拖出来,说明组件注册和工具面板配置都正常。接着再拖一个 dxSkinController 到窗体上,设一个内置皮肤,运行。皮肤生效说明控件包和皮肤资源都被正确链接。
最后一步是编译一个真实工程。找一个之前用 TDBGrid 的小模块,把网格替换成 cxGrid,编译运行。第一次可能要等几十秒,因为 IDE 要加载新包和新单元,之后速度会恢复正常。
3.4 验证不通过时的快速定位
最典型的现象是控件面板上连 DevExpress 标签都没有。先回到 3.1 的四个前置条件排查,多半是装了没重启、权限不够或者路径带中文。如果面板有标签但拖出来的控件报类不存在,手动在组件安装包里 Add 对应的 .bpl 即可。DevExpress 的包命名规律是 dcldx 开头代表设计时包,dx 开头是运行时包,手动注册认准 dcldx 开头的文件。
还有一种情况是拖 cxGrid 到窗体上直接报 Access Violation,十有八九是安装时 IDE 正在运行,某些包的初始化代码被跳过。处理方式是把控件卸掉,关掉 IDE 重新装一次。这个坑我踩过不止一次,后来养成的习惯是安装前先确认 IDE 完全退出,再动手。
4. 实战三件套:cxGrid、dxBarManager、dxLayoutControl 搭增删改查
4.1 把数据集接进 cxGrid:边绑定边解释
cxGrid 不自带数据访问层,通过 DataController 与 TDataSource 对接。常见做法是把 FireDAC 的 TFDConnection、TFDQuery 或老工程的 ADOQuery 接到 DataSource,再把 DataSource 指给网格视图。
procedure TfrmOrder.FormCreate(Sender: TObject); begin FDConnection1.Connected := True; DataSource1.DataSet := FDQuery1; FDQuery1.SQL.Text := 'SELECT order_no, cust_name, order_date, amount' + ' FROM orders ORDER BY order_no'; FDQuery1.Open; cxGrid1DBTableView1.DataController.DataSource := DataSource1; end;这段代码的关键有三处:DataSource 要先指定 DataSet,视图再指定 DataSource,顺序不能反;SQL 里显式排序,否则网格显示顺序受数据库返回顺序影响;在 Open 之前就把视图数据源指向 DataSource,避免在 OnStateChange 事件里做多余的刷新判断。如果表很大,可以用 FDQuery1.FetchOptions.RowsetSize 控制批量拉取,cxGrid 滚动时自动补数据,这个体验比 TDBGrid 平滑得多。
4.2 定义列显示:格式、对齐、宽度与弹出编辑器
cxGrid 里每个列是 TcxGridDBColumn 对象,设计期在结构定制器里添加,运行期也能用代码创建,适用于动态报表场景。
var col: TcxGridDBColumn; begin col := cxGrid1DBTableView1.CreateColumn; col.DataBinding.FieldName := 'amount'; col.Width := 120; col.HeaderAlignmentHorz := taCenter; (col.Properties as TcxCurrencyEditProperties).DisplayFormat := '¥ ,0.00;-¥ ,0.00'; end;DataBinding.FieldName 决定列关联的字段,Width 是像素宽度,HeaderAlignmentHorz 控制列头对齐。这里有个容易错的地方:Properties 类型必须与字段类型匹配。金额字段用 TcxCurrencyEditProperties,日期字段用 TcxDateEditProperties,强行把金额字段设成文本编辑器,保存时会发生类型转换异常。DisplayFormat 分号前面是正数格式,后面是负数格式,逗号是千分位,这些设计期也能在结构定制器里直接配,但用代码统一设置的好处是表结构变化时,重新绑定字段仍能保持一致的展示规范。
4.3 dxBarManager:把按钮和动作组织起来
工具栏我会用 dxBarManager,而不是原生 ToolBar。原因在于它把按钮、子菜单、快捷键、图标统一管理,而且支持运行时动态增按钮,这在做权限控制时非常好用。
var bar: TdxBar; btn: TdxBarButton; begin bar := dxBarManager1.Bars.Add; bar.Caption := '常用操作'; btn := TdxBarButton.Create(dxBarManager1); btn.Caption := '导出当前视图'; btn.OnClick := ExportCurrentView; bar.ItemLinks.Add(btn); end;这段代码创建一条工具栏并添加导出按钮。TdxBarButton 的 OnClick 直接指向一个方法,不需要中间再包一层 TAction,事件链路短,出问题时好排查。ItemLinks.Add 的顺序就是按钮在工具栏上的从左到右顺序。设计期拖按钮同样可行,但运行时添加的好处在于,按钮列表可以来源于授权配置:技术岗能导出,业务岗只能看,按权限表动态生成。这个用法处理一个界面在不同角色下显示不同操作集特别有效。
4.4 dxLayoutControl 与面板细节:自动布局拯救手排表单
录入界面的老大难是控件摆放。标签和编辑框挨个拖,窗口一缩放就乱,分辨率一变更是惨不忍睹。dxLayoutControl 把每行当成一个布局项,自动控制标签宽度、控件高度以及间距,窗口缩放时整体跟随。
dxLayoutControl1.BeginUpdate; try dxLayoutControl1.AddItem('客户名称', cxTextEdit1); dxLayoutControl1.AddItem('下单日期', cxDateEdit1); dxLayoutControl1.AddItem('订单金额', cxSpinEdit1); finally dxLayoutControl1.EndUpdate; end;BeginUpdate 和 EndUpdate 是批量修改布局时必须包起来的方法,它避免每添加一个项目就重新计算布局,减少闪烁和性能损耗。AddItem 的第一个参数是标签文字,第二个是被管理的控件,标签会按整体风格统一对齐,不需要手工处理每个 Label 的 Caption 和位置。这里顺带说一个常被问到的点:panel 控件圆角怎么做。原生 TPanel 要圆角得重写 OnPaint,而 dxLayoutControl 的样式里通过 Item 的 ControlOptions 或皮肤里的圆角样式可以直接实现,不需要额外代码。
4.5 一键导出 Excel:delphi excel 操作的最短路径
最后是业务系统躲不掉的需求:导出 Excel。原生方案是创建 Excel.Application 对象逐格写入,速度慢,客户机器没装 Office 就直接崩。cxGrid 自带的导出器在内存里生成 xlsx 文件,不依赖 Office,速度也快不少。
if cxGrid1DBTableView1.DataController.RecordCount > 0 then cxGrid1DBTableView1.SaveToXLSX('d:\exports\orders_' + FormatDateTime('yyyymmddhhnnss', Now) + '.xlsx');SaveToXLSX 接受一个带 .xlsx 后缀的完整路径,导出前先判断 RecordCount 是否为 0,避免生成空文件。文件名里带日期时间戳是为了防止同名覆盖把历史文件冲掉,这是处理导出需求时养成的习惯。如果客户只需要 CSV 或者 HTML 报表,SaveToCSV 和 SaveToHTML 也能用,不过 xlsx 是通用性最好的格式。
5. 避坑记录:六条编译与运行期问题的现象、原因与解法
5.1 Delphi 编译程序报内存错误
现象:装完 DevExpress 后第一次编译工程,Delphi IDE 弹出 Out of memory,或者编译中途直接关闭。
原因:最常见的是旧版本控件残留的 .dcu 缓存还在搜索路径里,新包加载时单元名冲突;其次是库路径过长,IDE 符号表膨胀。
解决:删除 %AppData%\Embarcadero\BDS<版本号>\cache 下的内容,清理 IDE 缓存;打开工程选项里的搜索路径,把旧 DevExpress 相关路径全部移除,只保留新版本 Source 目录;最后执行一次全量 Build,而不是 Compile。
5.2 工具面板没有 DevExpress 标签页
现象:DxAutoInstall 显示安装成功,控件面板里找不到任何 DevExpress 分类。
原因:安装时 Delphi IDE 未完全关闭,设计时包注册失败;或者 DxAutoInstall 里选错了 IDE 版本。
解决:关掉 IDE,以管理员身份重新运行 DxAutoInstall,核对版本号;如果仍然没有,手动把 Bin 目录下 dcldx 开头的 .bpl 通过组件菜单的安装包功能逐个注册。这个过程看着麻烦,实际五分钟能做完。
5.3 换机器编译提示找不到单元
现象:工程在自己机器上正常,拷贝到同事机器编译,提示 Unit dxCore not found 或 Can't find unit cxGrid。
原因:Delphi 的 Library 路径写在 IDE 全局配置里,不会自动跟随工程文件迁移。
解决:新建环境变量 DX_ROOT,指向解压后的 Source 目录;在 IDE 的工具选项里的 Library 路径中加入 $(DX_ROOT)。整个团队按这个规则配置,换机器基本零成本。如果使用项目级搜索路径,注意 .dproj 里的相对路径基准,避免提交后 CI 环境找不到单元。
5.4 皮肤控件运行期不生效
现象:窗体上放了 TdxSkinController,SkinName 设置了,运行时界面还是原生灰色样式。
原因:皮肤绘制单元没有被链接进程序。很多情况下只要 .dpr 文件的 uses 里少了 dxSkinsDefaultPainters,皮肤控制器就会静默失效,不报错、不提示。
解决:在 .dpr 的 uses 段加上 dxSkinsDefaultPainters,重新编译。如果只是单个窗体调试,可以在窗体 OnCreate 里显式调用 Refresh,但根治方法还是保证该单元被链接进编译。
5.5 中文显示乱码
现象:网格里中文正常,导出 xlsx 后 Excel 打开乱码,或者单据里的中文变成问号。
原因:导出时文本编码与打开工具预期不一致,或者数据库连接字符集设置不对,导致进入控件前的字符串已经损坏。
解决:数据库层面,确认连接字符串的字符集参数,FireDAC 可以在 Params 里加 CharacterSet=UTF8。导出层面,xlsx 导出默认走 Unicode,如果数据源本身是好的,问题多半出在旧版组件未按 UTF-8 导出。建议把从数据库到控件的整个链条统一为 UTF-8,不要一半 GBK 一半 UTF-8,排查起来会非常痛苦。
5.6 旧版本包与新版本共存冲突
现象:升级到 v25.1.6 后,原工程编译报 Package was compiled with a different version。
原因:工程里某些单元引用了旧版包的 .dcu 或 .bpl,IDE 同时加载新旧两种包,类型定义不一致导致冲突。
解决:卸载全部旧版 DevExpress VCL,删除磁盘上旧版 .dcu 和 .bpl 文件,再用 DxAutoInstall 重装新包。这一步虽然耗时,但最彻底。我有一次升级图省事保留了旧目录,排查单元版本冲突大半天,最后干净重装只用了十分钟。
6. 进阶技巧:把皮肤加载、编译子集和团队路径做成统一标准
皮肤加载建议收敛到一个函数里,而不是在每个窗体直接操作 dxSkinController。我习惯封装成这样,程序启动、用户切换主题时统一调用,以后公司做定制皮肤,只需要改一处源码,不用翻遍整个工程去替换 SkinName 字符串。封装之后,团队的视觉规范也就有了一个可追溯的入口。
procedure TAppSettings.ApplySkin(const ASkinName: string); begin dxSkinController1.SkinName := ASkinName; dxSkinController1.Refresh; end;如果工程只用了 cxGrid 和 dxLayoutControl,可以只编译对应的 dpk,让 BPL 体积小很多、加载更快。在 Source 目录里按包名挑出需要的 .dpk,用 Delphi 逐个打开编译,这一步会少装很多用不到的皮肤和编辑器,IDE 启动速度和编译速度都有明显改善,适合在稳定交付后作为收尾动作。
团队项目里,把 DevExpress 解压目录固定到一个统一路径,比如 D:\DevExpress\v25.1.6,并把该路径配置写进版本库的说明文档。成员机器路径不一致时,宁可花十分钟重排环境,也不要临时改本地路径攒野账——改完一时爽,提交代码后全组报错。我曾经在一台新笔记本上把控件装到 D:\MyStuff,结果工程一提交,团队其他成员的库路径全指向 D:\DevExpress,CI 环境直接挂掉。从那以后,每次装 DevExpress 之前都强制走一遍路径检查,确认与团队文档一致才开始动手。希望帮到你。
本文还有配套的精品资源,点击获取