要求:
1、不是套打,表格線也需要輸出
2、每張報表打印8行記錄,不足的空白行也需要輸出
3、按憑證號打印單據,可以連續打印多張報表。
一、創建樣式:
在創建Form之前,需要創建多種段落和字體樣式,供Form中的文字使用。需要設置多種“段落格式”,並且必須在“表頭數據”中設定“標準段落”
1.創建段落格式,一般有RH(Report Header),PD(Page Header), PB(Page Bottom),LD(Line Header and Details),字體:CNSONG,9pt。注意最好在各段落的“首行縮”中設定1mm的縮進,否則,在Form中表格線和文字之間會沒有任何間隙。
2.設置“表頭數據”中“標準段落”
3、保存並激活樣式文件。
二、創建SmartForm
1、在“全局設置”-〉“表格屬性”-〉“輸出選項”中
設定“頁格式”:即紙張的大小
“樣式”:設定本Form使用的默認樣式文件,這裏指定爲第一步創建的樣式文件。
2、在“全局設置”-〉“表格接口”-〉“導入”
設置兩個參數:
ptr_header type c
ptr_items type c
這兩個參數用來傳入我們在Report中Export內表數據的句柄(ID key)。
3、在“全局設置”-〉“全局定義”中進行多項設定
a、“類型”設定,在這裏需要定義4個類型,一個用來保存表頭數據的工作區和內表,一個用來保存明細數據的工作區和內表,它們的結構必須與Report中Export到數據庫中的內表的結構完全對應一致,否則,我們將不能從傳入的句柄(ID key)中恢復內表數據。
TYPES:
BEGIN OF TYP_header_ROW ,
mblnr LIKE mseg-mblnr, " 憑證號
bldat LIKE rkpf-rsdat, " 憑證日期
c_so(16) TYPE c, " 銷售訂單號
c_issdt LIKE sy-datum, " 發貨日期
werks LIKE mseg-werks, " 地點
PLNAT_NAME LIKE t001w-name1, " 出貨單位名稱
kokrs LIKE mseg-kokrs, " 控制範圍
kostl LIKE mseg-kostl, " 成本中心
cc_name LIKE cskt-ktext, " 成本中心名稱名稱
c_depart(45) TYPE c, " 領料部門
bwart LIKE mseg-bwart, " 移動類型代碼
btext_mt LIKE t156t-btext, " 移動類型描述
c_btext_mt(60) TYPE c, " 移動類型次數
C_TOTAL(17) TYPE C, "合計輸出時由用戶手工填寫
END OF TYP_header_ROW .
TYPES: TYP_HEADER_TABLE TYPE TYP_HEADER_ROW OCCURS 0.
* 領料單明細信息
TYPES:
BEGIN OF TYP_ITEMS_ROW ,
mblnr LIKE mseg-mblnr, " 物料憑證編號 : 物料憑證
rsnum LIKE rkpf-rsnum, " 憑證號 : 預留單
mjahr LIKE mseg-mjahr, " 物料憑證年度
zeile LIKE mseg-zeile, " 序號
bwart LIKE mseg-bwart, " 移動類型代碼
werks LIKE mseg-werks, " 地點
kokrs LIKE mseg-kokrs, " 控制範圍
kostl LIKE mseg-kostl, " 成本中心
matnr LIKE mseg-matnr, " 物料號碼
maktx LIKE makt-maktx, " 物料描述
erfme LIKE mseg-erfme, " 計量單位
c_planc LIKE resb-bdmng, " 計劃數量(手工填寫)
c_outc LIKE mseg-erfmg, " 實發數量
c_count(6) TYPE c, " 件數(手工填寫)
lgort LIKE mseg-lgort, " 倉儲地點
charg LIKE mseg-charg, " 備註
END OF TYP_ITEMS_ROW.
TYPES: TYP_ITEMS_TABLE TYPE TYP_ITEMS_ROW OCCURS 0.
b、在“全局數據”中,定義全局的變量,我們需要定義如下幾個變量
wa_header type typ_header_row "表頭數據工作區,由於SmartForms中的內表不能有HeaderLine,因此必須定義一個與內表結構一樣的工作區
wa_items type typ_items_row "表單明細工作區
ig_items type typ_items_table "表單明細內表
wa_blanks type typ_items_row "空白行工作區
ig_blanks type typ_items_table "空白行內表
g_count type i "記錄一張報表的明細的記錄數量
G_CURRLINE type i "記錄所有報表共計打印了多少行,用於判斷最後一頁
G_TOTALLINES type i "記錄內表ig_items總行數,用於判斷最後一頁
G_CURRPAGE type i "一個憑證的當前頁碼
G_TOTALPAGE type i "一個憑證的總頁碼
c、在“初始化”中,將數據句柄中的內表恢復到剛設定的全局變量中
輸入參數:ptr_header,ptr_items,ig_header,ig_items,g_totallines
perform Restor_buffer using ptr_items changing ig_items.
DESCRIBE TABLE IG_ITEMS LINES G_TOTALLINES.
d、在Freecode"格式化程序"中,定義Form Restor_buffer函數
import t from database indx(hk) id typeid.
endform.
至此,我們已經得到了表頭和明細這2個內表的數據,下面準備畫報表並輸出數據。
4、在“頁和窗口”中,在“%Page1”頁下,添加3個窗口
"MAIN主窗口": 在SmartForm中,只有窗口類型爲“主窗口”的窗口,才能被循環。例如,在最前面的樣表中,明細數據有20條,不能在一頁中打印輸出完畢,需要輸出4頁才能打印完一張單據的數據,在這4張單據中,表頭和表尾是不變的,但是表中間部分數據卻是變化的,中間這個窗口需要被循環輸出4次。因此需要將這個窗口類型設定爲“主窗口”。在本例中爲現實明細數據的這部分。
“窗口1”:從表最上面到明細欄的標題欄(包括標題欄)
“窗口2”:最底下2行。
注意:窗口的寬度加上遍距不能大於紙張寬度。
創建好這三個窗口,設定好窗口的寬度,高度,以及位置信息。下圖是整個SmartForm的結構
注意,我將輸出表頭的窗口“%windows1 頁頭”放在了輸出明細數據的窗口“主窗口”的下面,這是必須的,因爲表頭中的數據需要從表頭內表ig_header中來。loop1是循環內表ig_header,將數據放到表頭工作區wa_header中。因此,%windows1 頁頭窗口就可以直接使用工作區wa_header中的數據。如果該窗口放在了主窗口的前面,那麼至少第一頁中表頭會沒有數據,而且後面每一頁的表頭顯示的都是下一個表頭的內容。
注:雖然打印機輸出時,現打印%WINDOWS1 頁頭,再打印MAIN主窗口,最後打印%WINDOW2頁尾窗口,但是程序執行時,卻是按照上圖中樹結構從上到下進行處理的,是先處理MAIN主窗口,其次%WINDOWS1 頁頭,最後%WINDOW2頁尾窗口的邏輯順序,可以從跟蹤SMARTFORMS程序得知。
下面詳細介紹整個邏輯流程和代碼:
1、%LOOP1表頭循環
設置:數據-〉loop循環-〉操作數:ig_header into wa_header
作用:循環表頭內表中的數據,每次打印一個憑證的行項目數據。由於內表在這裏不能有工作區,因此將每個表頭數據放置到另外的工作區。
2、%LOOP4計算單個憑證總頁碼
設置:數據-〉loop循環-〉操作數:IG_ITEMS INTO WA_ITEMS
WHERE條件:IBLNR = WA_HEADER-IBLNR
作用:由於在打印每張憑證及行項目之前,需要知道該憑證的總頁數,因此需要首先計算IG_ITEMS內表中有多少條當前憑證的行記錄數。
3、%CODE4累計單個憑證的行項目數
輸入參數:G_COUNT
代碼:
作用:累計當前憑證的行項目數。
4、%CODE1計算當前憑證總頁碼
輸入參數:G_TOTALPAGE,G_COUNT
代碼:
*計算單個憑證的總頁碼
G_TOTALPAGE = G_COUNT MOD 8.
IF G_TOTALPAGE = 0.
G_TOTALPAGE = G_COUNT DIV 8.
ELSE.
G_TOTALPAGE = G_COUNT DIV 8 + 1.
ENDIF.
G_COUNT = 0.
作用:根據第三步累計的單個憑證的總行項目數,以及每頁打印的行記錄數(8),計算該憑證需要打印的總頁數。計算完畢以後,G_COUNT重新置0。
6、%LOOP2循環輸出明細
設置:數據-〉loop循環-〉操作數:IG_ITEMS INTO WA_ITEMS
WHERE條件:IBLNR = WA_HEADER-IBLNR
作用:這裏的循環條件與第2步的條件完全一致,準備循環打印當前憑證的所有行項目。
7、%CODE2記錄行數加1
輸入參數:G_COUNT,G_CURRLINE
代碼:
G_COUNT = G_COUNT + 1.
G_CURRLINE = G_CURRLINE + 1.
作用:每循環一次,當前憑證打印的行記錄數加1,所有憑證打印的總行記錄數加1。
8、%TEMPLATE4數據明細
作用:模板,行記錄的表格,以及相關文本內容。LOOP2每循環一次,就打印輸出一行該模板以及文本內容。行高一般爲5mm(根據實際調整),注意模板的寬度不能超過窗口的寬度。在“細節”中可以調整模板的每個單元格的寬度,以及每行的高度。
9、%TEXT22 - %TEXT30文本內容
%TEXT22 序號:&G_COUNT(CZT4R)& 輸出選項-〉輸出結構:第1行第1列
%TEXT23物料號碼:&WA_ITEMS-MATNR& 輸出選項-〉輸出結構:第1行第2列
依此類推。
10、%CODE5計算當前頁碼
輸入參數:G_COUNT,G_CURRPAGE
代碼:
L_LINE = G_COUNT MOD 8.
IF L_LINE = 0.
G_CURRPAGE = G_COUNT / 8.
ELSE.
G_CURRPAGE = G_COUNT DIV 8 + 1.
ENDIF.
作用:每輸出一行,計算當前行所在的頁碼,即爲當前頁
11、%CODE3計算空行
輸入參數:G_COUNT,IG_BLANKS,WA_BLANKS
代碼:
* 需要的空記錄行數
IF G_COUNT <> 0.
G_COUNT = 8 - G_COUNT.
ENDIF.
CLEAR IG_BLANKS[].
DO G_COUNT TIMES.
APPEND wa_blanks to ig_blanks.
ENDDO.
G_COUNT = 0.
作用:在當前憑證的所有有效數據行打印完畢以後,還需要計算需要打印多少空行,才能剛好打印滿一張紙。用計算的數量,填充內表IG_BLANKS,計算完畢以後,G_COUNT必須清0。
12、%LOOP3 補充打印空行
設置:數據-〉loop循環-〉操作數:IG_BLANKSS INTO WA_BLANKS
WHERE條件:無
作用:循環內表IG_BLANKS,次數爲內表中的記錄數,即空行數,打印輸出空行。
13、%TEMPLATE5空數據明細
作用:該模板與第8步的TEMPLATE4完全一樣,只是該模板下不需要有文本TEXT,只序號輸出模板的表格線即可。
到此步驟,已經打印完畢了當前憑證的所有有效數據行和補充的空行,如果當前憑證需要打印多頁,例如有30條行記錄,需要打印3個滿頁,第4頁數出6行數據,補充2個空行,這3次分頁是系統自動分頁的,分也之前,自動處理頁頭和頁尾窗口,輸出這兩個窗口的內容。自動分頁的條件是“MAIN主窗口”的高度被打印滿了,因此一定要注意,主窗口的高度必須等於你需要的高度,不要多,也不要少,在本例中,高度爲8行 x 5mm = 40mm
14、%CONDITION1分頁
設置:一般屬性-〉節點條件:G_CURRLINE <> G_TOTALLINES
作用:在一個憑證打印完畢以後,將要進入打印下一個憑證之前,需要分頁,但是在打印完最後一個憑證的最後一頁以後,卻不能有分頁,否則最後會多一個空行。
15、%COMMAND1強制分頁
設置:一般屬性-〉轉到新頁:%PAGE1
作用:在G_CURRLINE <> G_TOTALLINES 條件成立(不是最後一行)的情況下,強制分頁。
你也許會說,這裏不強制分頁,系統也會自動分頁,因爲前面輸出的高度正好都滿足的各窗口的高度,會自動進行分頁,確實如此,系統會自動進行分頁,但是在這裏強調:強制分頁是必須的,不能使用自動分頁,原因是:自動分頁發生的時間不是我們預想的,我們需要在第13步執行完畢以後,馬上進行分頁,這時,WA_HEADER中的內容還是當前憑證的數據,這樣,在處理頁頭和頁尾窗口時,數據是正確的。而自動分頁卻不在此時發生,而是在第1步LOOP1循環再次執行以後,也就是WA_HEADER之中的內容變成下一條以後才發生,這樣我們就不能輸出正確的表頭和表尾數據,因此必須使用強制的分頁命令。
16、表頭和表尾窗口
由於這兩個窗口非常簡單,僅輸出文字描述和WA_HEADER中的內容,因此不詳細說明。
Q&A
1.打印預覽表格線都正常,但是用針式打印機輸出出現部分表格線無法輸出。
答:這個可能是由於針式打印機的分辨率較小的緣故,使用激光或者噴墨打印機可以正常輸出,或者在SmartForms中加粗表格線,使用30TW。
2.在使用穿孔紙連續打印時,後面的紙張出現錯位現象。
答:原因不是很清楚,需要設置打印機中的紙張格式,將紙張高度根據錯位的距離進行加或者減,多次調整以後可以達到沒有錯位。