
简介报表控件是跨平台应用开发中连接数据与打印输出的关键组件其核心原理在于通过模板定义文档结构再结合数据源接口和统一的渲染引擎实现一次设计、多处运行。面对FireMonkey框架在Android、Windows等平台上的打印差异和PDF导出需求成熟报表方案能显著降低开发成本。FastReport FMX作为Delphi生态中常用的报表工具支持可视化设计器、多种数据源绑定及PDF、Excel等格式导出尤其适合处理中文乱码、分页错乱等移动端报表难题。在实际工程中从安装部署、设计器操作到移动端字体与尺寸适配都需要系统化的实践指引。本文以FastReport FMX v2025.2 for Delphi 13为对象记录在FireMonkey项目中从零搭建报表环境的完整流程涵盖组件安装、数据关联、动态内容生成及Android真机部署的关键技巧帮助开发者快速掌握跨平台报表的实现方法。 最近在做一个 FireMonkey 项目被报表模块折磨得够呛。Windows 桌面端跑得好好的一到 Android 平板上要么中文变成方块要么分页乱套客户直接扔过来一句“你们这个报表不行”。折腾两天后我决定老老实实用 FastReport FMX。正好手头拿到 FastReport FMX v2025.2 for Delphi 13 Florence 的包这篇文章把从安装部署到实际写报表的完整过程都记录一下。如果你是 Delphi 开发者尤其是用 FireMonkey 做跨平台应用需要生成 PDF、打印、导出报表这篇应该能帮你少走不少弯路。先说清楚这是 FMX 版不是 VCL 版两者虽然同门但安装方式和使用习惯差别不小。1. FireMonkey 报表的困境以及 FastReport FMX 为什么能填坑1.1 FMX 跨平台 UI 很香但报表一直是个老大难FMX 框架本身跨平台做得很好一套代码编到 Windows、macOS、iOS、AndroidUI 效果也接近原生。但报表这玩意和平台关联太深了因为报表最终要落到打印和 PDF而每个平台的打印系统完全不一样。Windows 有 GDI/EMFmacOS 有 QuartzAndroid 打印服务各家厂商还不太一样。FMX 自带的打印支持其实只是最基础的页面绘制真要做一个带页眉页脚、分页、数据分组的正式报表靠自己写几乎是不现实的。自己写报表常规路子有三条我全走过。第一条是用 TLayout 堆页面设计时看着直观运行时把数据库记录循环铺到子控件上数据一多界面就卡分页只能靠 TScrollBox打印缩放完全失控。第二条是用 TStringGrid 或 TGrid 展示表格样式好调但 TGrid 是屏幕控件不是文档模型导出 PDF 时你得自己绘制格式还原度很差。第三条是在 Canvas 上直接绘制最灵活但页眉怎么重复、页脚怎么放、跨页断行怎么处理、页边距怎么算全得手写维护成本高得吓人。FastReport FMX 的出现把这条逻辑链彻底改了报表模板.fr3里定义的是文档结构数据通过 TDataSet 接口喂进去渲染由引擎统一处理。所以你只需要关心数据从哪来、模板长什么样而不是关心 Windows 和 Android 在打印上有啥区别。这种“一次设计处处渲染”的模型才是 FMX 项目里做报表的正解。1.2 FastReport FMX 的核心能力清单简单列一下这个版本的核心能力方便还没接触过的朋友快速建立认知。能力说明可视化报表设计器嵌入式设计器可以直接在程序中打开也可以单独编辑 .fr3 模板数据源连接支持 TFDQuery、TDataSet、FDMemTable、TClientDataSet 等标准 DataSet 接口报表对象文本、图片、形状、线条、富文本、条码、复选框、表格等 40 多种导出能力PDF、XLSX、DOCX、CSV、HTML、图片BMP/PNG/JPEG/TIFF、XML跨平台Windows、macOS、iOS、Android、Linux 共用同一套模板多语言内置中文等多语言资源设计器菜单可切换实际用下来最让我满意的是条码对象和 PDF 导出的稳定性。以前用 Canvas 画条码经常被扫码枪识别不了换成 FastReport 内置的 Code128 和 QR Code 之后这个问题再没出现过。1.3 为什么升级到 v2025.2v2025.2 这个版本最直观的变化是官方宣告支持 Delphi 13 Florence。其次在高分屏设计器、PDF 导出字体嵌入、Linux 部署方面都有改进。我实测下来PDF 导出在中文和嵌入字体方面比之前版本稳定Android 上中文 PDF 导出不再出现方块字。如果你们项目里有跨平台报表需求或者正准备迁移到 Delphi 13这个版本值得关注。另外一个细节是v2025.2 对 FMX 的 HiDPI 支持明显做得更好了Windows 上 150% 缩放的屏幕里设计器里的标尺和控件位置不会错位。之前某些版本在 4K 屏上打开设计器字体小到怀疑人生这个版本修复得不错。1.4 Retail 版与试用版的区别Retail 指的是零售正式版和 Trial 试用版的主要区别在于试用版会在预览和导出时加限制比如水印、部分导出格式不可用Retail 版功能完整没有这些限制。安装包命名里的 Retail 表明这不是评估版而是完整功能的正式授权版本。这里也提醒一句FastReport 是商业控件拿到安装包后务必确认授权许可不要在未经授权的环境里使用。2. 从 rar 压缩包到 IDE 可用的完整部署笔记2.1 解压后的目录结构先认清楚再动手我拿到的是 FastReport FMX v2025.2 for Delphi 13 Florence Retail.rar解压后是典型的 FastReport FMX 分发包结构。核心目录有这么几个FastReportFMX\Lib包含各平台的运行时 .dcu 和编译好的 .bplFastReportFMX\Design设计期包源码和编译单元这是要安装进 IDE 的部分FastReportFMX\Source核心源码Retail 版通常包含排查问题时很有用FastReportFMX\Demos官方 Demo强烈建议先跑一遍FastReportFMX\Setup.exe 或 Install.bat官方安装脚本如果你手里的压缩包里有 Setup.exe直接以管理员身份运行它会自动识别 Delphi 版本并完成路径配置。但如果只有源码和 dpk就需要手动编译安装。我这次是手动安装的因为我需要同时给 Win32、Win64 和 Android 三个平台准备环境脚本自动装的路径有时候不满足需求。2.2 在 Delphi 13 中设置 Library 路径手动安装的第一步是把 FastReportFMX 的 Lib 目录加入 IDE 库路径。操作路径是 Tools - Options - Delphi Options - Library在 Library path 里新增以下几项$(FastReportFMX)\Lib\Win32 $(FastReportFMX)\Lib\Win64 $(FastReportFMX)\Lib\Android $(FastReportFMX)\Lib\iOS $(FastReportFMX)\Lib\OSX这里强烈建议先定义一个环境变量 FastReportFMX指向解压根目录然后在 Library path 里引用变量。这样以后升级控件版本只需要改环境变量不用逐个改项目搜索路径。这步不做的话编译你的项目时会报找不到 FastReport 相关单元而且错误提示不会直接告诉你缺的是路径只会说某个 frx 单元不存在容易让人误判成组件没装好。2.3 编译并安装设计期包FastReport FMX 和其他控件一样分运行时包和设计期包。运行时包负责程序运行时的逻辑设计期包安装到 IDE 后工具箱里才会出现 TfrxReport、TfrxDBDataSet 这些组件。安装步骤大致是这样打开 FastReportFMX\Design 目录下的 .dpk 文件用 Delphi 13 打开。在工程管理器里确认目标平台为 Win32设计期包一般只装 Win32。先编译运行时包右键 dpk 选择 Build确保没有编译错误。再对设计期 dpk 执行 Install看到 “Package installed successfully” 提示。重启 IDE打开一个 FMX 项目在 Tool Palette 搜索 frx就能看到组件。编译过程中如果提示找不到 dcu回 2.2 步检查路径顺序尽量把 FastReport 的 Lib 放在 Library path 列表前面避免和其他控件版本冲突。这里有个小技巧编译顺序一定是从最底层的运行时包开始往上编译如果先装了设计期包会发现它依赖的运行时包还没注册IDE 启动时会报 “Cannot load package” 错误。2.4 解决“每次进 IDE 控件丢失”的经典问题很多 Delphi 开发者都遇到过装完控件当时能用重启 IDE 后组件面板里控件不见了或者打开项目提示“组件类不存在”。这在 FastReport FMX 安装里也常见我排查下来无非三种原因。第一种装的是 32 位设计期包但 IDE 以 64 位模式运行。Delphi 13 的 IDE 默认是 32 位但如果你装了其他版本的 64 位 IDE设计期包必须分别安装到对应的 IDE 里。第二种设计期包依赖的运行时包没有被注册到系统路径。把 Lib 路径加入 IDE 库路径只是让编译器能找到 dcu但安装包还要在 Windows 系统路径下找到 .bpl运行时包没注册好IDE 启动时静默跳过组件就不见了。第三种FastReport 版本和 Delphi 版本不严格匹配项目面板里还残留旧版本的 FastReport 包IDE 加载失败。如果重启后还是丢控件还有一个土办法用文本编辑器打开项目的 .dproj 文件搜索 fastreport 关键字清理掉旧版本残留的搜索路径再重新加载项目。IDE 会按 dproj 里的搜索路径去找包路径不对就报错。这个办法能解决绝大多数“装好了但项目打不开”的问题。2.5 验证安装成功的标志安装完不要急着写代码先跑官方 Demo 验证环境。打开 Demos 目录下的一个 FMX Demo比如 PrintPreview编译运行。如果设计器能打开 .fr3 文件、能预览、能导出 PDF说明环境没问题。我第一次装完没跑 Demo直接写代码结果接口不会用查了半天文档才明白。跑 Demo 还有一个好处是能学习官方推荐的写法比如设计器里数据字典怎么配置、代码里 frxReport 怎么和 DBDataSet 关联这些在 Demo 里都有现成的例子。3. 设计器里最常见的三类操作连接数据、版面布局、动态内容3.1 把 TFDQuery 的数据拿到报表里FastReport FMX 最常用的数据绑定方式是 TfrxDBDataSet。在 FMX 窗体上放一个 TFDConnection、TFDQuery 和 TfrxReport然后再放一个 TfrxDBDataSet把它的 DataSet 属性指向 TFDQuery1。接下来在设计器里操作双击 TfrxReport 打开报表设计器。点击左侧“数据字典”窗口右键新建一个 DataSet 数据源选择 frxDBDataSet1。把 DataSet 的字段拖到报表区域FastReport 会自动生成标题带和数据带。在数据带MasterData上确认数据源已绑定运行时它会自动迭代数据源里的每一条记录。一个新手特别容易懵的点是设计器里的数据带和数据库记录之间的关系。其实很简单MasterData 就是一个循环模板一条记录渲染一次设计器里看到的只是一行运行时循环输出所有行。页脚带在设计器里是固定的运行时只有当前页显示一次。如果想让数据刚好占满一页可以在数据带的高度上做文章把数据带高度设置成页面可用高度减掉页眉页脚的高度这样数据量不足一页时自动铺满数据多时则自动分页。3.2 主从报表的绑定方式主从报表常见于订单单据一个订单对应多个明细。FastReport FMX 里配置也不复杂。窗体上放两个 TFDQueryqryMaster 和 qryDetailqryDetail 通过参数关联 qryMaster。再放两个 TfrxDBDataSetfrxDBMaster 指向 qryMasterfrxDBDetail 指向 qryDetail。设计器里的关键步骤是添加两个数据带MasterData 绑定 frxDBMasterDetailData 绑定 frxDBDetail。然后在 DetailData 的 DataSource 属性里选择 MasterDataFastReport 会自动在主数据带迭代时同步刷新子数据。这里要注意qryDetail 的 SQL 要写成参数化查询参数值来自主查询的字段SELECT * FROM order_items WHERE order_id :ORDER_ID我实测这种参数联动在移动端速度还可以订单明细几百条没问题。如果数据量再大就要考虑先把明细数据一次性加载到 FDMemTable再做内存关联避免逐条查询数据库。3.3 动态文本、图片和条码业务报表很少是纯静态文本常见的是根据数据库字段动态显示。在 FastReport 里动态显示字段的写法很直观双击文本对象在表达式编辑器里写 [qryMaster.FIELD_NAME]。要拼接字符串写 [qryMaster.客户姓名] - [qryMaster.订单号]。要显示条件内容可以用 IIF 函数格式是 IIF(条件, 真值, 假值)IIF([qryMaster.金额] 1000, 大额, 普通)图片对象可以绑定数据库 BLOB 字段比如签名照片、商品图片也可以通过代码在 BeforePrint 事件里动态赋值。条码对象最常用在物流单上支持 Code128、QR Code 等。FMX 版在 Android 上也可以渲染条码这在 PDA 应用里非常实用。我做过一个项目用 Delphi FireMonkey 的扫码组件拿到快递单号后直接调用 FastReport 生成一张带条码的标签从扫码到出单可以一条龙整个流程跑下来体验很顺。3.4 报表预览与导出在代码里启动预览最简单的方式是frxReport1.ShowReport();如果要把预览控件嵌入窗体比如做一个自定义的预览页面可以放一个 TfrxPreview 控件到 FMX 窗体然后设置frxReport1.Preview : frxPreview1; frxReport1.ShowReport();导出 PDF 也很直接frxReport1.PrepareReport(); frxReport1.Export(frxPDFExport1);这里提醒一下FMX 版的 PDF 导出有一个容易踩的坑嵌入字体选项。在 TfrxPDFExport 的 Engine 属性里有 EmbeddingFonts 相关设置移动端建议开启。否则 PDF 文件到了别的设备上如果对方设备没有你用的中文字体显示出来就是方框。这个坑我踩过一次客户在手机上打开 PDF 说全是乱码排查半天发现是导出时没有嵌入字体。4. 移动端跑报表字体、尺寸和运行时部署的几个大坑4.1 同一套报表在 Windows 和 Android 上的差异理论上 FastReport FMX 保证跨平台一致但实际体验里桌面和移动端还是有三个明显差异。第一个是字体差异Windows 的微软雅黑Android 上是 Roboto 或者厂商字体同一个字体名两边可能都有但渲染宽度不同文本会自动换行导致 PDF 分页不同。第二个是 DPI 差异FMX 的 TfrxReport 走的是虚拟坐标然后在不同平台上按 DPI 换算。Android 平板默认密度和 Windows 的 96dpi 不同同样的报表模板在平板上预览会显得偏小。第三个是打印支持Android 上没有通用的打印对话框直接打印不完整通常都是导出 PDF 再交给其他 App 处理。这三点在项目规划阶段就要考虑不要等模板设计完再适配。我当时就是先设计模板后适配移动端结果字体和 DPI 两个问题来回调浪费了不少时间。4.2 中文字体在 FMX Android 上的处理中文字体是重灾区。我遇到的情况是Windows 上设置“宋体”没问题到了 Android 上所有中文变方块。原因很简单Android 系统里没有“宋体”这个字体名。FastReport FMX 的解决方案是使用字体回退机制或者干脆在代码里适配。方案一模板里不直接指定具体字体名运行时根据平台判断选择字体用条件编译或者代码动态设置。方案二把字体打包进 Assets通过代码注册字体文件到 FMX 字体缓存再让报表引用注册后的字体名。方案三Android 上直接用系统默认字体模板中文字对象全部不设置 FontNameFastReport 会使用默认字体。我实际项目里用的是方案三的变种在代码里设置一个公共字体名所有中文文本跑报表前统一替换。虽然土但最稳。后来发现一个问题系统默认字体在 Android 上显示中文没问题但在 Windows 上字体比较丑所以我在代码里区分平台Windows 用微软雅黑Android 用系统默认字体。4.3 运行时文件部署FMX 移动端跑 FastReport不只是代码里引用单元那么简单。Android 打包时如果报错找不到 frx 资源要去 Deployment Manager 里检查资源文件是否添加。中文字体文件比如从 Windows 拷贝的 msyh.ttf要添加到 Android 的 assets 目录并确保 Remote Path 设为 assets/。如果用到条码检查使用的条码库是否需要在 Android 下额外引入 .so 文件。这些步骤容易漏漏了之后表现也很典型开发机上跑没问题部署到真机或模拟器就崩溃。我遇到过最诡异的一次是报表里用了一张本地图片Windows 上正常Android 上报“Cannot open file”最后发现是 Deployment Manager 里没有把图片文件打进去。建议在项目设置里把 Deployment 里的内容逐项对一遍别图省事。4.4 尺寸自适应A4 不是唯一答案移动端报表经常遇到这个问题。FastReport FMX 里页面尺寸是模板属性A4、Letter 只是预设你完全可以新建一个自定义纸张宽度按屏幕比例设置。我习惯建一个“屏幕宽”纸张宽度设为屏幕宽度像素高度按内容长度动态调整。这样平板上预览效果接近原生应用。还有预览缩放的问题。TfrxPreview 控件在 Android 上支持触摸缩放但缩放比例如果设置不当用户双指缩放之后分页预览会乱。建议固定启动缩放比例为“适合宽度”再允许用户手动缩放体验最好。这个设置我记得在 TfrxPreview 的 ZoomMode 属性里可以设成 fzxFitWidth。5. 与 Delphi 13 生态的配合从数据到导出的实战组合5.1 结合 FDMemTable 做报表数据集很多报表数据不是直接来自数据库而是内存数组、JSON 解析结果。这时候不用绕道数据库直接把数据塞进 FDMemTable 就行。TFDMemTable 有个特性可以 FieldDefs 自动建字段也可以复用一个查询的字段结构。代码示例FDMemTable1.Close; FDMemTable1.FieldDefs.Clear; FDMemTable1.FieldDefs.Add(ID, ftInteger); FDMemTable1.FieldDefs.Add(Name, ftString, 50); FDMemTable1.Open; FDMemTable1.Append; FDMemTable1.FieldByName(ID).AsInteger : 1; FDMemTable1.FieldByName(Name).AsString : Delphi 13; FDMemTable1.Post;然后把 TfrxDBDataSet1.DataSet 指向 FDMemTable1报表数据源不用动模板不用改。这种模式和“先把业务逻辑跑完最后集中渲染报表”的思路很搭。我在一个 PDA 项目里就是这样用的扫码拿到数据处理后塞进 FDMemTable再生成报表逻辑清晰调试也方便。5.2 与 TCSVDataSet、ODAC 等常用组件的配合FastReport FMX 的数据接口是 TDataSet 标准接口理论上任何 TDataSet 子类都能接上。我用过 TCSVDataSet 加载导出的 CSV再丢给 FastReport 出报表链路很简单CSVDataSet1.FileName : report_data.csv; CSVDataSet1.Open; frxDBDataSet1.DataSet : CSVDataSet1; frxReport1.ShowReport();这套组合适合从外部系统拿数据的场景比如客户给的 CSV 导出文件不用导入数据库直接出报表。ODAC 组件在 Delphi 7 时代和 FastReport 的 VCL 版配合很多但在 Delphi 13 FMX 项目中ODAC 提供 FMX 支持的话也可以这样接。关键是 DataSet 接口不变FastReport 认的是 DataSet不是具体组件。5.3 PDF 导出、水印和加密业务报表里 PDF 导出最常见的两个需求是水印和加密。FastReport FMX 的 PDFExport 属性里都有。UserPassword 和 OwnerPassword 分别控制打开密码和权限密码。水印可以在报表模板上放一个半透明文本或图片也可以在 TfrxPDFExport 的水印属性里配置。我实际用的是模板里的半透明文本因为这样在预览时也能看到效果导出 PDF 时保持一致。还有一个容易被忽略的细节导出 PDF 到微信里打开建议将编码设为“Unicode”兼容性比 ANSI 好中文不会乱码。这个选项在 TfrxPDFExport 的属性面板里默认值有时候是 ANSI改成 Unicode 后跨平台分享就稳定了。5.4 性能优化大数据量报表该注意什么先说结论FastReport FMX 在大数据量下不要用设计器预览模式。几十万条记录直接 ShowReport()UI 线程会被拖死用户能看到界面卡成 PPT。我的做法是关闭报表实时预览调用 PrepareReport 时不绑定预览控件。使用缓存数据把数据先加载到 FDMemTable再传给报表避免报表引擎直接连接数据库查询接口反复取数。必要的时候用报表脚本FastReport 支持在报表里写 Pascal 脚本做聚合计算比在 Delphi 代码里循环高效。控制每页数据量模板里设置数据带每页显示 N 行超过则自动换页减少单页渲染对象数量。实测一个三万多行的报表直接 ShowReport 需要 8 秒优化后 PrepareReport 控制在 2 秒内预览只渲染当前页用户体验完全不一样。6. 关于版本、许可和后续升级的几点经验6.1 版本匹配FastReport 版本和 Delphi 版本必须严格对应这是反复踩出来的教训。FastReport FMX 的每个版本针对特定 Delphi 版本编译v2025.2 for Delphi 13 是给 Delphi 13 Florence 用的。如果你用 Delphi 12 Athens硬装 for Delphi 13 的包编译期可能过了但运行期会 BPL 版本不匹配报错。尤其是从旧版本迁到新 Delphi 时不能只替换安装包还要把项目里所有 FastReport 相关 DCU 重新编译一遍。项目搜索路径里如果同时存在旧版和新版目录编译器会随机选择其中一个报出非常奇怪的错误比如“类 TfrxReport 没有默认属性”。这种问题排查半小时都找不到头绪最后发现是搜索路径顺序问题。所以升级时先在 IDE 的 Library path 里把旧路径删干净再添加新路径。6.2 Retail 授权管理的细节Retail 授权通常绑定机器或用户。FastReport 的激活方式一般是通过授权文件或者注册号。拿到安装包后先找到 GetLicense 之类的工具或文档按照官网步骤激活不要在开发机上重复激活过多导致授权失效。另一个容易忽略的细节如果你是团队开发最好把授权文件放在一个统一的位置让所有开发机的 IDE 都能读到。否则别人打开你的项目时FastReport 虽然能编译但某些功能可能被降级成试用模式导出 PDF 带水印这种问题第一反应根本想不到是授权问题。6.3 升级到新版本之前备份什么升级 FastReport FMX 之前建议备份以下内容现有的 .fr3 模板文件新版本设计器可以打开旧模板但反向不一定兼容改坏了就回不去了。项目里的 FastReport 相关单元引用搜索 frx 关键字记录所有使用位置。IDE 的组件包配置记录当前已经安装的 FastReport 包名和版本号出问题回滚时有用。我吃过一次亏升级之前没备份模板新版设计器打开旧模板后保存结果一个字段的表达式被自动改掉了数据错位查了一下午。从那以后凡是涉及报表的升级我第一件事就是备份 .fr3 目录。6.4 从个人经验谈报表控件选型最后说点大实话。如果在 Delphi 13 FMX 项目里要用报表可选的不多FastReport FMX 是最成熟的选择另一个是 Report Builder 的 FMX 版但流行度和教程都少得多。如果你刚进项目建议直接押 FastReport因为资料多、案例多、遇到问题能搜到答案。如果你只是在 VCL 项目里做报表FastReport VCL 版也很好但别把 FMX 版的源码和 VCL 版混装两个版本在同一个 IDE 里并存容易冲突。需要在程序里动态判断当前平台时用 {$IFDEF MSWINDOWS} 这类条件编译区分别把两个版本的单元都写在 uses 里。至少在我们这个项目里报表模块从最开始的手写 Canvas 一路折腾到 FastReport FMX后面基本就顺了。如果你也在 Delphi 13 Florence 上用 FMX 做跨平台报表可以按这个顺序走先装好环境再跑 Demo接着拿一个简单报表练手最后再上移动端。报表这东西模板设计阶段多花点时间后面能帮你省下一大堆熬夜的功夫。本文还有配套的精品资源点击获取