简介:本资源为Delphi跨平台UI开发核心组件库TMS FMX UI Pack v3.7.7.5完整源码包,面向使用Delphi 11进行FireMonkey(FMX)开发的中高级桌面与Android应用开发者,解决原生FMX控件数量有限、定制能力弱、跨平台适配成本高等实际问题。压缩包为RAR格式,大小56.74MB,含全部可编译源代码及配套资源,支持直接集成至Delphi IDE并深度二次开发;其中核心为.pas单元文件(实现控件逻辑)、.dfm/.fmx窗体模板(提供可视化示例结构)、.png等资源文件(用于主题与图标),整体构成高度模块化的UI解决方案。目前已有272人学习下载,适合需快速构建专业级多端界面、优化Android端渲染性能、或通过源码级调试解决布局/事件兼容性问题的实战型开发者。
1. Delphi TMS_FMX_UI_Pack_v3.7.7.5 全源码包:为什么一个 FMX 第三方 UI 组件集值得你花两小时搭好本地编译环境?
这不是又一个“下载即用”的控件压缩包。Delphi TMS_FMX_UI_Pack_v3.7.7.5 full source 是一套带完整 .pas 源码、可调试、可深度定制、与 FireMonkey 渲染管线深度耦合的 UI 组件集合——它不只提供按钮、表格、导航栏,更提供TTMSFMXGrid(支持虚拟滚动与 GPU 加速渲染的高性能网格)、TTMSFMXWebGMap(原生封装 Google Maps SDK 的跨平台地图控件)、TTMSFMXCloudUpload(直连 AWS S3 / Azure Blob 的断点续传上传器)等真正解决移动/桌面混合部署痛点的组件。我曾在一个医疗设备数据看板项目中,用它把原本卡顿的 5000 行实时波形表格刷新帧率从 8fps 提升到 52fps;也曾在某高校实验室的跨平台实验记录 App 中,靠修改TTMSFMXNavigationBar的DrawBackground方法,三行代码实现深色模式下状态栏文字自动反色。它适合两类人:一是正在用 Delphi 开发 FMX 跨平台应用、但被原生控件性能/样式/扩展性卡住的中高级开发者;二是需要在客户现场做白标定制、必须能改底层绘制逻辑的交付工程师。别急着双击安装 —— 这个版本的「full source」意味着你必须亲手配置 IDE、处理单元依赖、绕过几个隐藏的编译陷阱,否则连最基础的TMSFMXButton都无法放入窗体。下面,我们从零开始,把这套组件真正变成你 IDE 里可调试、可打断点、可 Patch 的“活”代码。
2. 环境准备与源码集成:在 Delphi 11 Alexandria 中注册 TMS_FMX_UI_Pack_v3.7.7.5 全源码包
2.1 确认 IDE 版本兼容性与前置依赖
TMS_FMX_UI_Pack_v3.7.7.5 官方声明支持 Delphi 10.4 Sydney 至 11.3 Alexandria。但实测发现:若你使用的是 Delphi 11.0(非 Update 1 或更高)且未安装 Windows 10 SDK 10.0.19041.0,则TTMSFMXWebGMap在 Windows 平台编译时会因WebView2Loader.dll加载失败而静默崩溃。这不是组件 Bug,而是 FireMonkey 对 WebView2 运行时绑定的版本敏感性问题。因此,请先执行以下检查:
# 在命令行中运行,确认已安装的 Windows SDK 版本 dir "C:\Program Files (x86)\Windows Kits\10\Lib" /AD /B提示:输出中必须包含
10.0.19041.0或更高(如10.0.22621.0)。若无,请前往 Microsoft 官网下载并安装 Windows 10 SDK 19041(注意:不是 Windows 11 SDK)。Delphi 11.0 默认不附带此 SDK,必须手动安装。
同时,确保已启用 Delphi 的「Design-time Packages」功能:Tools → Options → Environment Options → Delphi Options → Library →勾选 "Enable design-time packages"。这是让组件出现在 Tool Palette 的前提,缺一不可。
2.2 解压源码结构与关键目录识别
解压TMS_FMX_UI_Pack_v3.7.7.5_full_source.zip后,你会看到如下核心目录结构:
| 目录路径 | 用途说明 | 是否必须纳入搜索路径 |
|---|---|---|
\Source\FMX\ | 所有 FMX 组件的.pas源文件(如TMSFMXGrid.pas,TMSFMXCloudUpload.pas) | ✅ 必须 |
\Source\Common\ | 跨平台通用工具单元(TMSFMXUtils.pas,TMSFMXJSON.pas) | ✅ 必须 |
\Source\Win\ | Windows 平台专用封装(TMSFMXWebView2.pas,TMSFMXCloudUploadWin.pas) | ✅ Windows 项目必加 |
\Source\Mac\ | macOS 平台专用封装(TMSFMXWebViewMac.pas) | ⚠️ macOS 项目才需添加 |
\Design\ | 设计时包源码(.dpk文件,如dclTMSFMXUI.dpk) | ✅ 必须编译安装 |
注意:
v3.7.7.5版本中,TMSFMXWebGMap的 Google Maps API Key 注册逻辑已从设计时移至运行时ApiKey属性,这意味着你不能再像旧版那样在 Object Inspector 里填 Key —— 必须在窗体OnCreate中赋值,否则地图将显示灰色方块。这是该版本的重要行为变更,后续章节会详解。
2.3 编译并安装设计时包(dclTMSFMXUI.dpk)
这是让组件图标出现在 Tool Palette 的唯一路径。请严格按顺序操作:
打开
\Design\dclTMSFMXUI.dpk(注意:不是TMSFMXUI.dpk,后者是运行时包);右键点击包名 →
Options→ 切换到Description页 → 将Requires中的rtl、fmx、vcl(如有)保留,删除所有以TMS*开头的依赖项(如TMSFMXCore、TMSFMXUtils)——这些会在编译时自动解析,手动添加会导致循环引用;切换到
Directories/Conditionals页 → 在Search Path中添加以下三行(每行一个路径,用分号分隔):$(TMSFMX_SOURCE)\Source\FMX;$(TMSFMX_SOURCE)\Source\Common;$(TMSFMX_SOURCE)\Source\Win其中
$(TMSFMX_SOURCE)是你自定义的环境变量。强烈建议在Tools → Options → Environment Options → Environment Variables中新增:TMSFMX_SOURCE = D:\Libs\TMS_FMX_UI_Pack_v3.7.7.5_full_source(替换成你的实际解压路径)
这样未来升级版本只需改一个变量,无需重配所有路径。点击
Compile→ 若提示Unit not found: 'System.UITypes',说明你当前 IDE 版本低于 10.4 —— 此包最低要求 Delphi 10.4;编译成功后,右键包名 →
Install。IDE 将弹出确认框,点击Yes。
安装完成后,重启 Delphi。打开任意 FMX 工程,查看 Tool Palette —— 你应该能看到名为TMS FMX UI的新选项卡,内含TMSFMXButton、TMSFMXGrid、TMSFMXNavigationBar等控件图标。
3. 运行时包集成与跨平台条件编译配置
3.1 编译运行时包(TMSFMXUI.dpk)并链接到工程
设计时包只负责 IDE 内拖放,真正运行时逻辑由TMSFMXUI.dpk提供。你不能跳过这一步直接在工程中uses源码单元,否则将触发EAccessViolation(尤其在 iOS/Android 上),因为部分组件依赖运行时包中初始化的全局管理器(如TTMSFMXCloudUploadManager)。
操作步骤:
- 打开
\Design\TMSFMXUI.dpk; Options → Description → Requires中,仅保留rtl、fmx、System、System.Classes——务必删除所有dcl*开头的包名(如dclTMSFMXUI),设计时包不可被运行时包依赖;Options → Directories/Conditionals → Search Path中,填入与设计时包完全相同的三行路径;Compile→ 成功后,不要点击 Install(运行时包不能安装,只能链接);- 在你的目标 FMX 工程中,打开
Project → Options → Packages → Runtime Packages→ 勾选Build with runtime packages→ 在下方Runtime packages输入框中,手动追加TMSFMXUI(注意:不带.bpl后缀,也不带路径); - 同时,在
Project → Options → Delphi Compiler → Search Path中,添加与前述一致的三个源码路径。
关键逻辑说明:
Runtime packages设置让工程在运行时动态加载TMSFMXUI.bpl,而Search Path则确保编译器能找到.pas源码用于调试和符号生成。二者缺一不可。若只设前者,你无法在TMSFMXGrid.pas中打断点;若只设后者,iOS 构建会因找不到libTMSFMXUI.a静态库而失败。
3.2 针对 iOS 和 Android 的条件编译处理
v3.7.7.5引入了对 iOS 17+ 和 Android 13 的适配层,但默认未启用。若你的目标平台是移动设备,必须在工程的.dpr文件顶部添加条件定义:
program MyFMXApp; uses System.StartUpCopy, FMX.Forms, // ... 其他 uses {$IFDEF IOS} {$DEFINE TMSFMX_IOS17_SUPPORT} {$ENDIF} {$IFDEF ANDROID} {$DEFINE TMSFMX_ANDROID13_SUPPORT} {$ENDIF} {$R *.res} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.参数说明:
TMSFMX_IOS17_SUPPORT启用TTMSFMXNavigationBar对 iOS 17 新增的statusBarStyleAPI 调用;TMSFMX_ANDROID13_SUPPORT启用TTMSFMXCloudUpload对 Android 13 存储沙盒权限的自动检测。不加定义则组件仍可运行,但可能在新系统上出现状态栏文字不可读、或上传时因权限拒绝而静默失败。
3.3 Windows 平台 WebView2 运行时自动部署(避坑关键)
TTMSFMXWebGMap和TTMSFMXWebView2依赖 Microsoft Edge WebView2 运行时。v3.7.7.5不再自带WebView2Loader.dll,而是通过TMSFMXWebView2.pas中的LoadWebView2函数动态查找。常见失败场景是:开发机有 WebView2,但客户机没有,导致地图白屏。
解决方案:在工程中嵌入最小化 WebView2 引导逻辑。在主窗体OnCreate中加入:
uses TMSFMXWebView2, System.SysUtils; procedure TForm1.FormCreate(Sender: TObject); begin if not TMSFMXWebView2.LoadWebView2 then begin ShowMessage('WebView2 运行时未找到。请访问 https://go.microsoft.com/fwlink/p/?LinkId=2124703 下载并安装'); Application.Terminate; end; end;血泪经验:不要试图在
dpr中调用LoadWebView2—— 此时 FMX 应用上下文尚未初始化,函数会返回False却不报错,成为黑匣子。必须在首个窗体OnCreate中调用,且必须在Application.Initialize之后、Application.Run之前。
4. 常见编译与运行时问题排查:五个真实踩坑记录与修复方案
4.1 现象:编译dclTMSFMXUI.dpk时提示F2051 Unit 'FMX.TabControl' not found
原因:Delphi 11 默认安装的 FMX 框架路径未被正确索引,或你安装了多个 Delphi 版本导致 IDE 混淆了FMX.TabControl.pas的位置。v3.7.7.5源码中大量使用FMX.TabControl.TTabControl的扩展方法,若编译器找不到基类单元,整个包无法解析。
解决:
- 打开
Tools → Options → Language → Delphi Options → Library → Library Path; - 确保第一条路径为:
$(BDS)\source\fmx(对应 Delphi 11 的 FMX 源码根目录); - 若该路径不存在,请手动创建指向:
C:\Program Files (x86)\Embarcadero\Studio\22.0\source\fmx(22.0 是 Delphi 11 的内部版本号); - 重启 IDE 后重试编译。
4.2 现象:Android 工程部署后,TTMSFMXGrid显示空白,Logcat 报java.lang.UnsatisfiedLinkError: dlopen failed: library "libTMSFMXUI.so" not found
原因:TMSFMXUI.dpk编译时未生成 Android 平台对应的.so动态库,或工程未正确链接。v3.7.7.5的 Android 构建依赖Android NDK r21e,而 Delphi 11.3 默认配置为r23b,版本不匹配导致链接器跳过.so生成。
解决:
- 下载
Android NDK r21e(官网归档页面可得),解压至C:\Android\ndk\r21e; Tools → Options → Deployment → SDK Manager → Android SDK→ 点击Edit→ 将NDK Path改为C:\Android\ndk\r21e;- 重新编译
TMSFMXUI.dpk(Target Platform 切换为Android 64-bit); - 在工程
Deployment窗口中,确认libTMSFMXUI.so已被添加到Remote Path: libraries\arme64-v8a\(或arm64-v8a)。
4.3 现象:iOS 真机调试时,TTMSFMXWebGMap显示灰色方块,Xcode Console 输出Invalid API key
原因:v3.7.7.5将 Google Maps API Key 的校验逻辑从设计时前移到了TTMSFMXWebGMap.Create构造函数中,且 Key 必须在inherited Create之后、Self.Parent := ...之前设置。若你在窗体设计器中设置了ApiKey属性,该值不会被序列化进.fmx文件 —— 因为TTMSFMXWebGMap未在DefineProperties中注册该属性的流式保存。
解决:
在窗体OnCreate中,严格按顺序编写:
procedure TForm1.FormCreate(Sender: TObject); begin inherited; // 必须在 inherited 之后、Parent 赋值之前 TMSFMXWebGMap1.ApiKey := 'YOUR_GOOGLE_MAPS_API_KEY'; TMSFMXWebGMap1.Parent := Self; end;翻车现场:曾有 A 同学把
ApiKey设置放在TMSFMXWebGMap1.Visible := True之后,结果因 Parent 未赋值导致Create未完成,Key 被忽略 —— 调试器里ApiKey字段显示为空,但断点根本进不去Create,成了后悔药都难找的玄学问题。
4.4 现象:Windows 平台下TTMSFMXCloudUpload上传大文件(>500MB)时,进度条卡在 99%,最终超时
原因:v3.7.7.5的TTMSFMXCloudUpload默认使用TNetHTTPClient,其Timeout属性默认为60000(60 秒),且未暴露给用户。大文件上传受网络抖动影响,单次请求极易超时,而组件内部未实现分片重传。
解决:
在上传前,通过 RTTI 强制修改底层 HTTP 客户端超时:
uses System.Rtti, System.TypInfo; procedure TForm1.UploadBigFile; var LContext: TRttiContext; LType: TRttiType; LField: TRttiField; LHTTP: TObject; begin LType := LContext.GetType(TTMSFMXCloudUpload1.ClassType); LField := LType.GetField('FHTTPClient'); // 私有字段名,v3.7.7.5 中固定为 FHTTPClient LHTTP := LField.GetValue(TTMSFMXCloudUpload1).AsObject; // 修改 TNetHTTPClient.Timeout 属性(单位:毫秒) LType := LContext.GetType(LHTTP.ClassType); LField := LType.GetProperty('Timeout'); LField.SetValue(LHTTP, 300000); // 设为 5 分钟 TTMSFMXCloudUpload1.UploadFile(...); end;提示:此方案依赖私有字段名
FHTTPClient,属v3.7.7.5特定版本。升级到 v3.8+ 后字段名可能变更,需同步更新 RTTI 路径。
4.5 现象:macOS 工程编译通过,但运行时报EXC_BAD_ACCESS (code=1, address=0x0),堆栈指向TMSFMXWebViewMac.pas第 237 行
原因:v3.7.7.5的 macOS WebView 封装未正确处理 ARC(Automatic Reference Counting)内存模型。当TTMSFMXWebViewMac实例被释放时,其持有的WKWebViewdelegate 未置空,导致 delegate 回调时访问已释放对象。
解决:
在TMSFMXWebViewMac.pas中定位到Destroy方法(约第 230 行附近),在inherited Destroy之前插入:
// 在 TMSFMXWebViewMac.Destroy 中插入以下两行 if Assigned(FWKWebView) then FWKWebView.navigationDelegate := nil; inherited Destroy;注意:此补丁需在每次升级 TMS 包后重新应用。建议将修改后的
TMSFMXWebViewMac.pas单独存档,并在团队 Wiki 中注明补丁版本与生效范围。
5. 深度定制实战:修改TTMSFMXGrid单元格渲染逻辑,实现带图标与状态徽章的复合单元格
TTMSFMXGrid是v3.7.7.5中性能最强、扩展性最高的表格组件,但它默认的OnDrawCell事件只提供画布句柄和矩形区域,不暴露原始数据对象。若你想在订单列表中,为“已发货”状态的行右侧绘制一个绿色对勾图标 + “已发货”徽章,就必须深入其渲染管线。
5.1 理解TTMSFMXGrid的三层渲染架构
TTMSFMXGrid渲染并非简单调用Canvas.FillRect,而是分三阶段:
- 数据层:
TGridDataItem对象存储原始数据(如DataItem.Values[0]是订单号); - 样式层:
TGridCellStyle控制字体、颜色、对齐(OnGetCellStyles可动态返回); - 绘制层:
OnDrawCell事件中,ACanvas是TCanvas抽象类实例,但实际类型取决于平台(Windows 是TCanvasGDI,macOS 是TCanvasCocoa)。
关键洞察:OnDrawCell的ADataItem: TGridDataItem参数,正是你获取业务数据的入口。v3.7.7.5已将TGridDataItem的Tag属性开放为Integer,可用于临时挂载状态标识。
5.2 实现带图标与徽章的订单状态列
假设你的数据源是TList<TOrder>,其中TOrder.Status: TOrderStatus = (osPending, osShipped, osCancelled)。目标是在第 3 列(状态列)绘制:
osShipped→ 右侧绿色对勾图标 + “已发货”徽章(背景绿,文字白);osCancelled→ 右侧红色叉号图标 + “已取消”徽章(背景红,文字白);osPending→ 仅显示文字“待处理”。
步骤如下:
- 预处理数据,挂载状态 Tag:在
TTMSFMXGrid.LoadFromList后,遍历Grid.DataItems:
procedure TForm1.LoadOrders; var I: Integer; LOrder: TOrder; begin Grid.LoadFromList(FOrders); for I := 0 to Grid.DataItems.Count - 1 do begin LOrder := FOrders[I]; Grid.DataItems[I].Tag := Ord(LOrder.Status); // 将枚举转为整数存入 Tag end; end;- 实现
OnDrawCell,分离文字与图标绘制:
uses FMX.Graphics, FMX.Types, System.UITypes, System.Math; procedure TForm1.GridDrawCell(Sender: TObject; ACanvas: TCanvas; AColumn, ARow: Integer; ARect: TRectF; AState: TGridDrawState; ADataItem: TGridDataItem; ASelected: Boolean); var LText: string; LStatus: TOrderStatus; LIconRect, LBadgeRect: TRectF; LIconSize: Single; begin // 仅处理第 3 列(索引为 2) if AColumn <> 2 then begin inherited; Exit; end; LStatus := TOrderStatus(ADataItem.Tag); case LStatus of osShipped: begin LText := '已发货'; Grid.Canvas.Fill.Color := $FF4CAF50; // 绿色背景 end; osCancelled: begin LText := '已取消'; Grid.Canvas.Fill.Color := $FFF44336; // 红色背景 end; else begin LText := '待处理'; Grid.Canvas.Fill.Color := $FFFFFFFF; // 白色背景 end; end; // 绘制徽章背景 LBadgeRect := ARect; LBadgeRect.Left := LBadgeRect.Right - 80; LBadgeRect.Top := LBadgeRect.Top + 4; LBadgeRect.Bottom := LBadgeRect.Top + 22; Grid.Canvas.FillRect(LBadgeRect, 0, 0, AllCorners, 1); // 绘制徽章文字 Grid.Canvas.Font.Size := 12; Grid.Canvas.Font.Color := $FFFFFFFF; // 白色文字 Grid.Canvas.FillText(LBadgeRect, LText, False, 1.0, [], TTextAlign.Center, TTextAlign.Center); // 绘制图标(对勾/叉号) LIconSize := 16; LIconRect := ARect; LIconRect.Left := LIconRect.Right - LIconSize - 10; LIconRect.Top := LIconRect.Top + (LIconRect.Height - LIconSize) / 2; LIconRect.Right := LIconRect.Left + LIconSize; LIconRect.Bottom := LIconRect.Top + LIconSize; case LStatus of osShipped: DrawCheckMark(Grid.Canvas, LIconRect, $FF4CAF50); osCancelled: DrawCrossMark(Grid.Canvas, LIconRect, $FFF44336); end; end;- 实现图标绘制辅助函数(放入单元 implementation 区):
procedure DrawCheckMark(ACanvas: TCanvas; ARect: TRectF; AColor: TAlphaColor); var LPath: TPathData; begin LPath := TPathData.Create; try LPath.MoveTo(TPointF.Create(ARect.Left + 4, ARect.Top + ARect.Height / 2)); LPath.LineTo(TPointF.Create(ARect.Left + ARect.Width / 2 - 2, ARect.Top + ARect.Height - 4)); LPath.LineTo(TPointF.Create(ARect.Left + ARect.Width - 4, ARect.Top + 4)); ACanvas.Stroke.Color := AColor; ACanvas.Stroke.Thickness := 2; ACanvas.DrawPath(LPath, 1.0); finally LPath.Free; end; end; procedure DrawCrossMark(ACanvas: TCanvas; ARect: TRectF; AColor: TAlphaColor); var LPath: TPathData; begin LPath := TPathData.Create; try LPath.MoveTo(TPointF.Create(ARect.Left + 4, ARect.Top + 4)); LPath.LineTo(TPointF.Create(ARect.Left + ARect.Width - 4, ARect.Top + ARect.Height - 4)); LPath.MoveTo(TPointF.Create(ARect.Left + ARect.Width - 4, ARect.Top + 4)); LPath.LineTo(TPointF.Create(ARect.Left + 4, ARect.Top + ARect.Height - 4)); ACanvas.Stroke.Color := AColor; ACanvas.Stroke.Thickness := 2; ACanvas.DrawPath(LPath, 1.0); finally LPath.Free; end; end;关键参数说明:
ARect是单元格原始区域,我们通过ARect.Right - 80计算徽章左边界,确保徽章始终贴右;DrawPath使用矢量路径而非位图,保证 Retina 屏幕下清晰无锯齿;Stroke.Thickness := 2是视觉平衡经验值,太细则图标易被忽略,太粗则破坏紧凑感。
5.3 性能优化:启用虚拟滚动与 GPU 加速
上述自定义绘制若应用于万级数据表格,仍可能卡顿。TTMSFMXGrid内置虚拟滚动(Virtual Mode),但需显式启用:
Grid.VirtualMode := True; Grid.OnGetCellText := GridGetCellText; // 必须实现,否则虚拟模式不生效 Grid.OnGetCellStyles := GridGetCellStyles;并在GridGetCellText中,根据ARow从原始数据源FOrders中取值,而非依赖Grid.DataItems[ARow](虚拟模式下DataItems仅缓存可视行)。
最后,强制启用 GPU 渲染(Windows/macOS 有效):
Grid.UseGPU := True; // 此属性在 v3.7.7.5 中默认 False我一般会在项目启动时统一开启:
TMSFMXGrid.GlobalUseGPU := True;。这样所有TTMSFMXGrid实例默认走 GPU 路径,避免逐个设置遗漏。实测开启后,5000 行表格滚动帧率从 32fps 提升至 58fps,且 CPU 占用下降 40%。
希望帮到你。
本文还有配套的精品资源,点击获取