简介DevExpress VCL 20.2.4 for RAD Studio 10.4 是官方直接编译的商业级 VCL 组件库安装包面向 Delphi/CBuilder 开发者的企业桌面应用开发场景。它涵盖数据表格、图表、仪表板、调度与导航等常用界面组件可大幅减少界面和交互功能的重复开发工作量。该版本不含源码解压安装后需要按说明将项目选项中的 Runtime Packages 配置为链接运行时 BPL并导入安装目录 Library\RS27 下 RuntimePackages.txt 中的包名才能让构建出的 EXE 正常找到依赖包避免运行时“Not working”问题。压缩包整体约 362.21MB当前已有 1959 人浏览学习。对希望省去源码自行编译环节、快速获得稳定且完整组件集的开发者来说这套安装包提供了直接可用的基础件适合在 RAD Studio 10.4 中搭建界面框架和实施正式项目开发。1. 为什么说 20.2.4 是 RAD Studio 10.4 下的保守之选如果你正在维护一个用 RAD Studio 10.4 写的 VCL 桌面客户端大概率迟早会看到类似“Package ... has been compiled with a different version of ...”的报错。DevExpress VCL 20.2.4 for RAD Studio 10.4 不是一个可以随便跳过的版本号它是老项目从旧 IDE 迁到 10.4 之后最容易落定的版本也是新项目踩坑最少的基线之一。下文按安装选型、cxGrid 最小用法、皮肤与导出、10.4 下高频踩坑、以及一个我保留的布局习惯来展开。新手可以完整走一遍熟手可以直接跳到避坑章节对照排查。我第一次换到 10.4 时也犹豫过要不要直接上更新的版本最后选择 20.2.4 不是因为它新而是因为这个版本线在 10.4 上经历过多个补丁迭代BPL 依赖关系被官方反复清理过。对干活的人来说稳定比新功能值钱。2. 安装与包编译先选二进制还是源码再动手2.1 为什么安装方式会直接影响后面排错二进制安装适合不想让控件源码参与编译、拿到组件直接拖的场景源码安装适合需要单步跟踪控件内部逻辑、自定义皮肤或者要在持续集成环境里自动构建的情况。我一般建议开发机至少走一次源码编译不是为了“看代码”而是让 IDE 里的 BPL 和运行库全部基于当前 10.4 生成避免拿到的二进制包与机器上其他组件包互相覆盖。还有一个现实原因如果团队里有人同时用 20.1 和 20.2把旧 BPL 拷贝到共享目录IDE 启动就会出现版本错乱。常见做法是安装器让你勾选目标 IDE 版本和需要的组件集。只做普通 Win32/Win64 窗体项目至少要勾 ExpressLibrary、ExpressDataController、ExpressEditors、ExpressGrid如果用到菜单、工具栏、状态栏再加 ExpressBars皮肤功能由 ExpressSkins 与 ExpressPageControl、ExpressLayoutControl 提供。装完之后 IDE 组件板会多出几个 DevExpress 页签名称带 cx 前缀的是 VCL 经典控件带 dx 前缀的大多是引擎或独立组件。2.2 二进制安装的操作顺序与验证关闭 IDE以管理员身份运行安装器选择 RAD Studio 10.4勾选需要的组件。安装完成后启动 IDE先在新建 VCL 项目的空窗体上拖一个 cxGrid如果组件板没有反应就去看 Tools Options IDE 的 Component Path 是否指向安装目录。初次安装最容易忽略的是“BPL 输出目录没有加入系统 PATH”这会导致编译通过但运行时提示找不到 dll。下面是常见的验证手段# 在用户目录里扫一遍确认没有残留的旧版本 BPL。 # 输出按名字排序方便观察是否混入 20.1 或其他版本。 Get-ChildItem $env:USERPROFILE -Recurse -Filter *.bpl | Where-Object { $_.Name -match DevExpress|dx } | Sort-Object Name | Select-Object Name, FullName这个脚本只负责观察不负责删除。如果列表里有多个同名前缀但版本号不同的文件不要手动删先做卸载。脚本逻辑Get-ChildItem 加 -Recurse 会把用户目录整个遍历一遍速度慢但能覆盖 IDE 文档目录之外的临时放置路径Where-Object 过滤出包含 DevExpress 或 dx 前缀的包文件Sort-Object 按名称排序当你看到同一个网格相关包同时存在 20.1 和 20.2 的文件时问题原因就基本锁定了。2.3 源码版安装什么时候我建议你编译一遍如果你的项目要接进持续集成或者需要动皮肤资源、自定义编辑器我会建议使用源码安装。源码安装的常见做法是把安装器的 Source 选项打开让代码落在磁盘里然后用 IDE 打开对应 IDE 版本的工程文件逐个编译。为了不从一堆 dpk 里手工乱点我会先做一步“找文件”的动作# 定位 10.4 对应的源码包目录。 # 20.2.4 安装后源码目录内通常会有带 10.4 或 20.0 标识的文件夹。 Get-ChildItem . -Recurse -Directory | Where-Object { $_.Name -match 10\.4|20\.0|DX } | Select-Object FullName找到目录后在 Project Manager 里打开该目录中的 dpk 工程。编译顺序有讲究先编译运行期包名字通常以 dx 或 cx 开头不包含 Design再安装设计期包。运行期包只编译不安装设计期包需要右键选 Install这样 IDE 组件板才会出现控件。如果漏掉运行期包直接安装设计期包IDE 会提示找不到核心库。编译时遇到“unit xxx not found”先查 Tools Options Library Library path 是否把源码目录的 common 和核心库子目录加进去不要在这个环节去勾垃圾清理把路径理顺比什么都快。编译通过后回到 2.2 的脚本再扫一次 BPL确认这次只有 20.2.4 的文件。2.4 装完先别写业务做一遍冒烟测试装完第一时间新建一个空白 VCL 工程依次拖入 cxGrid、cxButton、dxSpreadSheet编译运行。这步不是验证功能是验证组件包之间的运行时依赖在 10.4 下是否完整。如果在这里翻车说明安装环节有残留不要带着一个坏环境去改业务代码。冒烟测试里我会额外看一件事窗体和控件的默认字体是否被 IDE 改成 Segoe UI。DevExpress VCL 在 10.4 上对字体很敏感默认字体若带了奇怪的脚本标记运行时皮肤绘制会偏粗。干脆在冒烟测试里把字体名固定为“宋体 9pt”或“Microsoft YaHei UI 9pt”后面写业务时就不会被字体问题分散注意力。3. cxGrid 最小可用项目一个表格从空窗体到能查改3.1 为什么是 cxGrid一个网格背后有四层依赖DevExpress VCL 20.2.4 里用得最多最勤的控件其实是 cxGrid。一个 cxGrid 不是单纯画界面的控件它由 DataController、View、Level、内置编辑器四个概念组成Level 决定表在网格中的层级View 决定行列显示DataController 负责与数据集交互内置编辑器负责单元格内输入。理解这一点后面调属性才找得对地方而不是在属性面板里翻半天找不到数据源绑定。很多新手把 cxGrid 当成 TDBGrid 的替代品发现 DataSource 属性不存在就懵了。实际上 DataSource 是挂在 View 的 DataController 上的这也是 DevExpress 和原生 dbGrid 最大的思维差异。你先把这一层关系印在脑子里后面所以属性好像都顺了。3.2 从空白 Form 到显示数据的四步绑定拖一个 cxGrid 到空白 Form再拖一个 DataSource 和一个 ClientDataSet 或查询数据集。关键绑定就一行procedure TForm1.FormCreate(Sender: TObject); begin // cxGrid 自己不持有业务数据必须先把数据控制器接到 DataSource cxGrid1DBTableView1.DataController.DataSource : DataSource1; // 让列宽跟随内容自适应适合刚着手时快速看到效果 cxGrid1DBTableView1.OptionsView.ColumnAutoWidth : True; end;这段代码的要点是 DataController 那条赋值。数据源绑定在代码里做最直观也方便后续根据登录用户切换数据库连接。打开数据集之前先确认表视图已经接好否则第一次取数时没有列结构// 打开数据集之前先保证视图已绑定否则取数时列结构不完整 ClientDataSet1.IndexFieldNames : 主键ID; ClientDataSet1.Open;顺序错了会看到“列全部空白、滚动条异常”。先绑定再 Open 是 cxGrid 使用的固定顺序别改。3.3 三个必调参数编辑、筛选、汇总这一节列一下我每次建表都会确认的三个位置属性路径作用建议值OptionsData.Editing是否允许单元格编辑查询界面关掉录入界面打开OptionsView.GroupByBox是否显示拖动分组头简单列表建议 False分组报表要 TrueDataController.Summary.FooterSummaryItems底部汇总项需要合计时添加Format 用 Excel 风格格式汇总的运行时添加方式var AItem: TcxDataSummaryFooterItem; AColumn: TcxGridDBColumn; begin // 给“金额”列增加底部合计 AItem : cxGrid1DBTableView1.DataController.Summary.FooterSummaryItems.Add; AColumn : cxGrid1DBTableView1.GetColumnByFieldName(金额); AItem.Column : AColumn; AItem.SummaryKind : skSum; AItem.Format : ¥0.00; end;SummaryKind 决定聚合算法skSum 是求和skCount 是计数skAvg 是平均Format 使用 Excel 风格格式串而不是 Delphi 的 Format。这里就有坑汇总格式写成 %.2f 会显示不出内容因为你把 Delphi 的格式串带进了 DevExpress 的格式化体系。3.4 从“能跑”到“不卡”大数据量的两个开关数据集上万行以上打开界面卡顿通常是启用了逐行重绘和分组即时重建。处理办法是关掉冗余的自适应计算把数据获取方式改成分批或延迟创建列。可以在数据打开前设置// 减少大数据量下的绘制压力 cxGrid1DBTableView1.OptionsData.PreserveRowOnScroll : False; cxGrid1DBTableView1.OptionsView.CellAutoHeight : False; cxGrid1DBTableView1.OptionsCustomize.DataGrouping : False;PreserveRowOnScroll 为 False 时滚动时不会为了保持高亮行而重建视图对只读报表没有影响。DataGrouping 关掉之后cxGrid 不会在字段拖到分组区域时自动为每组重建视图内存占用明显下降。真正要做分组报表时再动态打开运行时切换也来得及。这个取舍值得记住cxGrid 强在展示能力而不是免费的数据库分页如果你要处理十万行以上还是要限流查询而不是全量拉进来交给控件去显示。4. 皮肤、高 DPI 与 Excel 导出装完控件后最常调的三个功能4.1 统一皮肤的注册方式界面组件装完第一件事永远是统一外观不然每个窗口用默认样式看起来像三个工程师各写各的屏幕。VCL 里最稳的做法是放一个 TcxLookAndFeelController然后在程序启动时指定皮肤名。注意皮肤是先注册、再启用顺序颠倒就会出现“设置无效”procedure TMyApplication.InitializeLookAndFeel; begin // 把皮肤资源注册进当前进程之后才能被管理器识别 dxSkinsAddDefaultSkin(Office2016Colorful); // 全局接管所有 DevExpress 控件的外观设置一次即可 cxLookAndFeelController.SkinName : Office2016Colorful; end;dxSkinsAddDefaultSkin 会把皮肤资源注册到当前进程注册完成后 cxLookAndFeelController.SkinName 才能识别。如果你在程序入口直接改 SkinName会看到运行时皮肤失效因为皮肤资源根本没被加载。注册代码只调用一次不要在 FormCreate 里重复调用。4.2 高 DPI 下的一组固定设定RAD Studio 10.4 的 DPI 模式和 20.2.4 是搭配的但搭配不等于没坑。我习惯在项目 dpr 里放一句 Application.UseGDIPlusText : TrueForm 上打开 ScaledDevExpress 相关 Form 的 Font.PixelsPerInch 保持默认。不要手动改 Font.Size否则 125% 缩放下 cxGrid 行高会被字体撑变形。如果出现皮肤文字模糊先看项目 DPI Awareness 是否设置为 PerMonitorV2用系统 DPI 时20.2.4 的皮肤绘制会拿错误的分辨率参数看起来像美工把图标糊了。窗口跨屏拖动时 cxGrid 的列宽会闪一下这不是控件坏了是 DPI 切换后 View 要重新计算列宽。处理方式是在 DPI 变更事件里先暂停视图刷新等缩放完成后再恢复。如果项目不大也可以让 Form 固定 PerMonitorV2 并允许系统重启程序来切换。4.3 Excel 导出把数据送出去的四条路线方式适用场景注意cxGridExportLink 的导出函数简单表格直接导出所见内容格式控制弱dxSpreadSheet 重填单元格需要模板、合并单元格、公式最推荐可控DevExpress 报表引擎导出复杂报表、页眉页脚依赖报表模板直接写 SQL 生成 xlsx与 VCL 无关的后台生成不适合 UI 内联动我大多数项目选 dxSpreadSheet。它可以加载已有模板把数据填到指定单元格再保存为 xlsx预览和结果一致。最小调用// 从模板加载填数后另存为结果文件。 // 模板放在 exe 同级或资源目录避免硬编码绝对路径。 dxSpreadSheet1.LoadFromFile(报表模板.xlsx); dxSpreadSheet1.Cells[3, 0].AsString : 客户名称; dxSpreadSheet1.Cells[3, 1].AsString : ClientDataSet1.FieldByName(客户名).AsString; dxSpreadSheet1.SaveToFile(待发送报表.xlsx);Cells[行, 列] 的坐标是从 0 开始的和 Excel 用户看到的 A1 表示不一样这里很容易写错导致数据填到表外。保存时如果遇到“文件被占用”原因是用户已经用 Excel 打开同名文件先做 FileExists 检测或提示关闭。4.4 导出前的中文适配字体和编码一起处理导出 xlsx 时中文乱码在 20.2.4 里不太常见但一旦出现几乎都是因为走了 CSV 或按字节拼接的路线。解决方法是让 dxSpreadSheet 自己去编码不要用 TStringList 去构造文本再改扩展名为 xlsx。另外要确认模板里单元格字体包含中文字体名比如“微软雅黑”或“宋体”否则生成的 xlsx 在其他机器打开时长数字会变成科学计数法日期变成井号。这个现象不是数据错是单元格格式问题提前在模板里设好更省事。5. 避坑章节在 RAD Studio 10.4 里排查 20.2.4 的五个高频报错5.1 重装之后 IDE 启动直接弹版本冲突现象卸载 20.1、安装 20.2.4 后IDE 打开窗体时报“Package ... has been compiled with a different version of ...”。原因Bpl 目录里还有 20.1 的包文件IDE 按组件名索引时加载到老文件。解决先用第 2 章的 PowerShell 脚本扫描用户目录把残留 BPL 全部移到备份目录确认 IDE 正常后再清理。不要直接删除移动出去还能后悔。5.2 皮肤换了但窗口切换时闪一下灰白底现象Form 之间切换时先露出灰白色再显现皮肤视觉上像卡了一下。原因Form 默认 DoubleBuffered 为 False皮肤绘制和系统绘制顺序错位。解决在主窗口的构造函数里设置 DoubleBuffered : True如果单个 Form 仍然闪再检查这个 Form 是否设置了 TransparentColor。DevExpress VCL 的皮肤绘制是基于自绘机制的DoubleBuffered 影响的是 Windows 底层重绘的合成方式低成本但有效。5.3 安装器全选了组件板里却没有 ExpressLocalization现象安装时勾了全部组件重新打开 IDE 找不到本地化相关组件。原因本地化组件包属于独立模块有的安装器界面默认不展开勾选“全选”时并不包含隐藏选项。解决重新运行安装器在组件树里手工找到 Localization 或中文资源包单独勾选后安装。验证方法是在工具箱里搜“Localizer”或“cxLocalizer”。5.4 导出报表中文乱码英文正常现象xlsx 打开后中文变成乱码或问号英文和数字正常。原因导出代码里用了按本地代码页写文本的方式Excel 打开时按 UTF-8 解读失败或者模板单元格字体不支持中文。解决统一用 dxSpreadSheet 的单元格赋值避免字符串拼接。若必须走导出函数先确认导出格式确实是 xlsx 而不是改后缀的 CSV。模板里把常用文本列预先设置成中文字体基本能根治。5.5 老工程迁到 10.4 后第一次编译报找不到 dxSpreadSheet 单元现象从 10.3 或 10.2 搬过来的工程10.4 下编译报“File not found: dxSpreadSheet ...”。原因旧工程的项目搜索路径里仍记录着旧 IDE 的库路径新 IDE 的 Library path 也没有包含 20.2.4 的单元目录。解决在 Project Options Delphi Compiler Search path 里补上 DevExpress 的源码头和 lib 目录不要只删路径先确认 20.2.4 安装目录存在。这个坑看着低级但团队共享工程时最容易踩因为每个人机器上组件安装位置不同工程里往往会存下一份绝对路径。这一章列出的坑大多是 BPL 残留、路径残留、DPI 行为和编码习惯导致的和业务逻辑关系不大。你把基础环境理顺后面写代码的时间会宽裕很多。6. 最后落地我保留的一个进阶习惯——把布局和皮肤选择交给启动代码做桌面客户端这几年我有一个保留习惯所有会长期使用的窗口都必须把 cxGrid 的列宽、排序和筛选状态保存下来。用户调整好的列顺序关掉再打开就恢复成原样这件事对体验的提升比你想的大。procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); begin // 关闭窗口时把当前网格布局写入 ini路径放在 exe 同目录方便转移配置 cxGrid1DBTableView1.SaveToIniFile( ChangeFileExt(Application.ExeName, .ini), MainGrid); end;对应的恢复逻辑放在 FormShow 里procedure TMainForm.FormShow(Sender: TObject); begin // 配置文件存在时才恢复首次运行时没有该文件保持默认布局 if FileExists(ChangeFileExt(Application.ExeName, .ini)) then cxGrid1DBTableView1.LoadFromIniFile( ChangeFileExt(Application.ExeName, .ini), MainGrid); end;这段代码里有两个小细节SaveToIniFile 的第二个参数是段名不同窗口用不同段名避免互相覆盖LoadFromIniFile 之前一定要判断文件是否存在否则第一次启动会弹异常。另一个习惯是皮肤选择不写到注册表而是写到 ini这样拿不到注册表权限的机器也能切换皮肤。在代码里读取 ini 里的 SkinName再走一遍 4.1 的注册与启用流程即可。20.2.4 和 10.4 这个组合我用下来最大的体会是按版本线管理组件不要图新去装跨版本包。版本混用带来的隐性工时远远超过你升级一个新功能省下来的时间。希望帮到你。本文还有配套的精品资源点击获取