简介:这份资源是面向 Delphi 与 C++ Builder 开发者的 TMS VCL UI Pack v13.5.11.0 完整源码包,适用于从 Delphi 7 到 13 Florence 的各版本环境,尤其适合需要快速构建专业级 Windows 桌面界面的中高级开发者。压缩包共约 2000 个文件、123.99MB,以 pas 源码、dfm 窗体、dproj/dpr 工程、res/dcr 资源、ico/jpg/png/bmp 图像及 pdf 文档为主,另含 dpk 包文件、csv/xls 数据与少量 cpp、h 头文件,覆盖组件源码、示例工程与素材资源。已有 120 人学习下载。借助完整源码,读者可深入理解按钮、编辑框、列表框、导航抽屉、菜单、状态栏、进度条等控件的设计原理与实现方式,按需定制样式与功能,并参考示例工程快速集成到自己的项目中,提升界面开发效率与代码质量。
1. TMS VCL UI Pack 到底解决什么问题:从一套源码包说起
如果你正在用 Delphi 或 C++Builder 做 Windows 桌面项目,大概率遇到过这种局面:VCL 自带的 TStringGrid、TListView、TPageControl 能用,但客户看一眼就说“太像 2005 年的软件”。想换第三方控件,DevExpress 报价不低,而且源码不给你,出了问题只能等官方更新。TMS VCL UI Pack 就是在这个缝隙里被大量 Delphi 团队选中的方案——它是一套覆盖网格、编辑器、导航栏、日程、图表、富文本、工具栏等常见界面需求的 VCL 控件集合,并且这个版本带 Full Source,也就是完整源码随包提供。
这次拆的是 TMS VCL UI Pack v13.5.11.0,适配 Delphi & CB 7 到 13 Florence。注意版本跨度:从 Delphi 7 一直覆盖到 13,意味着包里同时存在老式 DCU 兼容层和新版编译单元,安装时不能一股脑全编。它适合三类人:一是维护老 Delphi 项目、想低成本升级界面的;二是需要读源码改控件行为的;三是用 C++Builder 但找不到对应 HPP 头文件的。下面按“能装、能用、能改、能排错”的顺序走一遍。
2. 安装与编译:从包结构到 IDE 里真正跑起来
2.1 先看清包里的目录结构再动手
拿到压缩包解压后,不要急着双击任何 dpk。TMS 这类多版本控件包的目录通常按“源码 + 包 + 示例 + 帮助”分层,先花两分钟确认结构,能省掉后面半小时的编译报错。常见布局是根目录下分Source、Packages、Demos、Help几个文件夹,Packages里再按 Delphi 版本号分子目录。
| 目录 | 作用 | 处理方式 |
|---|---|---|
| Source | 全部控件源码单元 | 加入搜索路径,不要手动编译 |
| Packages | 各版本 dpk/dproj 包工程 | 按你的 IDE 版本选对应子目录 |
| Demos | 示例工程 | 用来验证安装是否成功 |
| Help | CHM 或 HLP 帮助 | 可选,装完再看 |
关键点在于:Source是给 IDE 编译时引用的,不是让你单独编译的。很多人翻车的第一个动作就是打开 Source 里的某个 pas 直接 Build,结果一堆条件编译指令报错,因为那些单元依赖包工程里定义的宏。
2.2 按 IDE 版本选择正确的包工程
Delphi 7 到 13 的包格式差异很大。Delphi 7 用的是老式 dpk,从 Delphi 2009 开始引入 Unicode,包内的字符串处理单元完全不同;到 Delphi 10.x 之后又涉及 Win64 目标平台。所以Packages目录下一般会有类似Delphi7、Delphi11、Delphi12、Delphi13这样的子目录,每个里面是一组 dpk。
操作顺序建议这样:
# 以 Delphi 13 Florence 为例,进入对应包目录 cd TMSVCLUIPack/Packages/Delphi13 # 目录里通常有多个 dpk,按依赖顺序编译 # 先编译基础包,再编译依赖它的高级包 ls *.dpk在 IDE 里的等价操作是:File → Open Project,选中基础 dpk,右键 Install。如果包之间有依赖,先装被依赖的那个。判断依赖关系的土办法是看 dpk 的 requires 子句,里面列出的包必须先装好。
提示:Delphi 13 的 IDE 对包签名和搜索路径比老版本严格,装之前先把
Source目录加到 Tools → Options → Language → Delphi → Library 的 Library Path 里,否则编译包时找不到单元。
2.3 编译顺序与搜索路径配置
假设包里基础包叫TMSVCLUIPack.dpk,高级包叫TMSVCLUIPackExtras.dpk,正确顺序是先基础后扩展。每个包装完后 IDE 会提示“是否重新编译依赖包”,选是。全部装完后,组件面板上会出现 TMS 分类页。
搜索路径配置有个容易忽略的点:32 位和 64 位要分别配。Delphi 13 默认可能只配了 Win32 的路径,如果你要编译 Win64 目标,得在 Library Path 里把平台切到 Windows 64-bit 再加一遍Source路径。C++Builder 用户还要额外确认 HPP 头文件生成选项是否打开,否则 C++ 侧引用控件时会提示找不到头文件。
// 验证安装是否成功的最小工程代码 procedure TForm1.FormCreate(Sender: TObject); var Grid: TTMSFNCGrid; begin Grid := TTMSFNCGrid.Create(Self); Grid.Parent := Self; Grid.Align := alClient; Grid.Cells[0, 0] := '安装成功'; end;这段代码的作用是运行时动态创建一个 TMS 网格控件并填一个单元格。如果编译通过且运行后窗口里出现网格,说明包安装和路径配置都没问题。参数上Parent必须设,否则控件不显示;Align := alClient让它铺满窗体,方便肉眼确认。
3. 核心控件上手:网格、编辑器与导航栏的实战配置
3.1 TAdvStringGrid 的数据绑定与性能参数
TMS 里用得最多的控件之一就是 TAdvStringGrid,它比 VCL 自带 TStringGrid 多了排序、过滤、合并单元格、内嵌按钮等能力。数据量大的时候,性能差异非常明显。默认配置下,往网格里灌一万行数据,如果每写一个单元格都触发重绘,界面会卡到怀疑人生。
正确做法是先关掉重绘再批量填:
procedure TForm1.LoadData; var I: Integer; begin AdvStringGrid1.BeginUpdate; // 暂停重绘 try AdvStringGrid1.RowCount := 10001; // 含标题行 for I := 1 to 10000 do begin AdvStringGrid1.Cells[0, I] := IntToStr(I); AdvStringGrid1.Cells[1, I] := 'Item ' + IntToStr(I); end; finally AdvStringGrid1.EndUpdate; // 恢复重绘并刷新 end; end;BeginUpdate/EndUpdate是这类网格控件的标准性能开关,作用是把多次重绘合并成一次。参数上RowCount要设成数据行数加一,因为第 0 行通常是标题。如果数据源是数据库,更推荐用DataSource属性直接绑定 TDataSource,让控件自己管理游标,比手动填 Cells 快得多,也少写很多同步代码。
3.2 富文本与 HTML 编辑器的取舍
TMS 包里带富文本编辑能力,常见的是 TAdvRichEditor 这类控件。它的定位是轻量级富文本,支持基础格式、图片插入、HTML 导入导出。如果你的需求只是让用户加粗、改颜色、插个表格,它够用;但如果要完整 CSS 渲染、复杂排版,它和浏览器内核不是一回事,别指望它当 Word 用。
配置时重点看两个属性:ReadOnly和HTMLMode。ReadOnly控制是否允许编辑,HTMLMode决定导出内容是完整 HTML 文档还是片段。导出片段更适合嵌入已有页面,导出完整文档则自带 head 和 body。
// 把编辑器内容导出为 HTML 片段 procedure TForm1.ExportHTML; begin AdvRichEditor1.HTMLMode := hmFragment; AdvRichEditor1.SaveToFile('output.html'); end;hmFragment表示只导出 body 内部内容,适合后续拼接到模板里。如果选hmFull,导出的文件可以直接用浏览器打开预览。这里没有玄学,就是看你的下游怎么消费这段 HTML。
3.3 导航栏与页面切换的状态管理
TMS 的导航类控件(如 TAdvToolBar、TAdvPageControl)在复杂窗体里能明显减少手写布局代码。但页面切换时有个常见问题:页面上的控件在页面未激活时是否已创建。如果用了延迟创建,第一次切到某页时会有短暂卡顿;如果全部预创建,启动又慢。
折中方案是预创建轻量页面,重量级页面(含大网格、图表)延迟到第一次切换时再建。判断逻辑放在OnChanging或OnChanged事件里:
procedure TForm1.AdvPageControl1Changing(Sender: TObject; var AllowChange: Boolean); begin if (AdvPageControl1.ActivePage = tabHeavy) and not HeavyPageBuilt then begin BuildHeavyPage; // 首次进入时才构建 HeavyPageBuilt := True; end; end;AllowChange默认 True,除非你要阻止切换。HeavyPageBuilt是个布尔标志,防止重复构建。这个模式在仪表盘类应用里很实用,启动速度能快一截。
4. 源码级定制:改控件行为与 C++Builder 互操作
4.1 读懂 Full Source 的条件编译结构
带 Full Source 的最大价值是能改。但 TMS 的源码里条件编译指令很多,直接改公共单元容易在下次升级时冲突。稳妥做法是:先找到你要改的那个方法,确认它没有被多个平台分支包裹,然后在你的工程里用继承方式覆盖,而不是直接改原文件。
比如你想改网格某个单元格的绘制逻辑,标准姿势是新建一个类继承 TAdvStringGrid,重写DrawCell或对应的绘制方法,把自定义逻辑放进去。这样原包升级时你的改动不受影响。
type TMyGrid = class(TAdvStringGrid) protected procedure DrawCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState); override; end; procedure TMyGrid.DrawCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState); begin inherited; // 先执行父类默认绘制 if (ACol = 0) and (ARow > 0) then Canvas.Brush.Color := clInfoBk; // 自定义首列背景 end;inherited不能省,否则父类的绘制逻辑全丢,单元格会变成空白。AState里包含是否选中、是否聚焦等信息,按需判断。
4.2 C++Builder 侧的 HPP 生成与引用
C++Builder 用户装完包后,如果组件面板能看到但代码里#include报错,多半是 HPP 没生成。Delphi 编译包时有个选项叫“Generate C++ headers”,默认可能没勾。重新编译包时勾上,或者在 Project Options 里确认。
C++ 侧引用 TMS 控件的头文件命名规则通常是单元名加.hpp,比如TAdvStringGrid对应AdvGrid.hpp。如果找不到,去包的输出目录里搜一下实际生成的文件名,不同版本命名可能有细微差别。
// C++Builder 中动态创建 TMS 网格 #include <AdvGrid.hpp> void __fastcall TForm1::FormCreate(TObject *Sender) { TAdvStringGrid *grid = new TAdvStringGrid(this); grid->Parent = this; grid->Align = alClient; grid->Cells[0][0] = "C++ 侧创建成功"; }注意 C++ 里属性赋值用->,字符串用双引号。Cells[列][行]的索引顺序和 Delphi 的Cells[列, 行]一致,别写反。
4.3 版本升级时的源码合并策略
从 v13.5.x 升到下一个版本时,如果你改过源码,直接覆盖会丢改动。建议用 Git 管理你修改过的文件,升级时先拉官方新包,再把你的改动以补丁形式应用。TMS 的更新频率不低,养成这个习惯能省很多后悔药。
5. 避坑与排查:安装、编译、运行时的常见问题
5.1 装完包组件面板不出现
现象:dpk 编译安装成功,但 Tool Palette 里找不到 TMS 分类。原因通常是 IDE 的组件页缓存没刷新,或者包被装到了错误的 IDE 实例(比如同时装了 Delphi 12 和 13,装到了 12 里)。解决:重启 IDE;确认 Tools → Options → Environment → Delphi Options 里的包列表中有对应包且已勾选;检查是不是多版本 IDE 装混了。
5.2 编译时报找不到某个 dcu
现象:编译你的工程时提示TMSxxx.dcu not found。原因:Library Path 里没加Source目录,或者加了但平台不对(Win32 加了,Win64 没加)。解决:按目标平台分别配置搜索路径;确认路径指向的是Source而不是Packages;如果用了相对路径,确认工程移动后路径没失效。
5.3 运行时控件显示为空白或错位
现象:窗体设计器里正常,运行时网格或导航栏空白、错位。原因:常见于高 DPI 缩放场景,TMS 控件的 DPI 感知设置和你的工程清单不一致。解决:在工程选项里统一 DPI 感知级别;检查控件的ScaleBy相关属性;如果是多显示器不同缩放,确认窗体创建时的 PixelsPerInch 处理。
5.4 C++Builder 链接时报重复符号
现象:C++ 工程链接阶段报 multiple definition 或重复符号。原因:同一个 TMS 单元被 Delphi 包和 C++ 静态库同时引入。解决:确认只通过包方式引用,不要在 C++ 工程里再手动添加 pas 文件;检查包列表里是否有重复安装的 TMS 包版本。
5.5 升级 Delphi 版本后包编译失败
现象:从 Delphi 12 升到 13 后,原来能编的 TMS 包报错。原因:新版本 IDE 的编译器对某些老式语法或已废弃单元更严格。解决:用新版本对应的Packages子目录里的 dpk,不要拿旧版 dpk 硬编;如果官方还没出对应版本,看Source里是否有条件编译开关能绕过废弃 API。
6. 进阶技巧:把 TMS 控件用出差异化的几个习惯
第一个习惯是给每个 TMS 控件写一个薄封装单元。不要直接在业务窗体里散落AdvStringGrid1.Cells[...]这种调用,而是包一层TMyGridHelper,把常用配置(列宽、排序、导出)收进去。这样换控件或升级时只改一个地方。我见过一个项目因为没做这层,后来从 TMS 换到另一套控件,改了三百多个文件。
第二个习惯是利用 Full Source 做“只读侦察”。遇到控件行为不符合预期时,别急着搜论坛,直接打开对应源码单元,看那个属性 setter 里到底做了什么。比如你设了某个颜色不生效,源码里可能有个条件判断把它覆盖了。这种第一手信息比任何文档都准。
第三个习惯是导出功能统一走一个入口。TMS 网格和富文本都支持导出 HTML、CSV、PDF(部分控件),但每个控件的导出 API 不一样。写一个IExportable接口,让需要导出的控件适配它,业务代码只调接口。下面是个简化示例:
type IExportable = interface procedure ExportTo(const AFileName: string); end; TGridExporter = class(TInterfacedObject, IExportable) private FGrid: TAdvStringGrid; public constructor Create(AGrid: TAdvStringGrid); procedure ExportTo(const AFileName: string); end; procedure TGridExporter.ExportTo(const AFileName: string); begin FGrid.SaveToCSV(AFileName); // 具体导出格式按需换 end;TInterfacedObject提供引用计数,ExportTo里调具体控件的保存方法。这样业务侧只依赖IExportable,不依赖具体控件类型。
最后一个习惯是版本锁定。TMS 每个小版本都可能修 bug 也可能引入新 bug,团队里要统一用一个版本号,写进工程文档。升级前先在分支上跑一遍所有用到 TMS 的窗体,确认没有视觉和交互回归再合并。从那以后我每次拿到新版本包,都先在一个空白工程里装一遍、跑一个最小示例,确认没问题才往主工程里引。希望帮到你。
本文还有配套的精品资源,点击获取