ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Delphi 13 控件 TMS VCL UI Pack 全源码编译与多版本兼容实战

Delphi 13 控件 TMS VCL UI Pack 全源码编译与多版本兼容实战 简介TMS VCL UI Pack v13.5.6.0 是面向 Delphi 与 C Builder 开发者的专业界面控件套件覆盖 Delphi 7 至 13 及 C Builder 7 至 13含 Florence 版本适合需要快速构建现代 GUI 的中高级开发者。套件内含面板、标签、按钮、表格、编辑器、树视图、列表视图、组合框等基础与高级控件并支持皮肤化定制可统一应用外观风格减少重复编码。资源包共约 2000 个文件以 pas 源码、dfm 窗体、dproj/dpr 工程、res/dcr 资源、ico/jpg/png 图像及 pdf 文档为主另有 dpk 包、csv/xml 数据与示例工程压缩包约 123.56MB目录结构完整便于按模块查阅与集成。该版本附带完整源代码读者可研读内部实现、按项目需求修改扩展并借助官方文档与示例项目降低上手成本。目前已有 123 人学习下载适合希望提升界面开发效率与定制自由度的 Delphi/C Builder 用户参考使用。1. Delphi 13 控件之 TMS VCL UI Pack从 Full Source 到可编译工程Delphi 13 发布之后VCL 生态里最常被问到的第三方控件包之一就是 TMS VCL UI Pack。标题里这一串v13.5.6.0 for Delphi CB 7-13 Florence Full Source其实信息量很大它同时支持 Delphi 和 CBuilder覆盖 7 到 13 的编译器版本Florence 是 Delphi 13 的内部代号而 Full Source 意味着你拿到的是带完整源码的版本不是只有 dcus 的二进制包。对一线开发者来说Full Source 的价值不在于“能看”而在于能改、能断点、能跟着调用栈排查玄学问题。这篇笔记面向两类人一类是刚升级到 Delphi 13、准备把老项目里的第三方 UI 控件统一换代的另一类是维护 CBuilder 老工程、需要在 7 到 13 之间做多版本兼容的。我会把安装、编译、源码级调试、多版本共存、踩坑排查这几件事按可复现的步骤讲清楚参数怎么设、失败看哪里都会落到具体位置。控件包本身不神秘难的是让它在你的编译环境里稳定跑起来。2. TMS VCL UI Pack 的组成与 Full Source 编译链路2.1 包结构运行期包、设计期包与源码目录拿到 Full Source 之后第一件事不是急着装而是先看清目录结构。TMS 的包通常分成三层运行期包runtime package命名类似TMSVCLUIPackPkg.bpl、设计期包design-time package负责在 IDE 里注册组件面板、以及源码目录Source下按控件分文件夹比如AdvGrid、AdvSmoothPanel、AdvTreeView。运行期包被你的 exe 依赖设计期包只在 IDE 里加载两者不能混。目录/文件作用是否随 exe 分发Source\*全部控件源码否编译进包即可Packages\Delphi13\*.dpkDelphi 13 的包工程否Packages\CBuilder13\*.cbprojCBuilder 13 的包工程否Lib\*预编译 dcus二进制版才有否Demos\*示例工程否Full Source 版本里Lib目录可能为空或只有少量文件因为源码要你自己编。这一点很关键如果你在 IDE 里直接引用组件却发现找不到 dcus八成是包还没编译。2.2 编译顺序先运行期再设计期编译包有严格顺序搞反了会报“找不到单元”。常见做法是先在 IDE 里打开运行期包工程Build 成功后再装设计期包。下面是我一般在命令行里做的批量编译用dcc32直接编避免 IDE 里逐个点:: 进入 Delphi 13 的包目录先编运行期包 cd /d D:\TMS\Packages\Delphi13 :: -Q 静默-B 全量重建-U 指定源码搜索路径 dcc32 -Q -B TMSVCLUIPackPkg.dpk -U..\..\Source -U..\..\Source\AdvGrid :: 运行期包成功后再编设计期包 dcc32 -Q -B dclTMSVCLUIPackPkg.dpk -U..\..\Source -U..\..\Source\AdvGrid逻辑说明-B强制全量重建避免增量编译时残留旧 dcus 导致的符号冲突-U把源码路径显式喂给编译器这样即使 IDE 的库路径没配全也能过。参数上-U可以重复出现路径多的时候建议写进一个.cfg文件用-Upaths.cfg引用比一长串命令行好维护。编译成功后运行期包会产出.bpl和.dcp。.dcp是给其他包引用用的.bpl是运行时加载的。设计期包依赖运行期包的.dcp所以顺序不能反。2.3 在 IDE 里注册组件面板命令行编完只是有了二进制组件要出现在 Tool Palette 还得在 IDE 里 Install。步骤是Component→Install Packages→Add选中设计期包的.bpl确定后组件会按分类挂到面板上。如果装完面板没出现先检查设计期包是不是真的编译成功再看 IDE 的Library Path里有没有把Source目录加进去——Full Source 版本必须让 IDE 能找到源码否则打开含组件的窗体时会提示找不到单元。提示多版本共存时每个 Delphi 版本要各自编译一套包不要共用同一个输出目录否则 12 和 13 的 dcus 会互相覆盖。3. 用 Full Source 做源码级调试与二次修改3.1 把源码路径接进调试符号Full Source 最大的用处是能单步进控件内部。要让调试器能进源码得保证两件事编译包时带了调试信息且 IDE 的Debugger能找到源码。编译时加-$D生成调试信息和-$L生成局部符号然后在 IDE 的Tools→Options→Debugger→Symbol Tables里把Source目录加进搜索路径。:: 带调试信息编译运行期包 dcc32 -Q -B -$D -$L TMSVCLUIPackPkg.dpk -U..\..\Source-$D让编译器把调试信息写进 dcus-$L保留局部变量符号。少了-$L断点能停但看不到局部变量值排查起来会很痛苦。这一步是很多人忽略的血泪经验装完包发现断点进不去九成是编译时没开这两个开关。3.2 修改源码后如何只重编受影响的包直接改Source下的.pas之后不需要重装整个包只要重新 Build 运行期包再让设计期包重新链接即可。但如果你的 exe 是静态链接没用到运行期包那改完源码必须重新编译你的 exe。这里有个容易翻车的点Delphi 的增量编译有时不会检测到第三方源码的变化导致你改了代码但行为没变。稳妥做法是改完源码后手动Build一次包工程别依赖Compile。// 示例在 AdvTreeView 源码里加一行日志验证调试链路是否打通 procedure TAdvTreeView.DoPaint; begin OutputDebugString(PChar(Format(DoPaint node count%d, [FNodes.Count]))); inherited; end;逻辑说明OutputDebugString会把信息发到调试器的 Event Log用 DebugView 或 IDE 的 Event Log 都能看到。参数是节点数量用来确认你的修改确实被编译进去了。如果日志没出现说明包没重编成功或者你的 exe 链接的是旧 dcus。3.3 二次修改的边界哪些能改哪些别碰Full Source 允许你改任何东西但不代表都该改。我的原则是只改行为层比如绘制逻辑、事件触发时机不动接口层published 属性、方法签名。因为一旦改了 published 接口设计期包注册的组件属性会和源码不一致打开老窗体时可能报“属性不存在”。如果确实要加属性记得同步更新设计期包的注册代码并重新 Install。注意改完源码后如果项目里同时有二进制版和源码版务必确认 IDE 的 Library Path 指向的是源码目录否则编译时可能悄悄用了旧的 dcus。4. Delphi 7 到 13 多版本兼容的编译配置4.1 条件编译用 VER 宏隔离版本差异TMS 的源码里大量使用条件编译来兼容老版本。你自己做二次修改时也要遵循这个套路否则在 Delphi 7 上编不过。核心宏是RTLVersion和CompilerVersion前者对应运行期库版本后者对应编译器版本。// 用条件编译隔离 Delphi 13 与老版本的 API 差异 {$IF CompilerVersion 36} // Delphi 13 的编译器版本号 // 使用新版本才有的 API FCanvas.FillRect(ARect, 1); {$ELSE} // 老版本走兼容分支 FCanvas.FillRect(ARect); {$IFEND}逻辑说明CompilerVersion是数值宏Delphi 13 对应 36具体值以你环境里System.pas的声明为准编译前用{$MESSAGE}打出来确认最稳。参数上FillRect的重载版本在新版里多了圆角参数老版没有所以必须分支。写兼容代码时把版本判断集中在少数几个单元里别散落各处否则维护成本会爆炸。4.2 包工程的多版本管理7 到 13 跨度很大包工程文件.dpk本身格式也变过。常见做法是为每个大版本维护一份.dpk放在Packages\Delphi7、Packages\Delphi13这样的目录下源码共享同一份Source。这样改源码时所有版本都受益只有包定义差异才需要分别维护。版本包目录编译器注意事项Delphi 7Packages\Delphi7dcc32不支持泛型源码需条件编译Delphi 12Packages\Delphi12dcc32支持内联变量Delphi 13Packages\Delphi13dcc32Florence 代号注意新 RTLCB 13Packages\CBuilder13bcc32c头文件需重新生成CBuilder 这边要额外注意Delphi 源码编译成.dcu后C 侧需要.hpp头文件。Full Source 版本通常带Generate C Headers选项编译包时勾上否则 C 工程里#include会找不到声明。4.3 用批处理一次编完所有版本手工切版本编译很烦我一般写个批处理把每个版本的编译命令串起来出错就停。echo off setlocal set TMS_ROOTD:\TMS for %%V in (Delphi7 Delphi12 Delphi13) do ( echo Building %%V cd /d %TMS_ROOT%\Packages\%%V dcc32 -Q -B TMSVCLUIPackPkg.dpk -U%TMS_ROOT%\Source || goto :fail ) echo All packages built. goto :eof :fail echo Build failed, check the version above. exit /b 1逻辑说明for循环遍历版本目录||保证任一版本失败就跳到:fail并返回非零退出码方便接进 CI。参数上-U指向共享的Source这样源码只有一份。如果你的 CI 里要跑这个记得把dcc32的路径加进PATH或者用完整路径调用。5. 安装与编译中的常见问题排查5.1 装完包组件面板不出现现象Install Packages里显示已加载但 Tool Palette 上找不到 TMS 组件。原因通常是设计期包没真正注册或者 IDE 的组件缓存没刷新。解决先确认设计期包的.bpl时间戳是新的然后在 IDE 里Component→Install Packages里 Remove 再 Add 一次最后重启 IDE。如果还不行检查设计期包的Register单元有没有被条件编译掉。5.2 编译报“Unit not found”现象Build 时报找不到AdvGrid之类的单元。原因是 Library Path 没包含Source目录。解决在 IDE 的Tools→Options→Language→Delphi→Library里把Source及其子目录加进Library Path。子目录多的时候用Source\*通配部分版本支持或者干脆把常用子目录都列上。5.3 运行时提示“Package version mismatch”现象exe 启动时报包版本不匹配。原因是 exe 链接的运行期包和系统里加载的.bpl不是同一次编译产物。解决确保 exe 和.bpl来自同一次 Build别混用不同版本的 dcus。多版本共存时把每个版本的.bpl放在各自目录运行时用PATH或 manifest 指定加载哪个。5.4 改了源码但行为没变现象明明改了Source下的代码重新编译 exe 后行为还是旧的。原因是增量编译没检测到第三方源码变化或者 exe 链接的是Lib下的旧 dcus。解决手动 Build 包工程确认 dcus 时间戳更新再检查 Library Path 里Source是否排在Lib前面。最稳的办法是删掉所有 dcus 全量重建一次。5.5 CBuilder 侧头文件不同步现象C 工程里#include报找不到符号。原因是 Delphi 源码改了但.hpp没重新生成。解决在包工程里勾选Generate C Headers重新 Build 一次确认.hpp时间戳更新。如果还是不行检查 C 工程的 include 路径有没有指向新的头文件目录。6. 进阶把 TMS 控件接进现代 Delphi 工程的两个技巧第一个技巧是用运行期包替代静态链接减小 exe 体积并支持热更新控件。做法是把包编译成.bplexe 里用LoadPackage动态加载这样换控件版本时不用重编 exe。代价是部署时要带上.bpl且要处理好包路径。我一般会在项目里加一个启动检查确认包版本和 exe 期望的一致// 启动时校验运行期包版本避免加载到错误版本 procedure CheckTMSVersion; var Pkg: HMODULE; begin Pkg : LoadPackage(TMSVCLUIPackPkg.bpl); if Pkg 0 then raise Exception.Create(TMS runtime package not found); // 这里可以进一步读取包内导出的版本常量做比对 end;逻辑说明LoadPackage返回模块句柄失败返回 0。参数是包文件名实际部署时建议用完整路径避免从系统目录加载到旧版本。这个检查放在Application.Initialize之后、主窗体创建之前最合适。第二个技巧是结合 Delphi 13 的多线程能力把耗时的控件数据加载放到后台线程UI 线程只负责刷新。TMS 的AdvTreeView这类控件在节点量大时同步加载会卡界面。常见做法是用TThread.Queue把节点添加操作切回主线程后台线程只做数据准备。这里要注意控件的任何属性访问都必须在主线程后台线程碰了就是玄学崩溃而且崩得毫无规律。最后一个习惯每次升级 Delphi 大版本我都会先在一个干净虚拟机上从零装一遍 TMS 包把编译日志存下来和上一版对比。这样下次再遇到“装不上”的时候至少有份后悔药可以翻。希望帮到你。本文还有配套的精品资源点击获取
返回列表