
简介这是TMS VCL UI Pack v13.4.0.1的完整源码包专门面向使用Delphi 7至12 Athens及CBuilder的程序员适合在企业级Windows桌面应用开发中快速构建现代界面。整套组件包含界面布局、图表、网格、导航、皮肤、多媒体等常用VCL单元能够大幅减少控件设计与交互逻辑的重复编码工作。压缩包共2000个文件、123.13MB其中502个pas源码文件、240个dfm窗体、228个dproj工程、211个dpr项目配合res、ico、png、jpg等图形资源以及47个pdf、43个csv、11个mdb等文档与示例数据库能覆盖从设计期到运行期的各类使用场景方便逐一对照工程验证功能。已有45人学习下载适合希望深入组件内部实现、排查版本兼容性或在RAD Studio不同版本间迁移项目的开发者。通过阅读源码和官方示例可以掌握TMS控件的对象关系与事件机制并在此之上定制满足自身业务需要的拓展组件。1. Delphi 12.3 下重新认识 TMS VCL UI Pack Full SourceDelphi 12.3 Athens 发布后老项目里最尴尬的不是语法升级而是原来那批控件在新的 IDE 里“失联”。TMS VCL UI Pack v13.4.0.1 Full Source 就是典型例子标题看起来像资源文件背后其实是三件事——RAD Studio 12.3 的 IDE 兼容、Delphi 与 CBuilder 两套工程下的包格式差异、以及 Full Source 带来的可调试边界。实际装起来最耗时间的不是控件本身的功能而是包顺序、Library Path、bpl 冲突这些环境问题。这篇文章按安装、编译、写代码、排错的顺序展开代码基于 RAD Studio 12.3 的默认工程结构给出适合正在维护老 VCL 项目的工程师也适合第一次往 Community Edition 里补控件的人。2. TMS VCL UI Pack 的包机制与 Full Source 的调试价值2.1 一套包两个入口.dpk 与 .cbprojTMS VCL UI Pack 在发布时会同时准备好 Delphi 和 CBuilder 两套工程文件。Delphi 侧是 .dpk 文件Package 工程CBuilder 侧是 .cbproj 或 .bdsproj。它们的职责一样把 Source 目录下的 .pas 单元编译成 .bpl 动态库并生成编译器所需的 .dcuDelphi或 .lib/.bpiCBuilder。一套源码两套构建入口这是 VCL 控件包最常见的组织方式。打开一个典型的 .dpk能看到这样的结构package tmsvcluipack_runtime; {$R *.res} requires rtl, vcl; contains AdvStyle in Source\AdvStyle.pas; AdvGrid in Source\AdvGrid.pas; AdvGlowButton in Source\AdvGlowButton.pas; end.这段代码定义了一个名为tmsvcluipack_runtime的包。requires声明它依赖 RTL 和 VCL 基础包contains列出要编入包的具体单元。编译成功后生成tmsvcluipack_runtime.bplIDE 启动时加载这个 bpl控件才能出现在组件面板上。CBuilder 侧的过程类似但链接时用的文件换成了 .lib运行时仍然依赖同名 .bpl所以两边共用一套二进制包是可行的。2.2 Full Source 拿到的不只是源码还有进入调试的路径“Full Source” 这个概念经常被低估。它真正改变的是调试方式F7 按下后IDE 能跳进控件的 .pas 源文件而不是停在 CPU 窗口里看汇编。要做到这一点光有源码不够还得保证源码路径被编译单元索引到否则 IDE 只会把源码当成普通文本文件。验证 Full Source 是否生效有一个很直接的办法。在窗体代码里写一行AdvStringGrid1.RowCount : 10;在它后面打断点F7 步进。如果跳到了AdvGrid.pas的具体实现说明源码路径解析正常如果跳进汇编窗口问题不在包在 Library Path。这个检查在新装任何控件包后都值得做一次半小时能省下后面好几个晚上的排查时间。2.3 Runtime 包与 Design 包安装顺序决定能不能看到控件TMS 的包按作用分两类。Runtime 包提供编译单元Design 包负责把控件注册到 IDE 组件面板。Design 包编译时依赖 Runtime 包的 bpl顺序错了就会提示找不到某个包。先编 Runtime再编 Design这个顺序基本不会出问题。包类型产物组件面板作用Runtime 包.bpl .dcu / .lib不出现提供编译和链接所需的单元Design 包.bpl出现注册控件显示属性与事件安装时最容易犯的错误是只装了 Design 包。这样 IDE 面板能看到控件但编译工程时会报找不到单元因为 Runtime 包对应的 .dcu 没有进入搜索路径。反过来只装 Runtime 包工具栏是干净的代码里能 uses但设计期看不到图形化控件。2.4 从 7 到 12条件编译与 Unicode 迁移TMS 声称覆盖 Delphi CBuilder 7-12这个跨度靠的是条件编译和宏判断。Delphi 7 时代是 AnsiString 为主2009 年引入 Unicode 后字符串类型发生了根本变化。控件内部常见的写法是{$IFDEF UNICODE} s : Edit1.Text; // UnicodeString {$ELSE} s : Edit1.Text; // AnsiString {$ENDIF}这套机制保证了同一份源码在不同版本下行为一致。对使用者来说真正要注意的是老工程迁移到 12.3 时PChar和PAnsiChar的混用会暴露出来。TMS 控件表面上看编译很顺但自己代码里的AnsiString(控件.Text)强制转换在 Delphi 12.3 下会得到截断数据。迁移时优先用string不要反向转 Ansi。CBuilder 侧同理UnicodeString和std::string之间的转换需要用TEncoding做过桥直接强制转换在东亚字符集环境下容易出现乱码。3. 在 RAD Studio 12.3 Athens 里安装 TMS VCL UI Pack3.1 解压后先看目录结构再决定装哪些包拿到 v13.4.0.1 的压缩包不要直接双击某个 dpk 就开始装。先完整解压到一个单独的组件目录我一般放在C:\Components\TMSVCLUI。目录结构通常包含这几个部分目录内容作用Source.pas 源文件编译包的源码也是调试时进入的文件Packages.dpk 与 .cbproj各类控件的包工程文件Lib预编译的 .dcu 和 .bpl如果发布版带的话可以跳过编译直接用Docs帮助文档CHM/HTML查阅具体控件的属性说明解压路径不要含中文也不要放到C:\Program Files下。Windows UAC 对系统目录有写保护bpl 注册和 dcu 缓存写入都会失败报错信息还不直观。3.2 用 IDE 的 Project Manager 安装 .dpk / .cbproj安装的标准流程是打开 RAD Studio 12.3选择 File Open Project定位到 Packages 目录按名称顺序打开包工程。先选 Runtime 包右键 Compile成功后再右键 Install。然后回头打开 Design 包做相同的两步。File Open Project TMS*.dpk Project Manager 右键包名 Compile Project Manager 右键包名 InstallInstall 动作会往 IDE 的已知包列表里写注册信息组件面板随即刷新。对 CBuilder 来说入口同样是 File Open Project但选择 .cbproj 文件。编译选项里注意目标平台的配置TMS 的包在 32 位和 64 位 Windows 下都要分别编译只在 Win32 下编译过切到 Win64 平台时仍会报找不到包。3.3 Library Path 配错Full Source 等于白拿安装完成后还有一个必做步骤配置 Library Path。路径的位置在 Tools Options Delphi Options Library。把 Source 目录加进搜索路径IDE 在编译工程时才会用自己的编译器重新编译源码而不是依赖预编译的 dcu。C:\Components\TMSVCLUI\Source C:\Components\TMSVCLUI\Packages路径顺序会影响源码冲突时的解析优先级。如果机器上同时还装过旧版本的 TMS较新的 Source 路径要排前面。CBuilder 用户在 C (Shared Options) Paths and Directories 里配置同一批路径另外还要把生成的 .hpp 文件目录加进 Include Path否则#include AdvGrid.hpp会直接失败。3.4 命令行编译 .dpk 的替代路径运维环境或 CI 机器上没有图形界面时可以用 msbuild 编译。RAD Studio 12.3 自带的 msbuild 需要先通过rsvars.bat初始化环境变量call C:\Program Files (x86)\Embarcadero\Studio\23.0\bin\rsvars.bat msbuild C:\Components\TMSVCLUI\Packages\TMSGridLib.dpk /t:Build /p:ConfigRelease /v:m/t:Build对应 IDE 里的 Build 动作和 Compile 的区别是 Build 会检查所有依赖项Compile 只编当前包。/p:ConfigRelease指定 Release 配置避免把调试符号带进运行时。/v:m把日志级别设为 minimal失败时切到/v:d能看到完整命令行列出的 dcc32 参数定位哪个单元编译失败比在 IDE 日志里翻效率高得多。3.5 安装验证三分钟检查清单装完别急着写业务代码用这个清单确认环境。第一新建一个 VCL 工程在组件面板搜索TAdvStringGrid能拖进窗体算过第二往代码里写一行AdvStringGrid1.RowCount : 1F7 能进入AdvGrid.pas算过第三CBuilder 里建一个空工程#include AdvGrid.hpp后编译LNK 错误为零算过。检查项方法通过标准组件面板注册搜索 TAdvStringGrid能拖入窗体源码调试赋值后 F7 步进进入 .pas 源码CBuilder 链接#include 头文件后编译无 LNK 错误三个检查都过才说明包安装到位。任何一步失败回头翻 3.2 的包顺序和 3.3 的路径配置问题基本出在那里。4. 实战用 TAdvStringGrid 做一个可跑的网格界面4.1 设计期放置控件与 DFM 属性TMS VCL UI Pack 里最常用的是 TAdvStringGrid。它在设计期的表现类似 StringGrid但对单元格格式化、合并、排序和导出支持更好。从组件面板拖一个到窗面上把ColCount设为 3RowCount设为 6FixedRows保留为 1用来做表头。对应 DFM 描述大致是object AdvStringGrid1: TAdvStringGrid Left 24 Top 24 Width 640 Height 360 ColCount 3 RowCount 6 FixedRows 1 Options [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine] ColumnHeaders.Strings ( 名称 数量 备注) endColCount和RowCount决定网格的维度FixedRows指定顶部冻结行数被冻结的行不会跟着滚动条移动。ColumnHeaders.Strings按列顺序写入表头文字。这里有个容易看错的地方Cells数组的下标[行, 列]和视觉上“先列后行”的顺序相反写数据时容易把行列颠倒。4.2 运行时动态创建 TAdvStringGrid设计期拖控件省事但动态创建更接近真实业务场景比如从配置文件决定网格的列数。动态创建的代码也不复杂procedure TForm1.CreateGrid; var Grid: TAdvStringGrid; begin Grid : TAdvStringGrid.Create(Self); Grid.Parent : Self; Grid.Left : 16; Grid.Top : 16; Grid.Width : 620; Grid.Height : 300; Grid.ColCount : 3; Grid.RowCount : 4; Grid.FixedRows : 1; Grid.Cells[0, 0] : 名称; Grid.Cells[1, 0] : 数量; Grid.Cells[2, 0] : 状态; Grid.Align : alTop; Grid.Visible : True; end;Create(Self)传入 Self 作为 Owner窗体销毁时控件会自动释放不需要手动 Free。Parent决定控件显示在哪个容器上漏掉这一步控件创建成功但看不见。Align : alTop在设置完位置后再付避免对齐方式覆盖手动指定的 Left 和 Top。CBuilder 侧的写法结构一样TAdvStringGrid* grid new TAdvStringGrid(this); grid-Parent this; grid-Width 620; grid-RowCount 4; grid-ColCount 3; grid-FixedRows 1; grid-Cells[0][0] 名称;4.3 常用属性与事件参数对照TAdvStringGrid 的使用频率高初始化阶段以下几个属性最常调属性类型作用常见误用RowCountInteger总行数忘记加表头行ColCountInteger总列数数据行写入越界FixedRowsInteger冻结表头行数设为 0 后表头滚动OptionsTGridOptions是否可编辑、拖拽等全部打开后误触编辑态事件侧最常用的是OnClickCell它的参数里带Col和Row在单元格点击时做联动操作。还有OnGetAlignment可以针对单列动态返回对齐方式比在设计期逐列设置Alignment灵活。需要注意OnClickCell的触发条件是鼠标按下弹起拖拽选区的过程中不会触发需要拖拽场景时改用OnMouseDown补判断。4.4 SQLite 中文乱码与 UTF-8 转换Delphi 12.3 是 Unicode 体系TMS 控件内部用的是UnicodeString本身不会乱码。乱码通常出在数据接入层SQLite 默认以 UTF-8 存储文本如果用AnsiString直接接收中文会变成“锟斤拷”。常见做法是把 SQLite 接口取到的TBytes显式转成 UTF-8 字符串var Raw: TBytes; Value: string; begin Raw : SQLite3GetColumnBytes(Stmt, 0); Value : TEncoding.UTF8.GetString(Raw); AdvStringGrid1.Cells[0, 1] : Value; end;TEncoding.UTF8.GetString把原始字节数组按 UTF-8 规则解码为UnicodeString这样再写入网格就不会变形。如果数据源本身是 UTF-16例如从 .NET 导出的数据直接取字符串赋值即可不用做转换。判断依据是数据源的导出声明SQLite 默认按 UTF-8 处理MySQL 旧版本则按连接字符集走不能一概而论。4.5 CBuilder 侧的使用差异CBuilder 调用 TMS 控件时需要注意.hpp头文件的引入时机。#include Vcl.AdvGrid.hpp要放在窗体头文件之前否则窗体类里声明 TAdvStringGrid 成员时编译器会报未定义类型。动态创建时new TAdvStringGrid(this)后同样要先-Parent this再设置其他属性。编译命令里#pragma link tmsvcluipack_runtime.lib通常不需要手写因为 .cbproj 里已经包含了链接库路径手写反而容易因为路径硬编码导致换机器后编译失败。5. 三个典型坑与一个验证技巧5.1 找不到 .bpl先查 Runtime 包和系统目录Delphi 12.3 下最常见的运行时错误是Cannot load package ... .bpl或... is not a valid package。先确认一件事实报错对应的包是 Runtime 还是 Design。Design 包找不到说明 IDE 注册信息指向了不存在或被移动的 bpl重装 Design 包即可。Runtime 包找不到可能是系统 PATH 环境变量里没有组件目录。TMS 的安装说明一般要求把 bpl 所在目录加入 PATH我习惯的做法是直接把C:\Components\TMSVCLUI\Packages加进去而不是把 bpl 复制到 System32后者会在版本升级时留下旧文件导致 IDE 加载到一个不匹配的旧包错误信息反而更扭曲。5.2 WebView 导航无反应与 WebView2 依赖TMS 的高版本控件里依赖 WebView2 的组件越来越多。遇到导航无反应先检查两个点系统有没有安装 WebView2 Runtime以及控件有没有指定可写的用户数据目录。用户数据目录不设置时控件用默认位置如果被安全软件锁住导航调用会静默失败。设置一个独立的目录能避开大部分问题TEdgeBrowser1.UserDataFolder : ExtractFilePath(ParamStr(0)) EdgeData;ParamStr(0)取当前程序目录加上EdgeData子目录。目录不存在时 WebView2 会自己创建。导航前用InitializeAsync确认初始化状态返回值非零时不要调用 Navigate。5.3 HTTPS 证书无效的托底处理TMS 的 HTTP 控件在请求 HTTPS 接口时如果服务器证书链不完整或证书过期会直接抛证书无效的异常。这个问题的处理应该在完成了正常的证书校验逻辑之后作为内网联调环境的托底手段IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Mode : sslmClient; IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyMode : [];VerifyMode置空表示跳过证书链验证代码能正常握手。这只能用于内网测试或调试阶段外部生产环境关闭所有校验会让数据完整性和保密性完全失效属于硬性风险。留作联调期间的临时方案没问题上线前务必恢复成默认校验或补充正确的根证书。5.4 用 F7 验证安装结果的 30 秒检查装完 TMS 后最快验证调试链路的做法是打开安装时创建的测试工程给AdvStringGrid1的RowCount赋一个新值在当前行打断点按 F7。正常情况下会直接进入AdvGrid.pas的SetRowCount方法。如果停在一个只写mov dword ptr [rax], 5的汇编块上说明 Library Path 里的源码目录没有生效。处理方法是清掉工程目录下的_dcu缓存重新编译大多数情况下是旧 dcu 残留盖住了新源码路径。这个检查动作每次装完控件后只花 30 秒但能确认编译器是否真的在用 Source 目录调试环节的稳定就取决于这一步。本文还有配套的精品资源点击获取