實戰(zhàn)解析)
簡介FastReport Vcl 5.3.13 for Delphi 7 是面向 Delphi 7 開發(fā)者的報表生成組件主要解決老項目與既有業(yè)務(wù)系統(tǒng)中集成現(xiàn)代報表、并快速生成含二維碼標(biāo)簽的復(fù)雜打印需求。該版本在傳統(tǒng)表格、圖表、圖像與文本混排基礎(chǔ)上新增二維碼生成與顯示能力適合電商物流單、產(chǎn)品溯源標(biāo)簽等需要快速掃碼解析的場景。壓縮包共 969 個文件大小約 12.92MB文件類型以 dpk 組件安裝包、pas 單元源碼、bdsproj 與 dproj 工程文件、dfm 與 lfm 窗體表單、res 與 dcr 資源圖標(biāo)為主并保留多版本工程配置便于開發(fā)者在 Delphi 7 中對照源碼和窗體定義進(jìn)行二次修改與部署。資源已有 775 人學(xué)習(xí)下載屬于實用型組件包。借助內(nèi)置的可視化設(shè)計器、腳本引擎與數(shù)據(jù)綁定功能可以拖放式設(shè)計報表、動態(tài)計算字段、直連 SQL Server、Oracle、MySQL 等數(shù)據(jù)庫并輸出打印預(yù)覽還能導(dǎo)出 PDF、HTML、Excel 等多種格式滿足多格式分發(fā)需求。針對二維碼這一關(guān)鍵特性開發(fā)者可直接在報表中放置條碼對象并綁定數(shù)據(jù)源省去自行封裝掃碼數(shù)據(jù)的額外工作。1. 還在用 Delphi7 做報表FastReport Vcl 5.3.13 就是那個「最后順手」的版本老項目還在 Delphi7 上跑報表卻要加二維碼這個需求聽著就頭疼。FastReport Vcl 5.3.13 是少有的、能在 Delphi7 里流暢編譯且原生支持二維碼的 FastReport 版本。5.3 之后的版本逐步切到 Unicode 和更高版本的 DelphiD7 用戶要么升級 IDE要么守著 5.3.x 這個分水嶺。這套資源解決的正是「D7 老項目 二維碼新需求」的夾縫問題報表設(shè)計器、二維碼組件、PDF 導(dǎo)出一條鏈路都是配套好的不用自己拼第三方庫。適合兩類人還在維護(hù) D7 存量系統(tǒng)的開發(fā)者以及被要求「報表加個碼」但又不想動整個技術(shù)棧的倒霉蛋。我這段時間把它在 D7 環(huán)境里完整拆了一遍編譯、設(shè)計、跑數(shù)、導(dǎo)出都驗證過下面這些是能直接照著做的。2. 先把環(huán)境立住在 Delphi7 里裝好 FastReport Vcl 5.3.132.1 為什么 5.3.13 是 D7 的「最后舒適區(qū)」FastReport VCL 從 5.x 開始把渲染引擎重寫了一遍但 5.3.x 這一代對 Win32 老項目的兼容性是最好的。5.4 之后官方把開發(fā)重心轉(zhuǎn)向 Unicode 版本Delphi7 的 AnsiString 體系跑新版本會出現(xiàn)大量類型不匹配的編譯錯誤。我自己試過拿 5.6 的源碼在 D7 里強(qiáng)行編譯報錯主要集中在 Strings 類型和 TfrxCustomMemo 的屬性簽名上修起來沒完沒了。5.3.13 的源碼包是 Ansi 時代的產(chǎn)物跟 D7 的 RTL/VCL 配合是天然順的。這套資源里帶的完整源碼好處是所有單元都保留著 .pas 文件不是編譯好的 .dcu 黑匣子。這意味著你可以像看自己項目代碼一樣去查 FastReport 內(nèi)部實現(xiàn)遇到特殊需求還能直接改源碼重編譯。5.3.13 在 D7 下用的是老式 Delphi 組件安裝流程打開包工程、添加路徑、編譯安裝三步走。跟新版本用 GetIt 或 命令行 MSBuild 的流程完全不一樣這也是很多人在這一步卡住的原因——拿新思路去套老工具。2.2 編譯安裝的三種正確姿勢第一種是 IDE 內(nèi)安裝適合大部分人。先把源碼包解壓到一個不帶空格的路徑下比如D:\FastReport\。然后打開 Delphi7點擊 Component - Install Packages在打開的窗口里點 Add瀏覽到Delphi7\fr5.dpk這個包工程文件。Delphi7 會自動編譯并彈出確認(rèn)框一路 Yes 就好。編譯過程中如果提示找不到frx.inc說明源碼路徑?jīng)]加對需要先到 Tools - Environment Options - Library - Library Path 里把 FastReport 的源碼根目錄加進(jìn)去。第二種是命令行編譯適合要寫腳本批量部署的情況。打開 Delphi7 自帶的命令行環(huán)境開始菜單里的 Delphi 7 - Delphi 7 Command Linecd 到源碼目錄后執(zhí)行dcc32 -B -Q -DDelphi7 fr5.dpk-B是強(qiáng)制全量編譯-Q靜默模式減少輸出-DDelphi7告訴編譯器按 D7 的宏定義來。編譯完再執(zhí)行一次安裝步驟把fr5.bpl注冊到 IDE 里。命令行方式的優(yōu)勢是可重復(fù)我一般會把這條命令寫成一個 .bat 放在源碼目錄里重裝系統(tǒng)后跑一次就行。第三種是只編譯運行時包不裝設(shè)計時包。這種方式適合只需要跑已有報表、不想在 IDE 里拖組件的場景。dclfr5.dpk是設(shè)計時包fr5.dpk是運行時包只裝運行時包的話程序能運行但窗體上不會出現(xiàn) FastReport 的組件面板。業(yè)務(wù)開發(fā)建議兩種都裝上不然寫代碼時沒有組件提示會很痛苦。2.3 路徑配置與 D7 的老脾氣裝好之后有個關(guān)鍵動作確認(rèn) Library Path 里同時包含源碼根目錄和Delphi7子目錄。前者是 FastReport 的公共單元后者是 D7 專屬的包工程目錄。少了任何一個編譯你的項目時都會報File not found: frxClass.dcu這類錯誤。D7 對路徑分隔符要求是分號而且不支持空格路徑源碼放C:\Program Files\FastReport這種帶空格的目錄再怎么配都會出詭異問題。我用一個 D7 老項目的實測配置做參考配置項值源碼根目錄D:\FastReport\D7 包目錄D:\FastReport\Delphi7\BPL 輸出目錄D:\FastReport\Delphi7\DCP 輸出目錄D:\FastReport\Delphi7\編譯后要確認(rèn)fr5.bpl和dclfr5.bpl在同級目錄Windows 的 DLL 搜索順序坑在這里也會發(fā)作BPL 找不到直接導(dǎo)致 IDE 啟動報錯。裝完重啟 Delphi7組件面板出現(xiàn)FastReport頁簽和在FastReport頁簽下的QR Code組件圖標(biāo)就說明安裝成功。3. 二維碼組件上手從拖一個 TfrxQRCode 到生成可掃描的碼3.1 組件在報表里的正確放置位置FastReport 的二維碼不是獨立控件而是寄生在 TfrxReport 頁面上的 TfrxQRCode 對象。在 Delphi7 的組件面板上找到 FastReport 頁簽展開能看到 TfrxQRCode把它拖到報表設(shè)計器的 DataBand 或 MasterData 上。放 DataBand 里能隨明細(xì)數(shù)據(jù)逐行生成放 PageHeader 則只生成一次。實際業(yè)務(wù)里二維碼內(nèi)容如果是訂單號、URL 這類單據(jù)級信息放在 DataBand 上最合理。TfrxQRCode 在 FastReport 內(nèi)部繼承自 TfrxCustomMemo 體系所以它的很多屬性跟文本框是相通的Font、Color、Align都繼承自 memo 的基礎(chǔ)能力。區(qū)別在于它有Text屬性和Expression屬性前者是靜態(tài)文本后者支持 FastReport 的表達(dá)式語法。二維碼內(nèi)容需要拼變量時用Expression而不是Text這是個容易踩的細(xì)節(jié)直接給Text賦表達(dá)式字符串報表會原樣輸出那串字而不是解析結(jié)果。3.2 二維碼參數(shù)一個個調(diào)通TfrxQRCode 的屬性面板里有四個參數(shù)決定二維碼最終能不能被掃出來ErrorLevel、PdfLevel、AutoCalcScale、ShowText。我一個個說明ErrorLevel容錯級別對應(yīng) QR 碼的 L/M/Q/H 四個檔取值 0 到 3。L 級(0)容錯 7%H 級(3)容錯 30%。二維碼里要印 Logo 或者可能被遮擋的選 2( Q 級15%)追求掃描速度的場景選 0 就行。容錯越高碼的密度越大掃描越慢別盲目上 H。PdfLevel這個是 FastReport PDF 導(dǎo)出時的二維碼清晰度等級范圍 0 到 2。0 是普通模式1 是高質(zhì)量矢量模式2 是最佳清晰度。導(dǎo)出 PDF 給印刷廠時務(wù)必設(shè)成 1 或 2否則打印出來的碼糊成一片。AutoCalcScale是否自動計算模塊尺寸。設(shè)為 True 時FastReport 根據(jù)對象尺寸自動決定每個模塊的像素數(shù)適合內(nèi)容長度變化大的動態(tài)二維碼。固定內(nèi)容建議設(shè) False 并手動指定ModuleSize避免同一列二維碼大小不一致。ShowText是否在二維碼下方同時顯示文本內(nèi)容。很多場景下二維碼下方還會印一串可讀的單號設(shè)為 True 可以少放一個文本框但格式控制能力有限我一般關(guān)掉它用單獨的 TfrxMemoView 來控制字體和位置。改完參數(shù)后的預(yù)覽驗證有個快捷方式在報表設(shè)計器里右鍵 TfrxQRCode選 Quick Preview會彈出一個小窗口顯示當(dāng)前內(nèi)容生成的效果。別等在整張報表的預(yù)覽里發(fā)現(xiàn)碼不對再返工那個環(huán)節(jié)調(diào)試效率低很多。3.3 動態(tài)內(nèi)容讓二維碼跟著數(shù)據(jù)集走報表里的二維碼內(nèi)容通常不是寫死的。FastReport 表達(dá)式語法里數(shù)據(jù)集字段直接用[DataSetName.FieldName]引用也可以在 TfrxReport 的變量里拼好再傳給二維碼。我在模擬項目X里驗證過的一個用法是訂單表主鍵 平臺標(biāo)識拼成帶前綴的字符串再生成二維碼?!笌熬Y的單號 二維碼」的報表思路是在源數(shù)據(jù)的 SQL 階段就拼好字符串而不是在 FastReport 里拼。原因有兩個一是 D7 的 FastReport 表達(dá)式對字符串拼接的中文編碼處理偶爾有玄學(xué)問題二是 SQL 里拼好的字符串到了報表層就是純展示出問題更容易定位。SQL 里這樣寫SELECT OrderId, http://example.com/order/ OrderId AS QrContent, CustomerName FROM Orders WHERE OrderDate :startDate報表設(shè)計器里把 TfrxQRCode 的Expression屬性填成[ORDERS.QrContent]預(yù)覽時就能看到每行數(shù)據(jù)生成不同的碼。這個方案在跨數(shù)據(jù)庫場景下有個注意點如果在 Oracle 里拼接字符串要用||而不是在 MySQL 里要用CONCAT()。數(shù)據(jù)層把字符串拼好報表層只負(fù)責(zé)展示是這套鏈路最不容易翻車的分工。4. 報表從取數(shù)到出文件數(shù)據(jù)鏈路與 PDF 導(dǎo)出的完整走查4.1 數(shù)據(jù)集橋接TfrxDBDataset 和 DataBand 的對齊FastReport 取數(shù)走的是經(jīng)典橋接模式先用 Delphi 原生數(shù)據(jù)集從數(shù)據(jù)庫取數(shù)據(jù)比如 TQuery、TADOQuery再通過 TfrxDBDataset 這個橋接組件把數(shù)據(jù)源轉(zhuǎn)發(fā)給 TfrxReport。很多新手直接在 TfrxReport 上連數(shù)據(jù)源D7 時代能碰上各種奇怪問題官方推薦路徑還是老老實實走 TfrxDBDataset。橋接的代碼在窗體單元里寫核心邏輯是先配置原生數(shù)據(jù)集再橋接給報表procedure TForm1.LoadReportData; begin ADOQuery1.Close; ADOQuery1.SQL.Text : SELECT OrderId, CustomerName, QrContent FROM Orders WHERE OrderDate :startDate; ADOQuery1.Parameters.ParamByName(startDate).Value : StartDateEdit.Date; ADOQuery1.Open; frxDBDataset1.DataSet : ADOQuery1; frxReport1.ShowReport; end;這段代碼里有個參數(shù)說明點ADOQuery1.Parameters集合在執(zhí)行Open前必須賦值FastReport 不會替你解析 SQL 參數(shù)。如果你在 FastReport 設(shè)計器里寫了帶參數(shù)的 SQL執(zhí)行時發(fā)現(xiàn)參數(shù)沒生效十有八九是這里的值沒傳進(jìn)去。報表模板里的 MasterData 數(shù)據(jù)帶要正確綁定打開設(shè)計器選中 MasterData在屬性面板的 DataSet 下拉里選frxDBDataset1然后在 DataBand 上放 TfrxMemoView并把Expression填成[ADOQuery1.CustomerName]這種格式。注意這里的表達(dá)式前綴是原生數(shù)據(jù)集的名字不是 frxDBDataset 的名字這是個高頻困惑點。FastReport 內(nèi)部通過 frxDBDataset 的 DataSet 指針能找到原生數(shù)據(jù)集但表達(dá)式的解析路徑是直接對著原生數(shù)據(jù)集字段名取的。4.2 交叉表數(shù)據(jù)的兩種組織方式報表界對交叉表的需求行列轉(zhuǎn)置、統(tǒng)計匯總FastReport 5.3.13 提供了 TfrxCrossView 控件它在設(shè)計器的 Cross 頁簽下。拖到報表頁面上后它有RowLevels、ColumnLevels、CellLevels三個維度屬性需要配置。比如要做「產(chǎn)品類別行 × 月份列 → 銷售額值」的交叉表就在設(shè)計器里把字段分別拖進(jìn)這三個區(qū)域。運行時交叉表數(shù)據(jù)準(zhǔn)備我習(xí)慣在 SQL 里把維度字段和度量字段全部平鋪查出來交叉邏輯交給 TfrxCrossView 處理。這樣 FastReport 的數(shù)據(jù)集接口是扁平的后續(xù)如果換成存儲過程或數(shù)據(jù)集報表模板不用改。這跟直接用 SQL 做 PIVOT 的區(qū)別是SQL PIVOT 的列是靜態(tài)的交叉表的列可以動態(tài)擴(kuò)展。老報表系統(tǒng)里月份是動態(tài)增加的用 TfrxCrossView 能在不改模板的情況下自動多列這是它最大的價值。4.3 PDF 導(dǎo)出中文、字體和文件大小三個坎FastReport 5.3.13 的 PDF 導(dǎo)出用的是內(nèi)置的 TfrxPDFExport 組件。調(diào)用方式是在代碼里創(chuàng)建導(dǎo)出對象綁定報表然后調(diào)用PrepareReport再導(dǎo)出uses frxExportPDF; procedure TForm1.ExportToPDF(Report: TfrxReport; const FileName: string); var PDFExport: TfrxPDFExport; begin PDFExport : TfrxPDFExport.Create(nil); try PDFExport.ShowDialog : False; PDFExport.FileName : FileName; PDFExport.Compressed : True; PDFExport.EmbedFonts : True; PDFExport.PageRange : 1-10; Report.PrepareReport(True); Report.Export(PDFExport); finally PDFExport.Free; end; end;這里Compressed : True能把 PDF 體積壓到三分之一左右EmbedFonts : True是中文 PDF 不亂碼的關(guān)鍵但代價是文件變大。實際項目里如果 PDF 要傳到小程序或網(wǎng)頁端展示我一般折中方案是 EmbedFonts 設(shè)為 True 但只在最終交付稿上開中間審閱稿不開。導(dǎo)出丟失中文的情況排查方向是檢查報表里中文字體是不是設(shè)為「宋體」這類中文字體了——FastReport 導(dǎo)出時如果遇到英文字體名直接跳過嵌入。另一個細(xì)節(jié)PrepareReport(True)的 True 是清空上一次的準(zhǔn)備緩存重復(fù)導(dǎo)出同一份報表但數(shù)據(jù)變了這個 True 必須傳否則導(dǎo)出的是舊數(shù)據(jù)。這是我優(yōu)化導(dǎo)出速度時翻過車的地方繞了很久才發(fā)現(xiàn)是 PrepareReport 的參數(shù)問題。4.4 文件清單這套資源里有什么能直接用拆開這套資源我列了個主要文件清單方便你對照自己缺什么文件/目錄作用Source\FastReport\完整源碼.pas全部保留Delphi7\fr5.dpkD7 運行時包Delphi7\dclfr5.dpkD7 設(shè)計時包Demos\官方示例含二維碼示例Help\編譯好的幫助文檔Demos 目錄里那個帶二維碼的示例報表示范了 TfrxQRCode 的基礎(chǔ)用法是快速上手最快的路徑。我建議先打開它確認(rèn)二維碼能生成再把它當(dāng)作模板刪掉業(yè)務(wù)數(shù)據(jù)改成自己的報表格式比從空白報表開始搭省一半時間。5. 避坑D7 下 FastReport 的四個高頻翻車點5.1 編譯報 E2133字符串類型不匹配現(xiàn)象編譯工程時出現(xiàn)E2133: Incompatible types: AnsiString and string而且在 FastReport 的某個單元里。這是 Delphi7 下最常見的翻車點尤其當(dāng)你把源碼從網(wǎng)上下下來發(fā)現(xiàn)編譯不過。原因FastReport 5.3.13 雖然面向 D7但內(nèi)部有部分單元用到了WideString如果這些單元跟你項目的編譯選項沖突編譯器會把string當(dāng) UnicodeString 處理。另一個常見誘因是 D7 的編譯選項里$H指令被改動默認(rèn) D7 的string是 AnsiString但某些第三方單元改了默認(rèn)值。解決在 FastReport 源碼根目錄的frx.inc文件里強(qiáng)制加上{$H-}和{$WARN SYMBOL_DEPRECATED OFF}然后在你的工程文件里同樣加上這兩行編譯指令。加完之后全量重新編譯 FastReport 包再編譯你的項目E2133 就消停了。D7 環(huán)境下別用$STRINGCHECKS ON那個指令開了之后字符串操作性能下降還有概率觸發(fā)長度檢查異常。5.2 中文字符在二維碼里掃出來是亂碼現(xiàn)象二維碼內(nèi)容含中文掃碼結(jié)果是亂碼。這在 FastReport 5.3.13 里特別典型。原因TfrxQRCode 底層把內(nèi)容交給二維碼編碼庫時默認(rèn)按 AnsiString 的 OEM 代碼頁處理而二維碼標(biāo)準(zhǔn)要求 UTF-8 編碼。Windows 簡體中文環(huán)境默認(rèn)代碼頁是 936GBKFastReport 直接把 GBK 字節(jié)塞進(jìn)二維碼掃碼槍按 UTF-8 解出來自然亂碼。解決內(nèi)容入碼前強(qiáng)制轉(zhuǎn)成 UTF-8 字節(jié)序列。在 FastReport 里可以用內(nèi)置的StrToUTF8函數(shù)包一層表達(dá)式[StrToUTF8(訂單表.單號)]如果你的報表內(nèi)容是混合的中文URL我習(xí)慣在上游 SQL 里直接轉(zhuǎn)好再喂給報表MySQL 用CONVERT(字段 USING utf8)SQL Server 用CAST(字段 AS VARCHAR(MAX)) COLLATE Chinese_PRC_UTF8。數(shù)據(jù)和展示分離問題就在源頭消失了。5.3 報表預(yù)覽卡死窗口假死不動現(xiàn)象點擊預(yù)覽按鈕報表窗口彈出來但整個 IDE 卡住鼠標(biāo)轉(zhuǎn)圈要等很久或者直接結(jié)束進(jìn)程。原因FastReport 的預(yù)覽引擎在 D7 下有一個已知的交互陷阱——報表里包含大量細(xì)粒度對象比如幾百個文本框或網(wǎng)格線時預(yù)覽渲染會跟 IDE 的主線程搶占窗口消息導(dǎo)致 UI 線程被餓死。還有一個場景是報表里嵌入了圖片且圖片加載是同步的網(wǎng)絡(luò)路徑下的圖片會卡住整個預(yù)覽。解決第一個方案是在報表的BeforePrint事件里把不需要打印的對象刪掉或設(shè)Visible : False。第二個方案是不要把網(wǎng)絡(luò)圖片路徑直接喂給 Picture 屬性先下載到本地臨時文件再加載同步 IO 的等待時間會短很多。第三個方案是升級到 FastReport 5.3.13 的補(bǔ)丁版本它對預(yù)覽消息循環(huán)做了優(yōu)化卡頓概率大幅下降。如果你加載到 5.3.13 后仍然卡檢查是不是把frxExportPDF、frxExportHTML這些導(dǎo)出組件全部放在了同一個窗體上——導(dǎo)出組件初始化時會遍歷所有頁面對象組件多會讓啟動變慢。不用的導(dǎo)出組件別全堆在一個窗體里按需動態(tài)創(chuàng)建。5.4 二維碼打印出來精度低掃不動現(xiàn)象同一份報表在屏幕上掃碼沒問題打印到紙上掃碼失敗率高掃碼槍識別很吃力。原因打印機(jī)分辨率 203DPI 的情況下二維碼模塊尺寸小于 2 個打印點就糊。TfrxQRCode 的AutoCalcScale在屏幕上計算結(jié)果是基于屏幕 96DPI 的打印按 203DPI 換算后模塊物理尺寸縮水精度不夠。解決二維碼對象的AutoCalcScale設(shè) False固定ModuleSize : 4像素。同時把PdfLevel設(shè)為 2在 PDF 導(dǎo)出時強(qiáng)制用矢量渲染這樣印刷時二維碼是按矢量精度輸出不會點陣化模糊。另外確認(rèn)打印機(jī)的驅(qū)動設(shè)置里「縮放模式」選的是「實際大小」而不是「適應(yīng)紙張」否則二維碼會被整體等比例放大或縮小模塊尺寸跟著變。5.5 導(dǎo)出 Excel 時單元格是合并的現(xiàn)象交叉表導(dǎo)出到 Excel 后單元格行列錯位且大量單元格被合并沒法做二次數(shù)據(jù)處理。原因TfrxCrossView 在導(dǎo)出時默認(rèn)把頁面上顯示的合并邏輯也帶過去了。交叉表的行列標(biāo)題區(qū)域本來就會合并但多維度行級聯(lián)時合并范圍計算容易出偏差Excel 里就出現(xiàn)錯位。解決導(dǎo)出前把 TfrxCrossView 的MergeCells屬性設(shè)為 False。這個屬性控制是否合并相同值的單元格設(shè)為 False 后導(dǎo)出數(shù)據(jù)表格就是標(biāo)準(zhǔn)的矩形。代價是表頭重復(fù)值會重復(fù)顯示但數(shù)據(jù)處理角度反而是干凈的。如果客戶要求表頭也合并可以導(dǎo)出后再用 Excel 的「取消合并」批量處理一次FastReport 不背這個鍋。6. 進(jìn)階技巧運行時動態(tài)生成二維碼并聯(lián)動設(shè)計器預(yù)覽的完整閉環(huán)日常業(yè)務(wù)里二維碼內(nèi)容常常是運行時才確定的比如「用戶在界面上選一個訂單生成一個 PDF 附件里的二維碼」。這塊我把完整的運行時調(diào)用路徑串一遍你在自己的窗體代碼里照著改就能用。核心函數(shù)如下procedure TForm1.ReplaceQRCodeContent( Report: TfrxReport; const OldExpr, NewContent: string); var i, j: Integer; Page: TfrxPage; Obj: TfrxComponent; QRCodeObj: TfrxQRCode; begin // 遍歷每一頁和頁面上的每個對象找 TfrxQRCode for i : 0 to Report.Pages.Count - 1 do begin Page : TfrxPage(Report.Pages[i]); for j : 0 to Page.Objects.Count - 1 do begin Obj : Page.Objects[j]; if Obj is TfrxQRCode then begin QRCodeObj : TfrxQRCode(Obj); // 只替換指定的舊表達(dá)式避免誤改其他二維碼 if QRCodeObj.Expression OldExpr then QRCodeObj.Text : NewContent; end; end; end; end;這個函數(shù)的核心邏輯是「先定位再替換」通過報表對象模型遍歷出所有 TfrxQRCode然后匹配它的Expression屬性來確認(rèn)是不是我們要改的那個。注意替換用的是Text而不是Expression因為運行時我們已經(jīng)算好了最終內(nèi)容不需要再走表達(dá)式解析。這樣改完后源碼里二維碼內(nèi)容不會隨數(shù)據(jù)集變化適用于「固定值動態(tài)拼串」的場景。調(diào)用它時要注意報表狀態(tài)必須在PrepareReport之前替換否則二維碼已經(jīng)按舊內(nèi)容渲染完成了。我用這個函數(shù)做了個聯(lián)動效果——界面上一個按鈕觸發(fā)生成先替換內(nèi)容再PrepareReport最后直接導(dǎo)出 PDFprocedure TForm1.btnGenerateClick(Sender: TObject); var LReport: TfrxReport; LContent: string; begin LReport : TfrxReport.Create(nil); try LReport.LoadFromFile(OrderReport.fr3); LContent : BuildOrderQRCodeText(OrderIDEdit.Text, PlatformCombo.Text); ReplaceQRCodeContent(LReport, [ORDERS.QrContent], LContent); LReport.PrepareReport(True); LReport.Export(TfrxPDFExport.Create(nil)); // 實際使用時參考前文導(dǎo)出代碼 finally LReport.Free; end; end;實際項目里跑這段代碼時有一個驗證習(xí)慣我一直強(qiáng)制自己走一遍生成完 PDF 后把文件丟到微信「文件傳輸助手」里用手機(jī)掃描測試。微信的二維碼識別引擎對容錯和模塊精度的判定比其他掃碼槍嚴(yán)格能過微信的碼到絕大多數(shù)硬件設(shè)備上都能過。如果微信掃不出來優(yōu)先檢查ModuleSize是不是設(shè)了太小或者內(nèi)容是不是有 BOM 頭的隱藏字符。這套資源我拆到最后發(fā)現(xiàn)5.3.13 在 D7 下只要環(huán)境配對了日常開發(fā)效率完全不輸新版本。從那以后我每次接老項目升級需求都強(qiáng)制先花半天時間把 FastReport 的編譯環(huán)境跑綠再談業(yè)務(wù)改動。希望這些踩過的坑能幫你省下那半天。本文還有配套的精品資源點擊獲取