简介面向 Delphi 与 C Builder 开发者的 DevExpress ExpressBars Suite v6.37 控件套件专注解决工具栏、菜单、状态栏与导航栏等界面组件的快速构建与深度定制问题适合需要在 Windows 桌面应用中实现专业 UI 的中高级开发者。压缩包共 912 个文件约 9.17MB主要包含 pas/cpp 源代码、dpk/bpk 工程包、dfm 窗体定义以及 res 资源文件等便于阅读控件实现并直接集成到开发环境。该版本内含完整源码可通过源码深入理解 XP 主题管理、GDI 绘图、国际化支持等底层机制。资源还附带 BarsDemo、RibbonNotepadDemo 等多个示例工程覆盖常用场景方便对照学习。目前已有 220 人学习对想要掌控 DevExpress 界面组件工作原理的开发者来说是难得的可读源码的完整资源。 DevExpress ExpressBars Suite v6.37 for Delphi/BCB 这套含完整源代码的组件包是我近几年维护老项目时翻得最多的东西。不少同行觉得DevExpress是给新Delphi用的其实在Delphi 7和CBuilder 6那个年代ExpressBars几乎已经是工具栏、菜单栏、停靠面板的默认选择。它解决的也不是“放一个按钮”这种小事而是把菜单、工具栏、右键菜单、快捷键、图标、皮肤全部统一到一套体系里这在老项目里能省下大量代码。含完整源代码这一点尤其重要组件在今天的操作系统上出问题时你可以直接打开源码定位而不是对着闭包组件干瞪眼。如果你手里也有一份ExpressBars v6.37的安装包或者正在维护一个用Delphi 7/BCB 6写的旧系统这篇东西应该能帮你把它的价值完整榨出来。我会从安装时的坑、源码调试体验、实战编排、以及和新版组件混用这四条线展开每个问题都是我在实际项目里真金白银趟过的。1. 这套老组件如今仍值得翻出来的三个理由1.1 它解决的从来不是“放一个按钮”的问题Delphi 7自带的TMainMenu和TToolBar在简单界面上完全够用。可一旦业务命令数量超过几十个你会发现同一批操作要在菜单、工具栏、右键菜单里反复出现每个地方都要单独维护一份OnClick启用禁用状态还得手动同步。ExpressBars的思路是先用TdxBarManager统一建立命令池每个命令对应一个TdxBarItem对象然后菜单、工具栏、右键菜单只是把同一个Item挂载到不同容器里。好处很明显命令的业务逻辑只写一次状态控制也只做一处展示层随便换。v6.37这一代的TdxBarManager稳定性和资源占用控制得都不错。我在老项目里见过连续运行几个月的POS终端工具栏菜单照常工作没有出现句柄泄漏或GDI对象暴涨的问题。当然它也有老组件常见的毛病在高DPI屏幕上显示会发虚部分控件对Unicode的支持不够彻底。但瑕不掩瑜对维护期系统来说功能稳定比花哨重要这也是很多老Delphi项目迟迟不愿意动这块的原因。1.2 有源码和没源码维护成本完全是两个量级闭包组件是个黑盒出问题时只能靠猜。v6.37含完整源代码意味着我可以把断点直接打进dxBar.pas里看工具栏按钮在点击时到底走了哪条消息链路。比如有一次项目里工具栏按钮的Hint显示乱码我顺着源码发现是内部处理WM_Notify时对宽字符转换的兼容分支有问题直接在自己的副本里改了处理逻辑问题当场解决前后不到半小时。另一个实际价值是裁剪。老安装包里有些单元你用不到比如dxBarExtDB、dxBarExtCtrls这类扩展包在源码级别上可以按需排除有效缩小DCU体积也避免引入不必要的依赖。这在新版组件里反而不容易做到因为新版包和包之间互相依赖严重删掉一个文件可能拖垮整个单元引用链。有源码的老版本反而成了最能“做减法”的选择。1.3 老版本本身也是理解DevExpress组件架构的教科书如果你用过新版DevExpress VCL会发现很多命名和设计思路都能在v6.37里找到源头。比如TdxBarItem和TdxBarButton这对类关系新版的TdxBarButton依然存在只是加了更多属性和事件。读一遍老源码等于掌握了DevExpress VCL控件体系的一条主线。很多技术交流里聊到“DevExpress控件怎么扩展”底层逻辑其实都在这一套源码里。2. 安装到Delphi 7/BCB 6三个让新手卡壳的关口2.1 安装顺序不对后面全是“File not found”ExpressBars v6.37依赖底层的ExpressCore库。解压之后你会看到源码目录里不只有dxBar.dpk还有dxCore.dpk以及其他一些基础包。正确顺序一定是先编译dxCore再编译dxBar最后编译设计期包。如果跳过dxCore直接打开dxBar.dpkDelphi会立刻报File not found: dxCore.dcu。这个报错很多新手遇到过根源不在文件缺失而在前置包没有编译。具体操作大致是这样在Delphi 7里打开dxCore.dpk点Compile然后点Install再打开dxBar.dpk同样先Compile再Install最后处理带Designtime或RunTime标识的扩展包。BCB 6的流程类似但CBuilder的包管理器会把编译产物放到Lib目录下如果你之前手动改过Lib路径需要确认dxCore.lib在搜索范围内。顺序对了后面就顺了。2.2 从报错到定位的完整排查链路假设你现在编译dxBar.dpk就报错先别急着把整个目录重新拷一遍。按下面这条链路走一遍基本都能定位。这套排查顺序我在不同机器上验证过多次顺序不能乱因为前置错误往往会掩盖真实原因先看报错信息里缺失的是DCU还是LIB文件。如果是DCU大概率是前置包没有编译或者搜索路径没包含源码目录。打开Project Options Directories/Conditionals在Search path里把ExpressBars源码根目录和ExpressCore源码目录都加进去。这一步能解决一半问题。确认你用的是不是同一套Delphi版本生成的DCU。v6.37年代没有统一DCU格式Delphi 7的DCU不能给BCB 6用反过来也不行。如果你机器上装了多个Delphi版本最容易发生这种串用。如果还报错打开Packages窗口看dxCore运行时包是否真的处于Installed状态。有时候Compile成功但Install失败后续包一样找不到类型库。2.3 路径里别带空格和中文这不是玄学老版本组件对路径的容忍度很低。ExpressBars v6.37的源码包如果解压到带空格的目录比如C:\Program Files\DevExpress\ExpressBars编译时会出现Unit not found或者Cannot open file这种随机问题。原因是老的Borland编译器在处理搜索路径时对空格的分割策略并不完善。建议直接放在C:\DX\ExpressBars\这样的纯英文短路径下能避掉大量莫名其妙的问题。中文路径就更别试了那个年代的IDE对编码的处理还没到今天这么成熟的水平。3. 有源码之后调试与定制才是这份包最大的价值3.1 把断点打进去组件内部逻辑一览无余闭包组件遇到疑难杂症只能开Ticket等回复含源码的组件则可以直接在本地加断点观察。我印象最深的一次是排查工具栏按钮的OnClick没有触发。表面上看是事件没挂上跟踪源码后发现TdxBarButton在Down状态下点击会走另一个消息分支事件分发的位置和普通按钮完全不一样。如果没源码这一步至少得猜一两天。类似的还有按钮图标不刷新、下拉菜单宽度计算错误、快捷键注册冲突等问题这些问题在源码里都有清晰的线索。源码调试的另一个好处是能看到DevExpress内部的防御性写法比如对nil的判断、对旧Delphi版本的兼容分支。这些经验写进自己的代码里也很有用算是一份很高质量的参考资料。3.2 一个真实魔改案例给所有工具栏按钮统一加提示前缀有一回我接手的项目界面要求所有按钮Hint统一显示成“功能-说明”的格式。如果逐条改设置几十个按钮要改半天。有了源码我直接在自己维护的dxBar.pas副本里找到Hint属性的读取方法在返回前做了前缀拼接。这样全部按钮自动生效改动面最小。当时改的位置大致在TdxBarItem.GetHint或者DoGetHint相关方法里。这里要提醒一句改源码要有版本管理意识。我习惯把改过的单元文件名保留原名但在工程里单独建一个Patches目录并把修改点用注释标记好。这样升级包版本或者对比原始代码时能快速知道自己动了什么不会在半年后看着一坨改动线索发懵。3.3 源码里被忽略的三个扩展点第一TdxBarManager的OnClick事件。它不只是转发Click还会把Item的Tag、Name、Category传出来适合做统一命令分发。第二TdxBarButton的重绘相关虚方法比如DoPaint可以在这里给按钮增加自己的视觉元素。第三TdxBarEditorCloseUp等与下拉交互相关的方法适合定制下拉面板行为。这三个扩展点是老项目里最常用的“半官方”魔改位置比在线程里发消息控制界面要稳妥得多。4. 从空窗体到完整布局ExpressBars实战编排的几个套路4.1 先理清Manager、Bar、Item三者关系刚接触ExpressBars的人容易被TdxBarManager、TdxBar、TdxBarItem这几个类绕晕。简单记法TdxBarManager是整个体系的根它持有两个集合——Bar集合和Item集合Item是“命令”Bar是“容器”。菜单栏、工具栏、右键菜单都是Bar只是配置属性不同。你往一个Bar里塞几个Item再往另一个Bar里塞同样的Item两个地方的操作状态自动同步因为底层引用的是同一个Item对象。这个设计与Windows的Command-based UI思想一脉相承。老项目里几十个菜单项和工具栏按钮不乱就是因为所有按钮共享同一个命令池状态管理只发生在一处。理解这一点后你会明白为什么ExpressBars的老用户都不太愿意退回原生控件的写法。4.2 动态生成菜单和工具栏的代码骨架在没有窗体设计器的环境下完全用代码创建一组工具栏也很快。核心流程是创建TdxBarManager创建Bar往Bar里添加Item给Item绑定事件。下面这段是我在维护项目里反复用到的简化版procedure TMainForm.SetupToolbar; var AMgr: TdxBarManager; ABar: TdxBar; AItem: TdxBarButton; begin AMgr : TdxBarManager.Create(Self); AMgr.Style : bmsUseLookAndFeel; ABar : AMgr.Bars.Add; ABar.Caption : Main; ABar.DockPos : 0; AItem : TdxBarButton.Create(AMgr); AItem.Caption : Open; AItem.Hint : Open file; AItem.Glyph.LoadFromFile(open.bmp); AItem.OnClick : DoOpenFile; ABar.ItemLinks.Add(AItem.Items[0]); end;这里每个类在源码里都是公开的不必非在IDE里拖控件。要注意的是Item的创建者传入AMgr后Item会归AMgr管理不能随便Free需要统一释放时用AMgr.Free即可。v6.37源码里这套生命周期管理写得很清楚。另外如果用的是BCB 6创建Item时还要注意组件归属选项在不同版本里有细微差别以你手头源码为准。动态代码最忌讳自己接管组件生命周期后又在别处释放一段代码里出现两次Free运行时随机崩溃很难查。4.3 老项目里最常见的状态同步技巧菜单项和工具栏按钮经常要随着数据状态一起变化比如没有打开文件时“保存”按钮应该是灰的。最简单的做法是在TdxBarManager.OnUpdate事件里统一刷新。在这个事件里遍历ItemLinks按业务状态修改每个Item的Enabled。因为有命令池机制同一Item在菜单和工具栏里会出现两次但Enabled只改一次所有展示同步生效。另一个常见需求是快捷键。ExpressBars里快捷键并不是挂在Form的KeyPreview上而是通过Item的ShortCut属性注册到内部热键表。源码里能看到它注册的是全局快捷键还是窗体级快捷键这在多窗体项目里关联到焦点问题。处理方式一般是把快捷键统一放在主窗体的BarManager里避免重复注册。很多老项目里还同时用着TClientDataSet的CloneCursor做数据集拷贝用SendMessage在进程间传消息这些老部件和ExpressBars搭配多年早已磨合稳定单独拆出来换新反而不划算。5. 老项目迁移与新版混用时的兼容性避坑5.1 v6.37和现代DevExpress VCL的关键差异维度ExpressBars v6.37新版DevExpress VCL安装包结构独立套件依赖ExpressCore全家桶模块化但依赖复杂单元命名dxBar.pas等短名称多数保留但新增大量单元DPI支持基本不支持字体发虚原生支持High DPI许可证老许可证仍有效但无新授权新订阅制需持续购买包名dxBar_run.dpk等版本化包名带年份后缀如果你只是维护老系统继续用v6.37完全没问题。但如果要开发新项目我不建议再用这个版本。原因不只是功能缺失更在于新操作系统和旧组件之间的兼容风险会随时间不断增加。新版Delphi里老包格式经常需要手动转换才能安装像Delphi 13这类更晚的版本对老组件的兼容支持已经明显收窄。5.2 混用时的DCU冲突与包依赖问题很多项目会同时装新版DevExpress VCL和老的ExpressBars v6.37。这里面的坑在于新版VCL同样包含TdxBarButton、TdxBarManager等类单元名和旧版一样运行时包会按搜索路径顺序加载。如果你把v6.37的源码路径排在系统搜索路径前面新版组件会莫名引用到旧DCU然后报Ambiguous overloaded这类奇怪错误。解决办法是把两套组件彻底隔离老项目单独用一个虚拟机或者单独的用户环境路径新版组件放到另一个目录不要在同一个IDE里同时加载两套新旧版本包。如果实在要共存务必在工程选项里显式指定Unit别名而不是依赖系统搜索顺序。这个教训来自我一次被折腾一下午的排错经历说出来都是泪。5.3 迁移前先做好这三件事再去动代码第一备份。不只是源码备份还要把整个Delphi环境目录、注册表里的包信息、现有DCU产物全部留一份。第二梳理自定义改动。如果你像我在3.2节那样改过源码要把补丁整理成独立文件不要散落在源码包各个角落。第三准备回归清单。ExpressBars涉及面广菜单、工具栏、右键菜单、快捷键、停靠窗口每一块都要有对应的验证用例。做好这三件事迁移失败也能随时回滚心理压力会小很多。最后分享一个我的习惯老项目交接时除了源码和数据库脚本我一定会把对应版本的ExpressBars完整安装包连同所有补丁副本放进项目的ThirdParty目录。有人觉得多余但我在多个项目里用它救过急比如新同事电脑上装不上老IDE时直接从这个目录恢复环境省去满网络找安装包的狼狈。这个习惯我保留到现在也是为什么我对v6.37这套老组件感情这么深的原因。本文还有配套的精品资源点击获取