
简介本资源为面向 Delphi 12.3 开发者的 TMS FNC UI Pack v6.2.0.0 控件包适合使用 FireMonkey 与 VCL 框架进行跨平台界面开发的中高级程序员用于快速构建现代化、多平台兼容的 UI 界面解决原生控件样式单一、跨端适配繁琐的问题。压缩包共约 2000 个文件整体 29.85MB以 556 个 pas 源码单元、87 个 dfm 窗体、67 个 fmx 跨平台窗体、37 个 lfm 与 lpr 工程文件为核心辅以 180 个 res 资源、158 个 ico 图标、220 个 jpg 与 27 个 svg 图像素材以及 dproj、dpk、groupproj 等工程与包文件另含 csv、xls、xml 等示例数据结构完整便于按模块查阅。目前已有 55 人学习下载。读者可获得完整源码、示例工程与资源素材直接用于界面定制、控件二次封装与跨平台项目集成并借助示例数据快速验证控件行为降低上手与排错成本。1. 从一次 FMX 界面重构说起TMS FNC UI Pack 到底解决了什么去年接手一个 Delphi 12.3 的跨平台项目VCL 端跑得好好的一到 FMX 的 Android 和 macOS 上TMS 那套老 Grid 就开始闹脾气——列宽错乱、触摸滚动卡顿、日期选择器在 iOS 上直接白屏。当时第一反应是自己写控件结果两周下来只搞定了半个 TreeView还搭进去一堆平台条件编译。后来同事甩过来一个包说试试 TMS FNC UI Pack我半信半疑装上去发现它把 VCL、FMX、LCL 三套框架的 UI 控件统一到了一套源码里Grid、TreeView、Planner、RichEditor、SyntaxMemo 这些常用组件全都有而且同一份代码在 Windows、Android、iOS、macOS、Linux 上编译出来的行为基本一致。这个 v6.2.0.0 版本对应 Delphi 12.3 的编译器和 RTL 做了适配装完不用改项目引用路径就能直接拖控件。如果你正在做多端 Delphi 项目又被原生控件在不同平台上的表现差异折腾过这个包值得花时间摸一遍。它适合已经熟悉 Delphi 基本开发、需要快速搭建跨平台业务界面的从业者不适合只想写纯 Windows 小工具、对跨平台没需求的人。2. 拆包与安装从 rar 到 IDE 工具栏的完整路径2.1 包结构里有什么先看清楚再动手拿到TMS FNC UI Pack v6.2.0.0.rar之后别急着双击解压到桌面。我一般会先建一个固定目录比如D:\DelphiLibs\TMSFNCUI\把 rar 解压进去然后看目录结构。这个包典型的分层是这样的根目录下有Source、Packages、Demos、Doc几个文件夹。Source里是全部控件的 Pascal 源码按控件名分子目录比如FMX.TMSFNCGrid、VCL.TMSFNCTreeView这种命名方式Packages里是按 Delphi 版本和平台分好的.dpk包文件Delphi 12.3 对应的是带D12_3或RADStudio12_3字样的目录Demos里是各控件的示例工程建议先别删后面调参数时对照着看比翻文档快。提示解压路径不要带中文和空格Delphi 的包编译对路径里的特殊字符偶尔会出玄学问题我踩过一次编译报错指向一个根本不存在的单元换了纯英文路径就好了。2.2 在 Delphi 12.3 里编译并安装包安装的核心动作是编译.dpk并注册到 IDE。打开 Delphi 12.3走File → Open定位到Packages下对应版本的目录先打开设计期包通常名字里带Dcl前缀比如TMSFNCUIPackDcl.dpk在项目管理器里右键Build编译通过后再右键Install。安装成功后IDE 的工具栏会多出一组 TMS FNC 的控件图标Tool Palette 里也会出现TMS FNC分类。// 如果你习惯用命令行编译可以在 RAD Studio 的命令行环境下走 msbuild // 先切到包所在目录再执行对应平台的构建命令 // 下面这行是编译设计期包到 Win32 平台的示例 msbuild TMSFNCUIPackDcl.dpk /p:ConfigRelease /p:PlatformWin32 /t:Build这段命令的逻辑是msbuild调用 Delphi 的编译引擎/p:ConfigRelease指定发布配置/p:PlatformWin32指定目标平台/t:Build表示执行完整构建。参数里最容易出错的是Platform如果你只装了 Win32 的编译器却写了Android会直接报平台不支持。编译完设计期包之后运行时包名字里通常带R或没有Dcl前缀也要用同样的方式 Build 一遍否则在 FMX 工程里拖控件时会提示找不到单元。2.3 把控件拖进现有工程引用路径与运行时包包安装好只是第一步现有工程要用起来还得配两处。第一处是Project → Options → Delphi Compiler → Search Path把Source下所有子目录加进去或者干脆加一个通配路径D:\DelphiLibs\TMSFNCUI\Source\*。第二处是Packages → Runtime Packages如果你用的是运行时包模式要勾选 TMS FNC 对应的.bpl如果用静态链接就确保Link with runtime packages没勾上。我一般新工程直接用静态链接省得部署时还要带一堆 bpl 文件。// 在单元里引用控件时VCL 和 FMX 的单元名不同别混用 // VCL 工程里这样引 uses VCL.TMSFNCGrid, VCL.TMSFNCTreeView; // FMX 工程里这样引 uses FMX.TMSFNCGrid, FMX.TMSFNCTreeView;逻辑说明TMS FNC 的单元命名遵循框架前缀规则VCL.开头的是给 VCL 工程用的FMX.开头的是给 FMX 工程用的。参数上没什么可调的但要注意如果你在同一个单元里同时引了两套编译器会报重复定义。常见做法是建一个公共数据单元把业务逻辑和 UI 框架解耦界面单元只引对应框架的那一套。3. 核心控件实战Grid、TreeView 与跨平台数据绑定3.1 TMSFNCGrid 的数据源绑定与列配置Grid 是这个包里用得最多的控件。和 Delphi 自带的TStringGrid不同TMSFNCGrid 支持直接绑定TDataSource也能手动填充。我一般两种场景分开处理数据量小、结构固定的用TDataSource绑定数据量大、需要虚拟模式的用手动填充加OnGetCellData事件。// 方式一绑定 TDataSource适合数据量在几千行以内的场景 procedure TFormMain.SetupGrid; begin FNCGrid1.DataSource : DataSource1; // DataSource1 指向某个 TDataSet FNCGrid1.AutoSizeColumns : True; // 自动列宽触摸端建议关掉手动设更稳 FNCGrid1.Options : FNCGrid1.Options [goEditing, goRowSelect]; // 列宽在 FMX 下建议给最小值否则 Android 上可能缩成一条线 FNCGrid1.Columns[0].Width : 120; FNCGrid1.Columns[1].Width : 200; end;逻辑说明DataSource属性把 Grid 和数据集连起来AutoSizeColumns在桌面端好用但在移动端会因为字体测量差异导致列宽跳动我一般关掉它手动设。Options里的goEditing开启单元格编辑goRowSelect让整行选中触摸操作时比单元格选中更友好。参数上Columns[i].Width的单位是像素在 FMX 下会按屏幕缩放比例自动换算不用自己乘 DPI。3.2 TMSFNCTreeView 的节点操作与懒加载TreeView 在业务系统里常用来做组织架构或目录树。TMSFNCTreeView 的节点类型是TTMSFNCTreeViewNode添加子节点的写法和 VCL 原生 TreeView 类似但多了Data属性可以挂业务对象。// 添加节点并挂载业务数据适合做懒加载 procedure TFormMain.AddOrgNode(AParent: TTMSFNCTreeViewNode; ADeptID: Integer; const AName: string); var Node: TTMSFNCTreeViewNode; begin if AParent nil then Node : FNCTreeView1.AddNode(nil, AName) else Node : FNCTreeView1.AddNode(AParent, AName); Node.Data : TObject(ADeptID); // 把部门 ID 挂上去展开时再查子节点 Node.HasChildren : True; // 先标记有子节点展开时触发 OnExpanding end;逻辑说明AddNode的第一个参数是父节点传nil表示加到根。Data是TObject类型这里用TObject(ADeptID)把整数强转进去展开事件里再取出来查数据库。HasChildren设为True会让节点显示展开箭头实际子节点在OnExpanding事件里动态加载。参数上要注意ADeptID是整数强转成TObject在 64 位编译器下会有警告更稳妥的做法是包一层记录类型或者用TNodeData类。3.3 跨平台下的字体与触摸适配同一套 Grid 代码在 Windows 上看着正常到 Android 上字可能偏小、行高不够点。TMS FNC 提供了ScaleForPPI相关属性但我的经验是别全指望自动缩放关键尺寸手动调更可控。// 在 Form 的 OnCreate 里根据平台调整基础尺寸 procedure TFormMain.FormCreate(Sender: TObject); begin {$IF DEFINED(ANDROID) or DEFINED(IOS)} FNCGrid1.RowHeight : 48; // 触摸端行高给足手指点得准 FNCGrid1.Font.Size : 14; FNCGrid1.Options : FNCGrid1.Options - [goEditing]; // 移动端先关编辑避免弹键盘遮挡 {$ELSE} FNCGrid1.RowHeight : 24; FNCGrid1.Font.Size : 9; {$ENDIF} end;逻辑说明条件编译指令{$IF DEFINED(ANDROID)}在编译期决定哪段代码生效不会带来运行时开销。RowHeight在触摸端给到 48 像素是经验值低于 40 手指容易点错行。goEditing在移动端关掉是因为弹出软键盘后 Grid 的滚动位置会乱需要额外处理焦点如果业务必须编辑建议改用弹出式编辑框。4. 避坑与排查安装、编译、运行时的五条血泪记录4.1 安装后工具栏不出现控件现象.dpk编译安装都提示成功但 Tool Palette 里找不到 TMS FNC 分类。原因通常是设计期包虽然编译了但没有真正注册到 IDE或者 IDE 的缓存没刷新。解决先确认Install按钮点过且没报错然后关掉 Delphi删掉%APPDATA%\Embarcadero\BDS\23.0\下的ToolPalette相关缓存文件重启 IDE。如果还不行检查.dpk的requires里是否引用了当前版本不存在的包。4.2 FMX 工程编译报找不到单元现象VCL 工程正常切到 FMX 工程编译时提示FMX.TMSFNCGrid找不到。原因一般是 Search Path 只加了 VCL 的源码目录没加 FMX 的。解决在Project → Options → Delphi Compiler → Search Path里把Source下所有子目录都加进去或者用通配符Source\*。注意通配符在部分 Delphi 版本里对深层子目录不生效保险做法是逐个加。4.3 Android 上 Grid 滚动卡顿现象数据量到几百行时Android 真机上滚动明显掉帧。原因是默认开启了逐行绘制且没有启用虚拟模式。解决设置FNCGrid1.Options包含goVirtualMode并在OnGetCellData事件里按需提供数据不要一次性把所有行都填进去。另外把DoubleBuffered设为True能减少闪烁。4.4 日期选择器在 iOS 上显示空白现象TMSFNCDatePicker在 iOS 真机上点开是一片白。原因是该控件在 iOS 上依赖原生的UIDatePicker而某些 iOS 版本对深色模式下的文字颜色处理有差异。解决在OnShow事件里强制设置Font.Color和Fill.Color别依赖主题继承。如果还不行临时改用TMSFNCCalendar替代它的绘制是纯 Pascal 的不依赖原生控件。4.5 运行时包部署后提示缺少 bpl现象开发机运行正常拷到客户机上提示找不到TMSFNCUIPackR.bpl。原因是用了运行时包模式但没把 bpl 一起部署。解决要么改成静态链接取消Link with runtime packages要么把Packages目录下对应的 bpl 拷到 exe 同目录。我一般推荐静态链接省去部署时的依赖管理代价是 exe 体积大几 MB。5. 进阶技巧用 FNC 的样式机制统一多端外观5.1 样式文件的结构与加载时机TMS FNC 的样式系统和 VCL 的 VCL Styles、FMX 的 StyleBook 都不一样它自己有一套.fncstyle格式本质是 JSON 描述的颜色和字体集合。我一般把样式文件放在 exe 同目录的Styles文件夹下在程序启动时加载。// 程序启动时加载自定义样式放在 Application.Initialize 之后 procedure TFormMain.LoadFNCStyle; begin if FileExists(ExtractFilePath(ParamStr(0)) Styles\MyTheme.fncstyle) then TMSFNCUtils.LoadStyleFromFile( ExtractFilePath(ParamStr(0)) Styles\MyTheme.fncstyle); end;逻辑说明TMSFNCUtils是包里的工具类LoadStyleFromFile会解析 JSON 并把样式应用到所有已注册的 FNC 控件。参数是样式文件的完整路径用ExtractFilePath(ParamStr(0))取 exe 所在目录避免硬编码。加载时机要在窗体创建之前否则已经创建的控件不会自动刷新需要手动调ApplyStyle。5.2 用样式变量做主题切换样式文件里可以定义变量运行时改变量值就能实现亮色/暗色切换不用准备两套文件。// 切换暗色主题改几个关键颜色变量 procedure TFormMain.SwitchToDark; begin TMSFNCUtils.SetStyleColor(Grid.Background, $FF1E1E1E); TMSFNCUtils.SetStyleColor(Grid.Text, $FFE0E0E0); TMSFNCUtils.SetStyleColor(TreeView.Background, $FF252526); TMSFNCUtils.SetStyleColor(TreeView.Text, $FFCCCCCC); // 改完通知所有 FNC 控件重绘 TMSFNCUtils.RefreshAllControls; end;逻辑说明SetStyleColor的第一个参数是样式键名格式是控件类型.属性名第二个参数是TAlphaColor类型的值$FF开头表示不透明。RefreshAllControls会遍历所有已注册控件并触发重绘。参数上要注意颜色值在 FMX 和 VCL 下的字节序一致都是 ARGB不用做平台判断。5.3 验证样式是否生效的笨办法样式改完不生效是常事我的排查习惯是先确认LoadStyleFromFile返回成功可以包一层 try 捕获异常再确认控件是在样式加载之后创建的。如果都对了还不生效就在OnPaint事件里打个断点看Fill.Color的实际值是不是你设的那个。有一次我折腾了半小时最后发现是样式文件里键名拼错了一个字母JSON 解析器静默忽略了。从那以后我每次改样式文件都先用 JSON 校验工具过一遍再放进工程里。希望这些经验能帮你少走点弯路。本文还有配套的精品资源点击获取