TMS FNC UI Pack:一套代码搞定VCL与FMX跨框架开发 📅 发布时间:2026/8/31 1:20:50 👁 浏览次数: 简介本资源是面向Delphi与C Builder中高级开发者的专业UI组件库——TMS FNC UI Pack v7.1.0.0完整源码包专为XE7至XE13 Florence版本设计显著降低跨平台现代化界面开发门槛。包内含2000个文件涵盖591个Pascal源文件.pas、166个Delphi项目文件.dproj、88个窗体定义.dfm、67个FireMonkey界面文件.fmx、149个图标.ico及大量资源文件.res/.jpg/.png总大小31.07MB结构清晰、模块完备支持Windows/macOS/iOS/Android全平台统一UI构建。已有42人学习下载适用于需深度定制控件行为、研究FNC跨框架机制或快速搭建数据可视化应用的开发者。获取即得全部源码可直接编译调试、修改渲染逻辑、扩展图表交互并复用其FMX适配层实现真正意义上的跨平台UI一致性。 我接触TMS FNC UI Pack的起因是一个被逼无奈的项目需求。去年接手一个老项目Windows桌面端用VCL写的功能都正常但公司突然要求出平板端。当时摆在面前的选择很现实用FMX重写界面桌面端也得跟着迁或者维护两套界面代码一套VCL一套FMX成本直接翻倍。后来我选了TMS FNC UI Pack把界面层逐步换成了FNC控件。改完之后同一套界面代码既能放在VCL Form上也能放在FMX Form上桌面和平板的UI逻辑基本是共享的。这篇文章我就围绕TMS FNC UI Pack v7.1.0.0聊一聊这套控件包的核心机制、安装注意点、常用控件落地经验以及我实际踩过的坑。适合正在纠结VCL和FMX跨界的Delphi/CBuilder开发者读也适合准备给老项目补移动端的人参考。1. FNC框架的底层逻辑代码只写一遍VCL/FMX都能跑1.1 “框架无关”是怎么做到的用FNC之前我脑子里有个疑问“框架无关”到底是什么概念VCL和FMX连控件基类都不一样一个基于Windows消息一个基于FireMonkey的场景图渲染TMS怎么可能让一套代码两边跑后来看了源码才明白FNC控件没有直接继承VCL的TControl也没有直接继承FMX的TControl而是从TMS自己的一套基类TTMSFNCComponent派生。这套基类内部挂了一层适配器单独实现绘制、鼠标、键盘、焦点的处理逻辑。也就是说TMSFNCGrid在VCL下运行时它并不是真的摆一个Windows原生Grid控件而是自己接管了画布把文字、边框、滚动条全部绘制出来在FMX下也一样。这个思路有点像做UI库时常用的自绘方案不依赖宿主框架的原生控件自己负责所有视觉呈现。你可能会想那何必用TMS FNC直接用Canvas或者FMX的自绘控件不就行了吗区别在于FNC把这些底层工作都封装好了你只需要关心业务代码。而且FNC控件的属性和事件名在VCL和FMX下完全一致这意味着界面布局、事件处理、数据填充代码可以直接复用。我实际测试下来一个单元里写的TTMSFNCGrid填充逻辑从VCL工程复制到FMX工程几乎不需要改动。1.2 宿主适配VCL和FMX到底差在哪儿虽然FNC控件自己绘制界面但各种宿主行为的差异还是存在的。最明显的是输入法、触摸滚动和缩放。Windows桌面环境靠的是窗口消息移动端靠的是手势事件FNC在这两者之间做了一层抽象。开发时选择不同的宿主适配层会自动切换但表现上会有细微差别。比如Windows上中文输入法弹候选框和FMX的Android端输入法弹软键盘行为不完全一样需要针对宿主做小适配。这不是FNC偷懒而是两个框架本身对输入法管理的逻辑差异太大向上层抽象后仍会漏出一些框架痕迹。另一个差异是文字渲染。VCL的GDI和FMX的GPU文字渲染方式在平滑度、字形宽度上不完全一致。FNC的自绘风格会明显带有自带样式的影子如果你用了某个字体在VCL和FMX下看到的行高、字宽可能有一两个像素的差。开发期就要有这个预期不要在UI验收时过分强调查像素级一致重点看布局比例和交互逻辑是否统一。1.3 什么时候适合用FNC而不是原生控件用了大半年FNC之后我的感受是它不适合所有项目。如果你的应用只跑Windows且团队对VCL的原生控件已经很熟那用TMS FNC的收益没那么大毕竟原生控件在某些细节上更贴近系统、性能也更好。但如果你预计项目要同时在Windows桌面和移动端跑或者今天可能用VCL、明天说不准要迁到FMX那么FNC的跨框架优势就很值。这类项目的共同特点是业务逻辑和界面交互是核心平台差异只是载体。FNC把“载体”这个变量的影响压缩到了最低后续换界面框架时核心业务代码不需要重写。我现在的做法也很简单新建的通用业务模块能基于FNC就用FNC哪怕当前只有VCL桌面需求。这样一旦移动端需求来了不用再从头铺一遍。2. 安装v7.1.0.0前的准备从XE7到Florence的兼容性处理2.1 安装工具如何识别已装的IDETMS FNC UI Pack的安装程序打开后会扫描本机已经安装的IDE。它读取注册表里的安装记录然后列出所有可支持的Delphi和CBuilder版本。v7.1.0.0这个版本的覆盖面很广从XE7一直覆盖到RAD Studio 13 Florence都能接得住对老项目来说特别有价值——很多公司还在用XE7或者10.3不敢轻易升IDE但控件包可以单独升级。安装时直接勾选你本机已有的IDE实例即可。有个情况需要留意如果本机装了多个IDE版本安装程序会默认全部勾选。我建议只勾选你实际要用的版本因为额外勾选会为每个版本重新编译一遍源码包编译时间会成倍增加。我第一次装的时候图省事全勾了结果FNC源码在XE7和11上各编译了几分钟装完还发现老版本IDE里加载的包不是最新生成的又得重新处理。2.2 多版本IDE共存时的安装顺序TMS的安装工具虽然会为不同IDE版本分别生成包文件但如果同时装多个版本建议先装最新版比如13 Florence再装老版本比如XE7。原因很简单TMS源码编译时依赖当前IDE的编译器新版编译器编译出来的包在老版本IDE里不见得完全兼容。先装新版再用老版本重新编译覆盖能减少动态库路径混乱导致的奇怪问题。装完之后打开每个IDE的组件面板应该能看到TMS FNC相关的分组。如果某个IDE版本里没有出现组件多半是那个版本的源码目录没有正确加入到Library路径或者安装时没勾选。这种情况不需要重装在Tools-Options-Library里把TMS对应的源码目录加进搜索路径就行。这里要特别留意版本目录不能混新版本IDE去引用老版本源码目录轻则编译报错重则IDE启动时就弹一堆找不到类的框。下面这张表是我自己整理过的安装后症状对照遇到问题可以先按这个思路排查。现象可能原因处理方式组件面板没有FNC分类安装时未勾选当前IDE或Library路径没有生效在Tools-Options-Library中检查并添加对应版本源码目录工程打开后控件全部消失搜索路径中存在多个版本源码目录IDE加载了错误包清理工程Search Path只保留当前安装版本对应的目录运行时报找不到bpl/dllRuntime Packages未勾选TMS的运行时包在Project-Options-Runtime Packages中勾选对应包CBuilder链接时报找不到文件CBuilder工具链与lib路径不匹配检查Project Options中的lib搜索路径确认使用对应Clang/经典编译器生成的文件2.3 装完必须做的三件事第一件事分别用32位和64位目标平台编译一次TMS自带的Demo确认运行库路径没配错。特别是64位目标平台如果Debug模式下找不到bpl运行某些Demo会直接报错这个检查能提前暴露问题。很多团队只装了32位路径到了64位发布时才报缺库往往要浪费半天定位。第二件事确认IDE的Runtime Packages里已经勾选TMS FNC相关的运行时包。这一步很容易被忽略尤其是从老版本升级IDE后编辑器里放一个FNC控件没问题编译也不报错但一运行就提示找不到动态库多半就是Runtime Packages没配好。第三件事CBuilder用户要额外验证一下CBuilder工程能否正确链接。TMS FNC虽然底层是Delphi单元但官方支持CBuilder安装后会自动生成CBuilder可用的lib文件。如果你用的是Clang工具链的CBuilder版本链接参数和经典编译器不一样遇到链接器报找不到文件去检查项目属性里的Additional Options是否包含了FNC lib路径。这个坑比较隐蔽更容易出现在混合语言的团队里。3. 核心控件实战查询、扫码、导入导出都能用3.1 TMSFNCGrid把查询结果和Excel导出统一起来我项目里用得最多的是TMSFNCGrid。它的职责很纯粹展示数据、点击排序、选中行、导出。日常开发中后台查出来的数据直接往Grid里填代码非常直接Grid1.BeginUpdate; try Grid1.Clear; Grid1.RowCount : 100; Grid1.ColCount : 5; for i : 0 to 99 do begin Grid1.Cells[0, i] : IntToStr(i); Grid1.Cells[1, i] : Format(名称%2d, [i]); end; finally Grid1.EndUpdate; end;上面这个填充逻辑放到VCL工程里能跑放到FMX工程里也能跑这就是FNC的核心价值。如果你做的是查询模块完全可以把TDataSet或JSON转成Grid数据的逻辑封装成公共函数所有窗体共用。再配合很多老项目里的“memo中的数据导入Excel”需求TMSFNCGrid的导出功能会省很多事Grid1.SaveAsXLSX(query_result.xlsx);这一行代码就能把表格内容导成xlsx比逐行手动写Excel组件干净太多。实际项目里我通常会包一层通用工具方法功能是“把任意TDataSet导出到Excel”内部先创建一个不可见的Grid再把DataSet内容填充进去最后SaveAsXLSX。整个过程对调用方隐藏业务代码就一行。这个工具方法在项目里被多个模块复用从部门列表到库存台账都能用客户需求里凡是“给个Excel表”的基本一行代码搞定。3.2 TMSFNCTreeViewPDA扫码导航与懒加载另一个让客户满意的控件是TMSFNCTreeView。做仓库管理、设备管理这类系统时左侧通常是一棵组织或分类树右侧配合扫码结果定位。TMSFNCTreeView的节点可以自己做懒加载在节点展开时才去数据库拉子节点数据量大时不会卡。懒加载的核心是回调事件里判断当前展开节点的ID然后异步查询并插入子节点例如在节点展开事件里判断当前节点是否已经加载过没加载过才去fill。我做过一个PDA扫码场景手持设备上用FMX框架扫到一条码后我要根据条码定位到树上对应的分类节点。核心逻辑很简单遍历树或按已展开节点ID查找找到后设置节点的Selected和Expanded然后滚动到可视区域。这在VCL下是树控件的常规操作在FMX下如果不用FNC各平台树控件的API差异会让你多写不少适配代码。用FNC之后桌面和平板的树操作代码完全一致后面给客户增加平板端这个模块基本是零改动移植。3.3 工具栏、按钮、编辑框桌面和移动端风格一致很多开发者以为FNC重点是表格和树其实基础控件也很值得用。TMSFNCToolBar配合按钮、搜索框、分隔符可以快速搭出一个统一的顶部操作栏。比原生ToolBar的好处很明显在Windows和移动端上视觉一致不会出现桌面用VCL工具栏、移动端要用ActionBar这种两套代码的割裂感。用这些基础控件时有一点要提醒FNC控件有自己的Style体系设计期选好风格比运行期切换省事。我自己会在项目启动时调用一个统一的初始化函数把所有FNC控件的字体、字号、主题设置一遍这样全应用的观感会比较统一不需要在几十个窗体里逐个调。另外要注意FNC按钮在VCL下虽然不会自动获得系统焦点框但可以自己响应焦点事件画高亮移动端则要考虑触摸按下态。这个细节点如果不处理桌面端手感正常平板端点击按钮时没有任何视觉反馈用户会觉得不跟手。3.4 用JSON数据驱动FNC界面项目中很多接口返回的是JSON直接解析JSON填充FNC控件是复用度很高的套路。Delphi自带的System.JSON就能做不需要引第三方库。比如接口返回一个分类列表var json: TJSONObject; arr: TJSONArray; i: Integer; begin json : TJSONObject.ParseJSONValue(Response) as TJSONObject; try arr : json.GetValueTJSONArray(categories); TreeView1.BeginUpdate; try for i : 0 to arr.Count - 1 do AddTreeNode(TreeView1, arr.Items[i]); finally TreeView1.EndUpdate; end; finally json.Free; end; end;这套做法在桌面和移动端完全通用。我后来给PDA端的扫码结果页、库存查询页都采用了同一套JSON解析逻辑数据层抽成公共单元界面层只负责绑定。热搜词里大量出现“json delphi”说明这是很多Delphi开发者的共同需求。如果你想写一套前端无关的业务逻辑JSON FNC控件是目前很顺手的组合不需要为界面展示单独再做一套对象列表。3.5 Demo目录是最好的入门手册TMS FNC UI Pack安装目录下带着大量Demo覆盖几乎所有控件这个目录我强烈建议从头到尾过一遍。每个Demo基本是一个独立子目录里面有工程文件和一个展示该控件特性的窗体。遇到某个控件不知道某个属性是干嘛的直接在Demo里搜比翻文档快。我第一次真正搞懂TMSFNCMemo的段落样式和富文本加载就是在Demo源码里看到的后来做需求直接借用了它的示例代码。Demo还有一个用处验证控件当前版本的行为。比如某个控件在新版本里改了默认滚动条样式你拿老项目的代码对比Demo就能看出差异快速判断是升级引起的行为变化还是自己代码的问题。对从XE7升到13 Florence的项目来说这一招尤其好用。4. Full Source的价值从读源码到二次开发边界4.1 源码里看FNC的事件派发TMS FNC UI Pack是带完整源码的。深入源码最大的收获是理解FNC控件的事件派发机制。FNC控件自己管理鼠标和键盘内部有一套事件分发逻辑控件收到宿主消息后会先经过适配层转换成统一的“挂起事件、派发回调”流程。举个例子你在设计期给TMSFNCGrid的OnClick写代码运行后触发这个事件中间会经过宿主消息捕获、转换成FNC内部事件、再回调到OnClick。这个链路在源码里能直接打断点看。刚开始看可能觉得绕但理解后你会发现这正是FNC能跨框架复用的底层原因。源码里还能学到TMS作者对Canvas绘制的组织方式比如如何把绘制逻辑分成“计算布局”和“实际渲染”两个阶段。这个分层思路对你以后写自定义控件非常有用——如果你把布局计算和渲染混在一起改任何一个尺寸都要重绘全部内容性能会急剧下降。4.2 继承或组合自定义控件的两条路有了完整源码二次开发就有两条路。第一条是继承你写一个TTMSFNCGridEx继承自TTMSFNCGrid在里面加公共的初始化、导出、查询方法然后把原TTMSFNCGrid替换成这个子类。第二条是组合做一个通用的UserControl或Frame里面放FNC控件把业务逻辑封装成公共组件类似做一个业务组件库。我的建议是除非要改控件绘制细节否则优先组合不要继承。因为FNC控件本身功能已经很多继承后叠加业务逻辑很容易把基类的复杂度又往上抬一层后期升级TMS时还要处理父类接口变化。组合则把业务逻辑和控件隔离开升级影响小得多。比如我现在的通用查询框就是一个Frame内部放TMSFNCGrid、TMSFNCComboBox、TMSFNCButton对外暴露几个方法和事件。业务窗体只需拖一个Frame进去写几行绑定代码不用再去理解Grid的各种细节。4.3 升级版本时源码被覆盖的应对因为是完整源码很多人会忍不住直接改源码加功能。我的经验是可以读源码、打断点但尽量不要直接改TMS的源码文件。TMS后续版本升级时新的源文件会覆盖掉你改过的文件一旦出现合并冲突排查成本比你自己做的那点扩展高得多。真想动底层做法是复制源码里相关的几个单元出来改个名放到自己的源目录编译时优先搜索自己的目录。这样既满足了定制需求又不会影响后续升级。从XE7项目迁移到13 Florence时还会碰到另一个问题旧项目里用到的某些FNC属性或方法在新版本中被标记为Deprecated编译时会出一堆警告。这个不可怕关键是先让编译器把警告列出来再逐个判断是直接用新API替换还是保持旧写法。如果只是编译警告且功能正常可以先不处理但最好记录在项目技术债清单里别放任不管。团队的另一个项目就是因为没管Deprecated警告升级到13后某些旧属性直接不生效排查了很久才发现是版本迁移导致。5. 排雷实录IDE丢失控件、DPI漂移、移动端卡顿5.1 每次打开IDE控件就消失的根因网上经常能看到“控件版本问题导致每次进入IDE都丢失控件需要重新放置保存后还是那样”的提问我也遇到过类似情况。打开一个用TMS FNC写的工程Form上明明放了一堆FNC控件但IDE打开后组件全部消失显示成找不到类的提示重新放一遍保存后下次打开还是老样子。这个问题的根因绝大多数情况下不是控件安装失败而是工程的搜索路径和运行时包没配对。具体来说工程文件在打开时IDE会根据工程设置的搜索路径去找控件所在单元。如果搜索路径里同时存在多个版本的TMS FNC源码目录IDE可能加载了错误版本的包设计期控件就无法创建。解决方法是检查工程属性里的Search Path只保留当前安装版本对应的目录再检查Runtime Packages确认TMS FNC的设计期包和运行时包都来自同一版本。排掉这两个因素后控件消失基本就不会再出现了。这类问题还有一个诱因从老版本工程迁移到新IDE时工程的搜索路径里还残留着旧IDE版本的路径。IDE不会自动清理必须手动改。养成习惯任何带版本号的第三方包路径升级IDE后先检查一遍能省掉大量“每次进IDE丢控件”的烦恼。5.2 高分屏DPI导致的布局漂移Windows下高分屏是个老问题。FNC控件虽然自绘但还是要处理系统的DPI变化。我曾经在Win10的150%缩放下遇到FNCGrid的行高和表头高度本文还有配套的精品资源点击获取