2019年8月14日 星期三

把報表元件丟進垃圾桶,省下錢跟你的生命 Part 1.


列印與Canvas

過去,在Delphi裡面要列印資料到印表機,大家都不知道到底該怎麼做才是對的作法,我也是這樣子過了20多年,從Delphi 7的時代使用FastReport,到後來改用Cristal Report/QuickReport大多數是因應客戶的要求而採用這些報表元件。
這些元件所費不貲,而且許多都在升級時要另外支付升級版費用,最讓人煩的是「每個元件的用法都不一樣、前一手程式人員八仙過海各顯神通的寫法都不一樣」,讓接手的我常常覺得乾脆翻掉重寫一次還比較快。
最近一年的專案更是如此,前幾手的程式人員把Quick Report用到我都認不得了,而且同一家公司的程式碼,不同專案就有不同的寫法,一個Quick Report各自表述。有的專案中,在 Report元件的Hint 裡面用他自己定義的符號來寫該元件對應哪個資料表、哪個欄位;有的專案中,直接把Report的所有資料從主表單當中一筆一筆塞資料,另一個專案則是在報表檔裡面去抓另一個表單的各個欄位來填資料。
OK的,我在學校最常跟同學們說的一個概念,就是「程式不會只有一種寫法,大家可以發揮創意,只要做出來的程式符合規格,都是對的」。
這個概念仍然是對的,我只想補充後續的概念「大家在正確性沒有問題的前提下,都該追求維護的簡便,以及追求更好的效能」。剛剛提到的這一年的客戶的程式,正確性沒有問題,但他們的系統幾乎沒有用到Delphi的物件導向概念,連Object Pascal的規範都很少遵循,居然還能出現在同一個專案中的不同unit檔案裡,宣告同名全域變數這種連學生都不該犯的大錯,這些程式的問題可謂罄竹難書啊⋯⋯
不說了,說了讓自己徒生氣,我們回到主題吧。
Delphi 的類別來操作印表機
要列印資料到印表機,在Turbo Pascal的時代,我們用的是AssignPRN,來連接到印表機,再以WriteWriteln把文字資料寫到印表機去。但這個做法在FireMonkey當中,印出來的文字會像蚊子一樣小,無法閱讀。
而要把圖片列印到的話,則必須透過Canvas的操作。以往對Canvas熟悉的程式人員並不多,能對Canvas操作熟悉的,應該都是已經在開發領域有過一定經驗(吃過一定苦頭)的資深人員了,我自己是在2005年開始,自己製作圖形元件與自訂Delphi程式佈景主題之後,才對Canvas有一點基礎的認識。
列印的時候,不管是哪一款印表機,都是透過Delphi封裝的TPrinter類別來處理的,而且都是使用全域變數Printer來操作,例如要開始列印作業,我們可以這麼寫:
Printer.BeginDoc
要結束列印作業,則寫為:
Printer.EndDoc
而在列印當中,要換頁面的話,則這麼寫:
Printer.NewPage
基礎的操作介紹告一段落了,我們來看細部操作吧,要把文字輸出到印表機上面,我們要透過:
Printer.Canvas.FillText(DestRect, 'Test', WordWrapTrue, 1.0, flags, TTextAlign.Leading, TTextAlign.Center);
DestRect : 要把圖片區塊輸出到印表機 Canvas 的位置與大小
WordWrapTrue: 超過寬度是否要自動換行?
1.0  -> 顯示的透明度
Flag->文字從左到右或從右到左, 建議直接給[]就好
TTextAlign.Leading => 水平對齊設定 (Leading靠左, Tail靠右, Center置中)
TTextAlign.Center => 垂直對齊設定 (Leading靠上, Tail靠下, Center置中)
而要把圖片輸出到印表機上面,則透過這個寫法來達成:
Printer.Canvas.DrawBitmap(要列印的圖片物件, SrcRect, DestRect,1.0, True);
圖片物件的型別是: FMX.Graphics.TBitmap
SrcRect: 要把圖片輸出的範圍區塊
DestRect: 要把圖片區塊輸出到印表機 Canvas 的位置與大小
1.0  => 透明度
True => 是否高速列印 (高速列印一般應該就是品質較差)
透過這些程式碼,就可以把圖片、文字印到印表機去了,如果需要選擇印表機,請使用DelphiTPrinterDialog讓使用者選擇要列印的印表機即可。
第一部分就先講基礎的操作,後面我們再來講複雜的報表要怎麼作吧。
有些夥伴可能會想問,在Windows 10上面想要用Print To PDF這個選項,又想自訂輸出檔名的話要怎麼辦? 讓我賣個關子,下一部一開始就會講這個。

沒有留言:

張貼留言