【轉載】Smart Forms&ScriptFrom 詳解 BY 江正軍
Smart Forms
Smart Forms是在SAPScript的基礎上產生的一種新的表單製作方式,它完全相容SAPScript。但Smart Forms 更獨立,且使用起來更加方便,可以建立FORM的同時,生成該表單對應的功能塊(Function Module),從而為FORM和ABAP程式的互動提供引數介面
在中文環境下建立的Form,一般只在中文環境下開啟來編輯,在英文環境中中文文字節點可能顯示不出
事務碼:SMARTFORMS
Form:表單版式
Style:文字樣式
Text Module:文字模組
一個FORM往往是由頁面(PAGES
文字模組
Text Module:文字模組,主要用於設定一段固定的文字資訊,如報表頭名稱,或者是報表附加條款說明等資訊。
像下面這此使用:
節點元素
FORM中元素的輸出順序由Pages and Windows中的後繼節點結構和順序來決定,導航樹中的第一個頁節點是FORM處理的起始頁,該節點在FORM建立過程中被自動建立。
節點型別決定了節點可能的處理過程,如列印節點內容(文字、地址、圖片等)、執行節點中的語句或根據規則執行當前節點的後繼迴圈節點。
導航樹中的所有節點,按照從上到下的順序依次進行處理(包括“Pages and Windows”節點之間)
除開“Pages and Windows”外,其它所有節點都是可以加上執行條件屬性設定的,也就是說,只要滿足設定條件時,該節點及子節點才被處理
Page節點
每一個Form至少包含一個頁(Page)節點
Page節點為“Pages and Windows”的子節點,如果某個Page內容超出一頁,則會將其他內容輸出到Pages節點的Next Page屬性所指定頁面,即多出一頁的內容會產生分頁,一般Next Page分頁預設為自己,因為一般報表的主體內容會使用分頁,並且這些分頁排版相同,所以此種Page的Next Page不會設定成其他Page。如果報表需要有封面與封底,則需要另外新增Page這樣的節點元素
注:要注意的是,這裡的Page不是一頁的概念,它是指定頁面的一種統稱,具體輸出內容由它下面子節點元素來決定,且輸出內容可能會產生多頁
每Page頁面除了通過Next Pag靜態屬性來設定下一頁外,還可以在通過COMMAND節點的Go to New Page屬性來設定,當然,這種頁面跳轉是有條件的,所以COMMAND一般放在CONDITION條件節點裡使用:
視窗元素
頁面中的包含主視窗(Main Windows)和子視窗(Secondary Windows),其中,主視窗中的資料可以在多個列印頁面中可連續輸出,即可跨頁面(分頁顯示)。每個頁面(PAGE)中只能包含一個主視窗,但可以有多個子視窗(分頁情況下,子視窗應該在每頁上都會顯示,就是頁首頁尾一樣)。
一個FORM中只能定義一個主窗體;
不同PAGE上的主窗體必須寬度相同,但是高度可以不同;
一個沒有主窗體的PAGE指向的下一個頁面不能為它自己。
視窗中的模板的寬度與高度不要超過了視窗的高度與寬度,否則顯示不出
文字節點
一般使用文字節點在已經定義的視窗中新增各種型別的文字元素,唯一的例外是地址型別的文字元素也可以通過Address節點來新增。SAP Smart Form中含下列型別的文字:
①文字元素:使用Smart Form中的PC Editor在Form建立過程中編輯的新文字。
②文字模組:獨立於Smart Form,可以直接新增至Form,或參照文字模組生成Form文字元素。
③包含文字:已經插入設計好的SAPScript標準文字(在SO10中建立,可通過SE75查詢),體現了二者之間的相容性。
可以把一個文字節點直接新增到下列各種型別的節點下:
1、 主視窗(Main Window):文字可能在多頁中連續輸出
2、 子視窗(Secondary Window):將文字確切定義在指定頁中
3、 表格節點(Table):用於顯示錶格的內容
4、 模板節點(Template):把文字定義在靜態表格的單元格中
5、 標題(Header)和腳註(Footer):用於顯示錶格中總計資料等
6、 事件(Event)節點:用於顯示錶格的小計資料
有以下系統欄位可以直接引用
&SFSY-FORMPAGES&:返回Form中的總頁數,在一些報表中可能會出現總頁數為“*”號的問題,可以考慮使用引數壓縮輸出字串,例如:&SFSY-FORMPAGES(3CZ)&
&SFSY-PAGEBREAK&:觸發分頁後該欄位被賦值為 X
圖形節點SE78
圖開節點中的圖片可以直接使用伺服器上已有的圖片,或者通過事務程式碼SE78先將本地圖片上傳到SAP伺服器後再使用:
模板節點
模板節點比表格節點要靈活,模板單元格中可以儲存圖片節點,可以顯示圖片,而不是隻文字節點,另外,模板節點設定出的表格的行高是可以設定的,但表格節點是不能進行設定的。
所有單元格的總寬度一定要等於事個模板的寬度,否則編輯出錯
行定義中的“From”和“To”選項用於指定當前的設定應用於哪些行,行號的起始值為1,且行號不能出現間隔與重複。可以通過指定“Reference”的值將其他行的設定應用到當前行,指定引用號後,系統將自動拷貝該行的行高和列寬等設定到當前行
將文字等節點輸出到模板指定的單元格位置:
注意邊框線的寬度:預設為15TW。在實際工作中建議設定為20TW,用來適應針式印表機,鐳射印表機,噴墨印表機等。
地址節點
地址是經常出現在各種信函中的文字,在SAPScript中,它是文字元素的一部分。通過地址的好處是保證地址是根據發信人國家的書寫規範輸出,使用地址節點有一個前提條件,即該使用者必須具有SAP CAA的管理員許可權,否則只有通過文字節點進行地址新增
樣式
“表頭資料”是用來設定預設的字型及段落格式,其主要屬性包括如下內容:
建立新的“段落格式”與“字元格式”時,名稱最長不能超過兩位
SAP中的字型並非從當前作業系統的字型庫所取,除了一些預設的字型外,其他型別的主題還需要在SAP中額外安裝,通過SE73可以實現對欄位基本屬性的維護
通過“字元格式”還可以指定欄位樣式外,還可以定義成條形碼:
小技巧:檢視Form生成的函式
在設計好一個 smartform 後,系統會自動生成一個相對應的 function module , 我們在呼叫smartform時實際上就是呼叫這個對應的 function
如下我們可以找到對應的function: 點選選單環境->功能模組名
注意:程式呼叫Smart Form的時候,一定要用CALL FUNCTION ' SSF_FUNCTION_MODULE_NAME '先根據Smart Form名稱得到它的函式名稱fm_name。然後再 CALL FUNCTION fm_name呼叫Smart Form。因為Smart Form的fm_name可以重新分配,是個不固定值
SmartForm強制分頁(擡頭、專案表都顯示)
一、如果是模板,強制分頁命令要放在迴圈中;
二、如果是表格,強制分頁命令要放在表的主要區域迴圈中,而不能放在表頭部分。
強制分頁可以控制每頁固定顯示的資料條數
SmartForm設計:
*該SMARTFORMS使用了強制分佈技術,這樣確保了每頁只顯示有固定的行數,但單純的使用強制分佈只是解決了“接下頁(%TEXT12、)”正確顯示的問題,這樣就可以在SMARTFORMS裡對每小類(每條GT_HEAD)正確的進行小計,但強制分佈同時會帶來兩個問題:一是強制分頁會在在最末頁多出一個空白頁(經後其研究發現,最末多出空白頁,是由於原本在最後一頁資料輸出後,沒有對分頁命令進行控制,所以在最末而資料輸入後,再執行了一次分頁命令,而不是由於本身使用了強制分頁這項技術導致的這個問題);第二個問題是使用強制分頁後Head與Item不同步(錯行讀取問題)(經後其研究發現,該問題也不是由於本身使用了強制分頁引起的,根本的原因是由於表節點迴圈問題引起的,具體請參考這裡)。針對多出最後一個空白頁使用了有條件(在最後一條GT_HEAD資料讀取後不再執行分頁命令AGE_COMMAND,加上分頁條件:HEAD_INDEX
<= HEAD_COUNTS,HEAD_COUNTS為*GT_HEAD總條數)的強制分頁解決了該問題;針對頭Head與Iteam錯行讀取問題使用了程式手動控制頭的讀取操作,而不是使用原有系統自動遍歷方式。"分類小計
total_amount = total_amount + gw_item-amount.
*是否最後一行標示"如果不在%LOOP1裡強制分頁,則會有錯行問題:即在讀取到每一小分類最後一行(帶 X 的行)時,系統還是讀取下一行(也就是下一個小分類資料的第一行),但又不顯示在頁面上,這會造成每一個小分類資料小計不準確(所以如果需要在SMARTFORMS裡進行小計,則一定要實現強制分頁),既然要錯行讀取,所以先將gt_item-islastrow標示儲存到全域性變數lastrow中,供PAGE_COMMAND命令使用,這樣不管是否錯行讀取,最後一行標示都會被正確使用ifgw_item-islastrow = 'X'.
* lastrow = gw_item-islastrow .
endif.
"當使用強制分頁時,可以不用像上面那樣判斷 就可以給 lastrow 賦值,如果不使用"強制分頁,則需要像上面那樣賦值
lastrow = gw_item-islastrow .
if lastrow = 'X' .
"下一頁所需讀取的gt_head資料的索引號
head_index = head_index + 1.
endif.
"每頁資料的流水號
serial_number = serial_number + 1.
DATA mod TYPE i.
mod = serial_number mod 5.
if mod = 0 ."如果滿一頁時"當前頁碼加一
current_page = current_page + 1.
DISP_AUTO_PAGING_TXT = 'X'.
endif.
SmartForm原始碼:
主調程式:
REPORT yjzj_smartform_control_paging.
DATA: BEGIN OF gt_head OCCURS 10,
class TYPE string,"班級名
totalpages TYPE i,"每個小分類的總頁數
END OF gt_head.
DATA: BEGIN OF gt_item OCCURS 10,
class TYPE string,"班級名
student TYPE string,"學生名
amount TYPE i,"XX數量
islastrow,"標示是否為每一小分類的最後一行
END OF gt_item.
DATA: g_rows TYPE i,"記錄已讀取的行數
g_spacelines TYPE i,"不滿一頁時需要補充的空行行數
g_tabix LIKE sy-tabix,
flg .
START-OF-SELECTION.
PERFORM initdata.
LOOP AT gt_head.
CLEAR: g_rows,flg.
LOOP AT gt_item WHERE class = gt_head-class.
flg = 'x'.
g_tabix = sy-tabix."記錄最後一行的索引號,後面可能會需要修改這條資料
g_rows = g_rows + 1. "條數加1
IF g_rows = 5."滿一頁後計數雙從零開始"滿一頁數總頁數加一
gt_head-totalpages = gt_head-totalpages + 1.
CLEAR: g_rows.
ENDIF.
ENDLOOP.
IF g_rows <> 0 OR flg IS INITIAL."如果不滿一頁,或者無資料時
CLEAR: gt_item.
gt_item-class = gt_head-class.
g_spacelines = 5 - g_rows."需要補的空白行數
DO g_spacelines TIMES.
APPEND gt_item.
"SY-TABIX為上面APPEND語句操作後所影響的索引號
g_tabix = sy-tabix."記錄最後一行的索引號,後面可能會需要修改這條資料
ENDDO.
"滿一頁數總頁數加一
gt_head-totalpages = gt_head-totalpages + 1.
ENDIF.
gt_item-islastrow = 'X'."最後一行標示
MODIFY gt_item INDEX g_tabix TRANSPORTING islastrow.
MODIFY gt_head TRANSPORTING totalpages .
ENDLOOP.
PERFORM callsmartform.
FORM initdata.
DATA: times TYPE i,
classname TYPE string,
number TYPE i VALUE 1,
str TYPE string.
DO 5 TIMES.
str = sy-index.
CONDENSE str.
times = 4 + sy-index.
CONCATENATE str `班` INTO gt_head-class RESPECTING
BLANKS.
APPEND gt_head.
DO times TIMES.
gt_item-class = gt_head-class.
str = number.
CONCATENATE gt_head-class ` - 學生` str INTO gt_item-student.
number = number + 1.
gt_item-amount = sy-index.
APPEND gt_item.
ENDDO.
ENDDO.
gt_head-class = '6 班'.
APPEND gt_head.
ENDFORM. "initData
FORM callsmartform .
DATA: lf_fm_name TYPE rs38l_fnam.
"***********呼叫SMARTFORM程式生成函式
CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
EXPORTING
formname = 'YJZJ_SMARTFORM_CONTROL_PAGING'
IMPORTING
fm_name = lf_fm_name.
"***********動態呼叫新生成的函式
CALL FUNCTION lf_fm_name.
ENDFORM.
列印引數控制
DATA:lf_fm_name TYPE rs38l_fnam.
DATA:l_output_options TYPE ssfcompop.
DATA:l_control_parameters TYPE ssfctrlop.
DATA:l_job_output_options TYPE ssfcresop.
"********設定列印對話方塊中的引數
"列印對話方塊中的引數可以與l_output_options 結構中的相關欄位對應
l_output_options-tddest = 'LP01'."列印裝置
l_output_options-tdpageslct = '1,2,4'."列印哪幾頁,多頁使用逗號分隔
l_output_options-tdnoprev = 'X'."隱藏列印預覽按鈕
"********控制列印對話方塊顯示與否,及直接列印預覽方式輸出
l_control_parameters-no_dialog = 'X'."列印前不顯示列印設定對話方塊
l_control_parameters-preview = 'X'."而是直接顯示預覽結果
"***********呼叫SMARTFORM程式生成函式
CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
EXPORTING
formname = 'YJZJ_SMARTFORM_CONTROL_PAGING'
IMPORTING
fm_name = lf_fm_name.
"***********動態呼叫新生成的函式
CALL FUNCTION lf_fm_name
EXPORTING
output_options = l_output_options
control_parameters = l_control_parameters
IMPORTING "獲取列印對話方塊中使用者選擇、輸入、操作的結果:如判斷使用者在
"列印對話方塊中點選的是列印預覽還是點選的直接列印
job_output_options = l_job_output_options.
IF l_job_output_options-tdpreview = 'X'. "有些開發需求中需要控制報表的列印次數,可以通過該方法來統計操作結果,將列印記錄累加後存放於系統中,作為重複列印控制的依據。
WRITE :'列印預覽模式'.
ELSE.
WRITE:'直接列印模式'.
ENDIF.
一次性輸出多張報表
有時候可能需要一次性列印多張不同的報表,直接呼叫SmartForms時,每次列印一張後報表後,會在迴圈中反覆出現列印對話方塊,影響程式執行效率。SAP列印控制提供了假離線功能,允許將多張需要列印的報表快取,最的再一次性提交列印請求。
FORM callsmartform .
DATA:lf_fm_name TYPE rs38l_fnam.
DATA:l_control_parameters TYPE ssfctrlop.
DO 3 TIMES.
CASE sy-index .
WHEN 1.
l_control_parameters-no_open = space."首次執行時開啟列印對話方塊
l_control_parameters-no_close = 'X'."並且不關閉假離線請求
WHEN 2.
l_control_parameters-no_open = 'X'.
l_control_parameters-no_close = 'X'."
WHEN 3.
l_control_parameters-no_open = 'X'.
l_control_parameters-no_close = space."最後關閉假離線準備列印
ENDCASE.
"***********呼叫SMARTFORM程式生成函式
CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
EXPORTING
formname = 'YJZJ_SMARTFORM_CONTROL_PAGING'
IMPORTING
fm_name = lf_fm_name.
"***********動態呼叫新生成的函式
CALL FUNCTION lf_fm_name
EXPORTING
control_parameters = l_control_parameters.
ENDDO.
ENDFORM.
SmartForm轉PDF亂碼問題
如果將SmartForm輸出為PDF檔案時,可能會出現亂碼,則使用SPAD(假離線管理工具)設定列印裝置的裝置型別,設定為以CN開頭的裝置型別即可,然後在程式中使用這個LP01列印裝置
定義印表機紙張型別
關於列印紙張的定義,在國際上有很多通用的標準,如A5、A5等,這些通用的格式一般在Windows和SAP中都預設載入。但是,在實際應用中,經常會碰到一些不規範的紙張,對於這些非通用紙張,就需要使用者在系統中自己定義相關的紙張格式了。
1、 通過SPAD假離線管理工具中的“裝置型別->頁格式”可以自定義紙張,開啟“裝置型別”頁籤,在“頁格式”欄位中輸入自定義名稱,然後點選後面的“顯示”按鈕,顯示“頁面格式清單”頁面,再點選“編輯”即可建立新的紙張:
2、 上面定義的紙張,下面再定義“格式型別”,“頁格式”選擇上面定義的ZF_PAGE,“型別”選擇 S SAPscript的格式型別,這樣就可以在SmartForm中進行呼叫了,如果是ALV,則要選擇 L ABAP列表的格式型別:
定義好頁格式和格式型別的,則需要將頁格式(即紙張)分配到指定的裝置型別。SAP的假離線操作中是需要指定輸出裝置的,而每個輸出裝置需要設定裝置型別。所以當列印時,只有屬於該列印裝置的頁格式才能被操作。若沒有維護的話,預覽不會存在問題,但在選擇列印時,系統提示錯誤。
目前對中文輸出所使用的裝置型別大部分都預設為“CNSAPWIN”,在“裝置型別”中輸入“CNSAPWIN”,再點選“顯示”,出現以下介面:
輸入“格式化”名稱(注:這裡輸入的其實是上面建立的“格式型別”,而不是“頁格式(即紙張)”),確認後如下:
需要對印表機操作維護基本的指令,沒維護指令時,操作該型別的報表資料可能會出現印表機不切紙或者不執行列印問題。需維護的指令和印表機的驅動存在關係,可以參照CNSAPWIN下已經維護好的格式型別來維護。
以SAP標準的A4紙張(DINA4)為例,一般需要維護操作包括:列印初始化、尾頁、行結束,如:
最後就可以在SmartForm編輯器裡選擇上面自定義的“頁格式(紙張)”了:
Table節點迴圈問題
雖然表頭、主要區域、腳標三者都在 %TABLE1表裡,但是隻對主要區域節點進行迴圈,表頭、腳標在每一頁中只執行一次,所以,表頭節點裡實質上還沒有開始對GT_HEAD內表進行迴圈,所以在表頭節點裡是不能訪問到GW_HEAD工作區的資料的,因此,如果像下面那樣在表頭節點裡讀取到GT_HEAD中的資料,只能像這樣手動根據head_index(該變數會在主要區域節點的某程式碼片斷裡進行賦值處理,即在每一個小分類處理完後,head_index設定為下一小分類,即GT_HEAD下一條資料)來讀取了(其實還會在主要區域節點裡對GT_HEAD再讀取一次,這裡為了提前讀取到資料,所以只能在表頭裡手動讀取了)
ScriptForm轉PDF併發送郵件
(轉PDF應該還可以使用此函式:SX_OBJECT_CONVERT_OTF_PDF)
data: gt_otfdata like itcoo occurs 0 with header line.
以動態的方式獲取ScriptForm資料(沒有試過,可能獲取不到):
field-symbols: <fs> type any.
data: l_tab_otfdata(30) value '(SAPLSTXC)OTF[]'.
assign (l_tab_otfdata) to <fs>.
if sy-subrc = 0.
gt_otfdata[] = <fs>.
endif.
如果上面這種方式取不到Form表單資料,則可以在CLOSEForm時得到:
call function 'CLOSE_FORM'
importing
result = result
tables
otfdata = gt_otfdata
exceptions
others = 1.
CLOSE_FORM 的otfdata 作用:當呼叫PRINT_TEXT 或者 OPEN_FORM時,如果引數OPTIONS(結構型別為ITCPO)中的欄位TDGETOTF值為'X' 時,將會通過引數OTFDATA以OTF的格式輸出,在這種情況下,列印輸出、螢幕顯示、傳真將不會被執行。
itcpo-tdnoprint = ' '.No printing from print preview
itcpo-tdnoprev = 'X'.No print preview
itcpo-tdgetotf = 'X'.Return of OTF table. No printing, display, or faxing
下面開始將ScriptForm資料轉換成PDF格式的資料:
data: binfilesize type i.
data: i_tline type table of tline with header line,
* convert OTF to PDF
call function 'CONVERT_OTF'
exporting
format = '