简介本资源为TMS FNC UI Pack v7.1.1.0完整源码包面向使用Delphi与C Builder进行跨平台界面开发的程序员覆盖XE7至13 Florence版本。控件包提供现代化、触摸友好的UI组件支持Windows、Mac、Linux、iOS与Android多平台适合希望快速构建响应式应用界面的中高级开发者。压缩包共约2000个文件体积31.09MB以591个pas源码单元、158个dpr工程文件、88个dfm窗体、67个fmx跨平台窗体及82个dcr组件资源为主另含dproj、res、ico、svg、png等工程与素材文件并附带html文档、csv数据与示例图片便于查阅与二次开发。目前已有56人学习下载。完整源代码开放意味着开发者可自由修改、扩展组件样式与动画效果结合官方文档能显著提升界面开发效率降低调试成本长期项目亦可获得持续更新支持。1. TMS FNC UI Pack 在 Delphi 13.1 里到底解决了什么问题如果你正在用 Delphi 13 Florence 做跨平台项目大概率遇到过这种局面VCL 一套控件、FMX 一套控件同一份业务逻辑要在两套 UI 里各写一遍界面风格还统一不了。TMS FNC UI Pack 就是冲着这个痛点来的——它是一套基于 FNCFramework Neutral Components架构的 UI 控件库同一份控件代码可以同时跑在 VCL、FMX 甚至 Web 端Delphi 13.1 和 CBuilder XE7 到 13 Florence 都在支持范围内。标题里的 Full Source 意味着你拿到的是完整源码版不是只有 DCU 的编译版这对需要改控件内部行为、做深度定制的团队来说差别很大。这套包覆盖的控件类型很广网格、树、列表、工具栏、日程、图表、编辑器等日常业务系统里能想到的 UI 组件基本都有对应实现。它适合两类人一是手上有多端发布需求、不想维护两套 UI 代码的团队二是需要读源码、改源码来解决特定渲染或交互问题的资深开发者。如果你只是做单平台小工具用原生控件可能更省事但一旦涉及多端和深度定制FNC 这套架构的价值就出来了。2. FNC 架构的跨框架原理与工程结构拆解2.1 FNC 为什么能做到一份代码多端渲染FNC 的核心思路是把控件的逻辑层和渲染层彻底分开。逻辑层处理数据、状态、事件渲染层负责把控件画到具体平台上。VCL 下它调用 Windows GDI/GDIFMX 下走 FireMonkey 的 Canvas 抽象Web 端则输出 HTML/CSS/JS。你在代码里操作的TTMSFNCGrid或TTMSFNCTreeView在不同框架下是同一个类名、同一套属性方法编译器根据当前框架选择对应的后端单元。这种设计带来的直接好处是业务代码里不需要写{$IFDEF VCL}和{$IFDEF FMX}的分支控件属性设置、事件绑定、数据填充的写法完全一致。代价是 FNC 控件不会像原生控件那样在每个平台上都做到像素级原生外观它走的是自绘路线风格统一但和系统原生控件有视觉差异。这一点在选型时要提前想清楚你要的是开发效率还是原生观感。从工程结构看安装后源码通常分布在几个关键目录FMX目录放 FireMonkey 后端VCL目录放 VCL 后端Common或Core目录放跨框架共享的逻辑单元Packages目录放各版本的包文件。理解这个结构很重要因为后面你要改源码或排查编译错误时得知道该去哪个目录找对应单元。2.2 在 Delphi 13.1 里安装 Full Source 版的完整步骤Full Source 版和编译版的安装流程不一样编译版直接装包就行源码版需要先把源码路径加入搜索路径再编译包。下面是我在 Delphi 13 Florence 上的实际操作步骤。第一步解压后先确认目录结构。通常根目录下会有Source、Packages、Demos几个文件夹。不要急着打开 IDE先在文件管理器里确认Source下确实有.pas源文件而不是只有.dcu。第二步在 Delphi 里打开包文件。Delphi 13 对应的包文件一般在Packages下按版本分目录找到Delphi 13或Delphi13目录里面会有TMSFNCUIpackDXE13.dpk之类的设计期包和对应的运行期包。先打开运行期包Runtime Package编译再安装设计期包Design Package。// 安装后在代码里引用 FNC 控件的典型 uses 写法 uses FMX.TMSFNCGrid, // FMX 下的 FNC 网格 VCL.TMSFNCGrid, // VCL 下的 FNC 网格按框架二选一 TMSFNCGridData, // 跨框架共享的数据单元 TMSFNCUtils; // 工具函数单元这里要注意单元命名规律框架相关的单元带FMX.或VCL.前缀跨框架共享的单元没有前缀。写代码时尽量只引用共享单元和当前框架的单元不要同时引用两个框架的版本否则会出现重复定义。第三步把Source目录加入 IDE 的库搜索路径。菜单Tools→Options→Language→Delphi→Library在Library Path里加上源码根目录和必要的子目录。这一步不做的话编译时找不到.pas文件只能找到预编译的.dcu那就失去 Full Source 的意义了。第四步编译一个 Demo 验证。Demos目录下通常有按框架分类的示例项目打开一个 VCL 的、一个 FMX 的分别编译运行。如果两个都能跑起来说明包安装和路径配置都对了。提示安装前先备份 IDE 的库路径配置源码版安装涉及路径修改出问题回滚会方便很多。2.3 包文件与搜索路径的对应关系很多人装源码版翻车不是包编译不过而是搜索路径没配对导致 IDE 里能看到控件但一编译就报找不到单元。下面这张表是我整理的关键目录和用途对应关系按这个核对基本不会漏。目录内容是否加入搜索路径Source\Common跨框架共享逻辑单元是Source\VCLVCL 后端单元是VCL 项目Source\FMXFMX 后端单元是FMX 项目Packages\Delphi13各版本 dpk 包文件否通过 IDE 打开安装Demos示例项目否路径加多了也会出问题比如同时把 VCL 和 FMX 目录加进去某些同名单元会冲突。我的习惯是按项目类型分开配置做 VCL 项目时只加 Common 和 VCL做 FMX 时只加 Common 和 FMX。如果团队同时维护两种项目可以用 IDE 的Build Configuration或不同 IDE 实例来隔离。3. 用 FNC 控件搭一个可复用的数据管理界面3.1 从零建一个带树形导航和网格的 VCL 窗口这一节用一个具体场景把 FNC 控件串起来左边树形导航右边数据网格顶部工具栏这是业务系统里最常见的布局。用 FNC 的TTMSFNCTreeView、TTMSFNCGrid、TTMSFNCToolBar来实现重点是让这套代码之后能低成本迁移到 FMX。先建一个 VCL 项目在窗体上放三个 FNC 控件。注意 FNC 控件在 Tool Palette 里的分类通常是TMS FNC开头的页签找不到的话检查设计期包是否装好。procedure TFormMain.FormCreate(Sender: TObject); begin // 初始化树形导航 TMSFNCTreeView1.DefaultItemType : itText; TMSFNCTreeView1.SelectionMode : smSingle; // 初始化网格列 TMSFNCGrid1.ColumnCount : 4; TMSFNCGrid1.Cells[0, 0] : 编号; TMSFNCGrid1.Cells[1, 0] : 名称; TMSFNCGrid1.Cells[2, 0] : 状态; TMSFNCGrid1.Cells[3, 0] : 更新时间; // 固定表头行 TMSFNCGrid1.FixedRows : 1; // 工具栏按钮 TMSFNCToolBar1.AddButton(新增); TMSFNCToolBar1.AddButton(编辑); TMSFNCToolBar1.AddButton(删除); end;这段代码里几个参数值得说明。DefaultItemType决定树节点的默认类型itText是纯文本节点如果要带复选框就改成itCheckBox。FixedRows : 1把第一行固定为表头滚动时表头不动。SelectionMode控制选择行为smSingle是单选多选用smMulti。工具栏的AddButton是简化写法实际项目里通常用Items.Add配合TMSFNCToolBarButtonItem来设置图标和事件。3.2 树节点与网格数据的联动绑定光有界面不够关键是树节点选中后网格要跟着刷新。FNC 控件的事件模型和原生控件类似但要注意跨框架时事件参数类型可能不同。procedure TFormMain.TMSFNCTreeView1SelectionChanged(Sender: TObject); var Node: TTMSFNCTreeViewNode; begin Node : TMSFNCTreeView1.SelectedNode; if Node nil then Exit; // 根据选中节点刷新网格数据 LoadGridData(Node.Text); end; procedure TFormMain.LoadGridData(const CategoryName: string); begin TMSFNCGrid1.BeginUpdate; // 批量更新前挂起重绘避免闪烁 try TMSFNCGrid1.RowCount : 1; // 保留表头行 // 这里接你的数据源示例用模拟数据 AddGridRow(001, CategoryName -项目A, 启用, 2025-01-10); AddGridRow(002, CategoryName -项目B, 停用, 2025-01-11); finally TMSFNCGrid1.EndUpdate; end; end; procedure TFormMain.AddGridRow(const A, B, C, D: string); var R: Integer; begin R : TMSFNCGrid1.RowCount; TMSFNCGrid1.RowCount : R 1; TMSFNCGrid1.Cells[0, R] : A; TMSFNCGrid1.Cells[1, R] : B; TMSFNCGrid1.Cells[2, R] : C; TMSFNCGrid1.Cells[3, R] : D; end;BeginUpdate和EndUpdate这对调用是 FNC 网格性能优化的关键。数据量大时如果不挂起重绘每加一行都会触发一次界面刷新几百行下来肉眼可见地卡。RowCount的增减会自动管理行对象不需要手动创建销毁。SelectedNode在无选中时返回nil必须先判空再访问这是血泪经验早期版本里直接访问会抛异常。3.3 把 VCL 版本迁移到 FMX 需要改什么FNC 的卖点就是迁移成本低但不是零成本。把上面这个 VCL 项目改成 FMX主要改三处单元引用、控件实例类型、以及少量平台相关的属性。单元引用从VCL.TMSFNCGrid改成FMX.TMSFNCGridVCL.TMSFNCTreeView改成FMX.TMSFNCTreeView。控件实例的类名不变还是TTMSFNCGrid但声明所在的单元变了。属性方法层面绝大多数是通用的少数涉及窗口句柄、字体渲染、鼠标事件坐标的会有差异。// FMX 版本中获取鼠标位置的写法差异 // VCL 下常用 // P : TMSFNCGrid1.ScreenToClient(Mouse.CursorPos); // FMX 下应改为 P : TMSFNCGrid1.ScreenToLocal(TMSFNCGrid1.Scene.LocalToScreen(PointF(0, 0)));这类坐标转换的差异是迁移时最容易踩的坑因为编译器不会报错但运行时位置全错。我的做法是迁移前先把项目里所有涉及屏幕坐标、句柄、Canvas 直接操作的代码列出来逐个对照 FNC 的跨框架 API 改。FNC 提供了TMSFNCUtils单元里面有不少跨框架的辅助函数优先用这些而不是自己写平台分支。4. 源码版定制与编译期常见问题排查4.1 修改 FNC 源码后如何避免被包覆盖Full Source 版最大的价值是能改源码但改完源码后如果直接重新编译安装包你的修改可能被覆盖。正确做法是把要改的单元从源码目录复制到项目自己的目录在项目搜索路径里把项目目录排在源码目录前面这样编译器优先用你改过的版本。# 项目目录结构建议 MyProject/ Source/ Overrides/ # 放你改过的 FNC 单元 TMSFNCGrid.pas Lib/ # 编译输出搜索路径顺序MyProject\Source\Overrides在前TMSFNCUIpack\Source\Common在后。这样只有你覆盖的单元用改过的版本其余仍用官方源码。升级 FNC 版本时对比 Overrides 里的文件和官方新版的差异手动合并不要直接覆盖。注意改 FNC 源码前先确认许可证允许。Full Source 版通常允许修改自用但再分发有限制具体看授权条款。4.2 编译报错「Unit not found」的四种排查方向这个报错在源码版安装里出现频率最高原因通常不出四种。第一种搜索路径没加或加错检查 IDE 库路径里是否有源码根目录。第二种包没编译成功设计期包依赖运行期包运行期包没编译过设计期包也装不上。第三种同名单元冲突比如你项目里有个TMSFNCUtils.pas和官方的重名编译器不知道用哪个。第四种Delphi 版本对应的包文件选错了XE7 和 13 的包不通用。排查顺序建议从简到繁先看路径再看包编译输出再看单元名冲突最后确认版本匹配。包编译时把输出窗口的警告也看一下有些警告其实是致命问题的前兆。4.3 运行时控件不显示或显示异常的排查编译过了但控件在窗体上不显示或者显示成一块空白这类问题更隐蔽。常见原因一是 FNC 控件的Parent没设置动态创建的控件必须指定父容器二是Visible属性被意外置为False三是 FMX 下控件的Align和Position冲突导致尺寸算出来是零四是样式文件没加载FNC 某些控件依赖样式资源。// 动态创建 FNC 控件时的正确写法 var Grid: TTMSFNCGrid; begin Grid : TTMSFNCGrid.Create(Self); Grid.Parent : Self; // 必须设置父容器 Grid.Align : TAlignLayout.Client; Grid.Visible : True; // 显式确认可见 Grid.RowCount : 10; Grid.ColumnCount : 5; end;如果按这个写法还是不显示检查窗体的OnCreate是否在控件创建之前就抛了异常导致后续代码没执行。用断点跟一下创建流程比盯着属性面板猜要快得多。5. 避坑记录源码版安装与多端开发的五个真实翻车点现象一装完包后 Tool Palette 里找不到 FNC 控件。原因通常是只编译了运行期包没安装设计期包。设计期包负责向 IDE 注册控件图标和属性编辑器不装它控件就不会出现在面板上。解决方法是确认Packages目录下带Dcl前缀的包也编译并安装了。现象二VCL 项目编译通过切到 FMX 项目报大量重复定义。原因是库搜索路径里同时存在 VCL 和 FMX 的源码目录同名单元被重复找到。解决方法是按项目类型隔离搜索路径或者用 IDE 的Build Configuration为不同平台配置不同的库路径。现象三改了源码里的绘制逻辑运行时没生效。原因是编译器用了预编译的.dcu而不是你改过的.pas。Delphi 的编译策略是如果.dcu比.pas新就用.dcu。解决方法是删除对应的.dcu文件或者把项目目录的搜索路径排在源码目录前面强制从源码编译。现象四FMX 下网格滚动卡顿VCL 下却流畅。原因是 FMX 的渲染管线对频繁的 Canvas 操作更敏感FNC 网格在 FMX 下默认的重绘策略需要调整。解决方法是开启BeginUpdate/EndUpdate批量更新并适当增大ScrollUpdateInterval之类的刷新间隔参数减少每帧的重绘次数。现象五升级 Delphi 小版本后 FNC 包编译报错。原因是 FNC 的包文件按 Delphi 版本区分13.0 和 13.1 的包文件可能不通用RTL 单元有变动。解决方法是找 FNC 官方对应新版本的包文件或者用源码目录里的.dpk重新编译不要直接复用旧版本的包。6. 用条件编译和单元覆盖把 FNC 项目做成可长期维护的形态前面讲的都是单点操作这一节说一个能让你少返工的工程习惯用条件编译配合单元覆盖把 FNC 项目的多端差异收敛到最小范围。核心思路是建一个Platform单元所有平台相关的差异都封装在这里业务代码只调这个单元暴露的统一接口。FNC 本身已经做了大量跨框架抽象但总有一些边角需要你自己处理比如文件路径分隔符、剪贴板操作、消息框样式。把这些集中到一个单元比散落在各处写{$IFDEF}要好维护得多。unit MyProject.Platform; interface type TPlatformHelper class public class function GetConfigPath: string; class procedure ShowMessage(const Msg: string); class function ClipboardText: string; end; implementation {$IFDEF MSWINDOWS} uses Winapi.Windows, Vcl.Dialogs, Vcl.Clipbrd; class function TPlatformHelper.GetConfigPath: string; begin Result : ExtractFilePath(ParamStr(0)) config\; end; class procedure TPlatformHelper.ShowMessage(const Msg: string); begin Vcl.Dialogs.ShowMessage(Msg); end; class function TPlatformHelper.ClipboardText: string; begin Result : Vcl.Clipbrd.Clipboard.AsText; end; {$ENDIF} {$IFDEF MACOS} uses FMX.Dialogs, FMX.Platform; class function TPlatformHelper.GetConfigPath: string; begin Result : TPath.GetHomePath /.myproject/; end; class procedure TPlatformHelper.ShowMessage(const Msg: string); begin FMX.Dialogs.ShowMessage(Msg); end; class function TPlatformHelper.ClipboardText: string; var Svc: IFMXClipboardService; begin Result : ; if TPlatformServices.Current.SupportsPlatformService(IFMXClipboardService, Svc) then Result : Svc.GetClipboard.AsText; end; {$ENDIF} end.这个单元的价值在于业务代码里永远只写TPlatformHelper.GetConfigPath不关心底层是 Windows 还是 macOS。新增平台时只改这一个文件不动业务逻辑。FNC 控件的使用也是同理尽量用 FNC 提供的跨框架 API实在没有的再走这个 Platform 单元兜底。验证这套结构是否有效有个简单方法把项目从 VCL 切到 FMX 编译如果报错只集中在 Platform 单元和少数 UI 初始化代码说明抽象层做得对如果业务单元里到处报错说明平台相关代码泄漏了需要继续收敛。我自己的习惯是每接一个新平台先花半天把 Platform 单元写扎实后面能省掉大量「这个属性在另一个平台上叫什么」的翻查时间。FNC 已经把大部分脏活干了剩下这点收尾工作做好多端项目的维护成本才能真正降下来。希望帮到你。本文还有配套的精品资源点击获取