列表屏幕(List Screen)
生成列表屏幕
在START-OF-SELECTION事件處理塊中,用WRITE語句向列表緩沖區(List Buffer)輸出要顯示的內容,當該事件結束的時候,所有在列表緩沖區中的內容將被顯示到一個基本列表屏幕(Basic List)上。
當用戶在基礎列表屏幕上雙擊一行或按功能鍵“F2”時,將會觸發ABAP事件AT LINE-SELECTION,如果還想進一步顯示該行數據的詳細信息,則可以繼續使用WRITE語句輸出要顯示的內容,這次生成另外一個詳細列表屏幕(Details List Screen)。此詳細列表屏幕將覆蓋其上一層的基礎列表屏幕,若在其界面的工具條上點“返回”或按功能鍵F3,將返回到基礎列表屏幕。
在詳細列表屏幕上,當用戶雙擊一行數據或按功能鍵F2,AT LINE-SELECTION事件將會再次觸發,因此還可以繼續生成下一級的詳細列表屏幕。因此,除了基礎列表屏幕外,所有的詳細列表屏幕的生成都是在AT LINE-SELECTION 事件塊中一起處理的,因此應該有一個機制區別開是哪一個詳細列表屏幕將被生成。
ABAP提供了全屏變量sy-lsind來區別屏幕的層次,sy-lsind的值主要用於在 AT LINE-SELECTION事件處理塊中進行程序流程控。0表示為基礎列表屏幕,1表示第一級詳細列表屏幕,依次類推,最多可以有20個詳細列表。如果是返回上一次,則sy-lsind會自動減一:
如果要在dialog program (module pool)生成屏幕列表,則可以通過LEAVE TO LIST-PROCESSING向屏幕發送列表。
此部分主要是通過WRITE語句來輸出簡單的列表,具體參考《ABAP BC Programming.docx》的Write語句用法
復雜LIST
標准LIST
report demo_list_standard.
tables spfli.
skip.
uline at /(62).
select * from spfli where connid ge 0017
and connid le 0400.
write: / sy-vline, spfli-connid, sy-vline,
(15) spfli-cityfrom, 26 sy-vline,
31 spfli-cityto, 51 sy-vline, 62 sy-vline,
/ sy-vline, 8 sy-vline,
spfli-deptime under spfli-cityfrom, 26 sy-vline,
spfli-arrtime under spfli-cityto, 51 sy-vline,
spfli-fltime, 62 sy-vline.
uline at /(62).
endselect.
write: /10 'SAP *** SAP *** SAP *** SAP *** SAP *** SAP',
/19(43) 'Flight Information System',
/19(43) 'International Connections'.
standard page header
至少包括二行standard header,第一行standard header包括了listheader和pagenumber,第二行standardheader是一條水平線。當程序是可執行報表程序時,listheader存儲在SY-TITLE中。如果有必要,可以給standardheader添加最多四行的column headers與一條水平線。在水平或垂直滾動時standardheader是不會動的。
自定義LIST
自定義Page Header
TOP-OF-PAGE.
WRITE: ....
在TOP-OF-PAGE事件里輸出的為自定義Page Header,會在每頁正文本輸出前輸出
另外,如果屏蔽掉standard header,使用下面語句壓制:
REPORT <rep> NO STANDARD PAGE HEADING.
對於每個TOP-OF-PAGE事件,對於basic list設置的標准屬性標題與列表頭中的占位符 &0 - &9 ,會自動使用系統變量SY-TVAR0到SY-TVAR9來替換他們,所以在TOP-OF-PAGE事件里對SY-TVAR0到SY-TVAR9進行設置即可
REPORT demo_list_page_heading NO STANDARD PAGE HEADING.
TOP-OF-PAGE.
WRITE: sy-title, 40 'Page', sy-pagno. ULINE.
WRITE: / 'SAP AG', 29 'Walldorf, ',sy-datum,
/ 'Neurottstr. 16', / '69190 Walldorf/Baden'.
ULINE.
START-OF-SELECTION.
DO 5 TIMES.
WRITE / sy-index.
ENDDO.
LINE-SIZE
輸出寬度由REPORT的LINE-SIZE來決定:
REPORT <rep> LINE-SIZE <width>.
如果<width>設置為0,則采用標准LIST的寬度來輸出。缺省的列表的行寬為83個字符
一行最多只能顯示255個字符,但大多數的打印機只能打印132個字符。當前頁面寬度存儲在SY-LINSZ系統變量中
REPORT demo_list_line_size LINE-SIZE 40.
WRITE: 'SY-LINSZ:', sy-linsz.
ULINE.
DO 20 TIMES.
WRITE sy-index.
ENDDO.
LINE-COUNT
限制每頁多少行
REPORT <rep> LINE-COUNT <length>[(<n>)].
如果指定了<n>參數,系統會保留<n>行給page footer。如果<length>設置為0,系統會使用標准頁面長度。缺省每頁的行數為6萬行。
頁面的實質可輸出正本行數為<length>減去page header length,再減去<n>。每面的行數包含了列表頭(headings)、列表內容與列表腳注行(footer lines)。
系統變量SY-LINCT會存儲頁面行數<length>,注意:如果REPORT語句沒有設置該值,則該系統變量值為0,除非使用 NEW-PAGE語句進行了設置。
SY-PAGNO系統變量存儲了當前頁碼。
"注意:一定要使用(1)預留一行,否則頁腳不會打印出來
REPORT demo_list_line_count NO STANDARD PAGE HEADING LINE-SIZE 40 LINE-COUNT 5(1).
WRITE: 'SY-LINCT:', sy-linct.
SKIP.
DO 6 TIMES.
WRITE / sy-index.
ENDDO.
TOP-OF-PAGE.
WRITE: / 'Page title', ` ` &
`Pag NO.:`,sy-pagno NO-GAP LEFT-JUSTIFIED.
ULINE.
END-OF-PAGE.
WRITE: / '*****Page footer*****'.
Page Footer
END-OF-PAGE.
WRITE: ....
觸發的條件是數據要滿一頁時才觸發,否則不會被觸發:
REPORT demo_list_end_of_page LINE-SIZE 40 LINE-COUNT 6(2)
NO STANDARD PAGE HEADING.
TOP-OF-PAGE.
WRITE: 'Page with Header and Footer'.
ULINE AT /(27).
END-OF-PAGE.
ULINE.
WRITE: /30 'Page', sy-pagno.
START-OF-SELECTION.
DO 5 TIMES.
WRITE / sy-index.
ENDDO.
強制分頁
無條件分頁使用NEW-PAGE
如果是想保留多少空行后再分頁,使用RESERVE
NEW-PAGE
該語句結束當前頁,所有的輸出會在新的頁面里顯示。
該語句不會觸發END-OF-PAGE事件(是否觸發則要看執行該語句前數據是否已剛好滿一頁):
REPORT demo_list_new_page LINE-SIZE 40 LINE-COUNT 7(1).
TOP-OF-PAGE.
WRITE: 'TOP-OF-PAGE', sy-pagno.
ULINE AT /(17).
END-OF-PAGE.
WRITE: '**page footer**'.
START-OF-SELECTION.
DO 2 TIMES.
WRITE / 'Loop:'.
DO 3 TIMES.
WRITE / sy-index.
ENDDO.
NEW-PAGE.
ENDDO.
RESERVE
RESERVE <n> LINES.
在調用此語句時,如果最后一次輸出到Page Footer之間所剩行小於(注意:等於時不會分頁)<n>時會進行分頁,在開始新頁之前會觸發END-OF-PAGE事件(如果最后一頁數據不足一頁,還是不會顯示頁腳)。注意:該語句僅只影響后面緊挨着的輸出語句,如果不滿足分頁條件,則后面的輸出也不會再受該語句的影響。
另外,RESERVE可以定義后繼的輸出作為一個行塊整體輸出,請參照這里
REPORT zdemo_list_reserve LINE-SIZE 40 LINE-COUNT 8(2).
END-OF-PAGE.
WRITE: / '---page footer---'.
WRITE: / '**page footer**'.
START-OF-SELECTION.
DO 4 TIMES.
WRITE / sy-index.
ENDDO.
DO 2 TIMES.
WRITE / sy-index.
ENDDO.
RESERVE 3 LINES.
WRITE: / 'LINE 1',
/ 'LINE 2'.
RESERVE 3 LINES.
WRITE:/ 'LINE 3'.
控制分頁是否使用標准page header
標准pageheader是由list header 與 column header組成的。在使用NEW-PAGE進行分頁時,可以通過下面選擇屏蔽或打開standard page header:
NEW-PAGE [NO-TITLE|WITH-TITLE] [NO-HEADING|WITH-HEADING].
WITH-TITLE or NO-TITLE:控制NEW-PAGE新開啟的頁面以及后面使用NEW-PAGE開啟的頁面是否使用標准的list header
NO-HEADING or WITH-HEADING:控制NEW-PAGE新開啟的頁面以及后面使用NEW-PAGE開啟的頁面是否使用標准的column header
即使在REPORT后面加上了NO STANDARDPAGE HEADING選項,你也可以單獨使用WITH-TITLE and WITH-HEADING來打開。
該選項只對標准的pageheader有作用,對TOP-OF-PAGE中輸出的不起作用。
REPORT demo_list_new_page_options LINE-SIZE 40.
WRITE: 'Page', sy-pagno.
NEW-PAGE NO-TITLE.
WRITE: 'Page', sy-pagno.
NEW-PAGE NO-HEADING.
WRITE: 'Page', sy-pagno.
NEW-PAGE WITH-TITLE.
WRITE: 'Page', sy-pagno.
NEW-PAGE WITH-HEADING.
WRITE: 'Page', sy-pagno.
控制分頁中每頁的行數
為了單獨控制分頁出頁面允許的數據行數,可以使用:
NEW-PAGE LINE-COUNT <length>.
該選項決定了隨后的所有(除非又重新通過該語句的這個選項重新指定了)使用NEW-PAGE語句分出的頁面的允許的最大數據行數。如果為0,則使用標准頁面的長度。pageheader與pagefooter都是要算行數的。另外,不能通過NEW-PAGE的選項控制footer的行數,這只能通過REPORT語句選項指定。
系統變量SY-LINCT會存儲頁面行數(即<length>)。
REPORT demo_list_new_page_line_c_1 LINE-SIZE 40 LINE-COUNT 0(1).
END-OF-PAGE.
ULINE.
START-OF-SELECTION.
NEW-PAGE LINE-COUNT 5.
DO 4 TIMES.
WRITE / sy-index.
ENDDO.
WRITE: / 'Next Loop:'.
NEW-PAGE LINE-COUNT 6.
DO 6 TIMES.
WRITE / sy-index.
ENDDO.
控制分頁的頁寬
NEW-PAGE LINE-SIZE <width>.
SY-SCOLS:存儲了當前窗口在沒有滾動條的情況下允許的最大字符數(或叫Column),而LINE-SIZE選項指的是列表本身最大允許的字符數,與窗口大小沒有關系(如果LIST列表的寬度LINE-SIZE大於了窗口允許的最大字符數SY-SCOLS,則會出現滾動條,否則窗口不會出現滾動條)
滾動列表
滾動成功后SY-SUBRC為0
SY-SROWS系統變量中存儲了當前窗體可以輸出的最大數據行數,包括Page Header
垂直滾動:by Window
SCROLL LIST FORWARD|BACKWARD [INDEX <idx>].
FORWARD:向下滾動一屏(窗口)
FORWARD:向上滾動一屏(窗口)
<idx>:移動哪一Level的List
REPORT demo_list_scroll_1 NO STANDARD PAGE HEADING LINE-SIZE 40.
TOP-OF-PAGE.
"SY-SROWS系統變量中存儲了當前窗體可以輸出的最大數據行數,包括Page Header
WRITE: 'Top of Page', sy-pagno, 'SY-SROWS:', sy-srows.
ULINE.
START-OF-SELECTION.
DO 100 TIMES.
WRITE / sy-index.
ENDDO.
"向下翻一屏
SCROLL LIST FORWARD.
垂直滾動:by Pages
SCROLL LIST TO FIRST PAGE | LAST PAGE | PAGE <pag> [INDEX <idx>] [LINE <lin>].
如果省略了INDEX選項,該語句是針對當前List操作的。
如果指定LINE選項,則會滾動到列表的第<lin>行(不包括pageheader lines),否則滾動至列表的首行。
另一種滾動方式:
SCROLL LIST FORWARD | BACKWARD <n> PAGES [INDEX <idx>].
REPORT demo_list_scroll_2 NO STANDARD PAGE HEADING LINE-SIZE 40 LINE-COUNT 8(2).
DATA: pag TYPE i VALUE 2, lin TYPE i VALUE 3.
TOP-OF-PAGE.
WRITE: 'Top of Page', sy-pagno.
ULINE.
END-OF-PAGE.
ULINE.
WRITE: 'End of Page', sy-pagno.
START-OF-SELECTION.
DO 3 TIMES.
DO 4 TIMES.
WRITE / sy-index.
ENDDO.
ENDDO.
"第2頁的第3行會顯示在窗體的第一行
SCROLL LIST TO PAGE pag LINE lin.
水平滾動:滾動到頁面最左或最右
SCROLL LIST LEFT | RIGHT [INDEX <idx>].
REPORT demo_list_scroll_3 NO STANDARD PAGE HEADING LINE-SIZE 200.
TOP-OF-PAGE.
WRITE: AT 161 'Top of Page', sy-pagno,
'SY-SCOLS:', sy-scols.
ULINE.
START-OF-SELECTION.
DO 200 TIMES.
WRITE sy-index.
ENDDO.
"水平滾動到最右邊
SCROLL LIST RIGHT.
水平滾動:by Columns
SCROLL LIST TO COLUMN <col> [INDEX <idx>].
該語句作用是將滾動條滾動到LIST列表中的第<col>列(而不是滾動到當前窗口中的多少列)
SCROLL LIST LEFT | RIGHT BY <n> PLACES [INDEX <idx>].
該語句作用是向左或向右相對滾動多少列(即多少個字符)。
SY-SCOLS:存儲了當前窗口在沒有滾動條的情況下允許的最大字符數(或叫Column),而LINE-SIZE選項指的是列表本身最大允許的字符數,與窗口大小沒有關系(如果LIST列表的寬度LINE-SIZE大於了窗口允許的最大字符數SY-SCOLS,則會出現滾動條,否則窗口不會出現滾動條)
REPORT demo_list_scroll_4 NO STANDARD PAGE HEADING LINE-SIZE 200.
TOP-OF-PAGE.
WRITE: AT 161 'Top of Page', sy-pagno,
'SY-SCOLS:', sy-scols.
ULINE.
START-OF-SELECTION.
DO 200 TIMES.
WRITE sy-index.
ENDDO.
"滾動到LIST列表中的第178的位置
SCROLL LIST TO COLUMN 178.
水平滾動控制
NEW-LINE NO-SCROLLING.
新起一行將不能水平滾動,但可以垂直滾動
NEW-LINE:相當於 Write: / ,表示換行,在Write之前調用了NEW-LINE時再沒有 / 選項的 Write: 語句時會先換行再輸出。
REPORT sapmztst NO STANDARD PAGE HEADING LINE-COUNT 3 LINE-SIZE 140.
START-OF-SELECTION.
DO 3 TIMES.
WRITE: / 'SY-INDEX:'.
DO 10 TIMES.
WRITE sy-index.
ENDDO.
ENDDO.
"換行新起一行,但新行不能水平滾動
NEW-LINE NO-SCROLLING.
ULINE AT 20(20).
NEW-LINE NO-SCROLLING.
WRITE AT 20 '| **** Fixed! **** |'.
NEW-LINE NO-SCROLLING.
ULINE AT 20(20).
DO 3 TIMES.
WRITE: / 'SY-INDEX:'.
DO 10 TIMES.
WRITE sy-index.
ENDDO.
ENDDO.
左邊指定列不可滾動
SET LEFT SCROLL-BOUNDARY [COLUMN <col>].
REPORT sapmztst NO STANDARD PAGE HEADING LINE-COUNT 3 LINE-SIZE 140.
END-OF-PAGE.
"如果每頁左邊固定列數相同,則可以寫在
"START-OF-PAGE 或 END-OF-PAGE 事件中
* SET LEFT SCROLL-BOUNDARY COLUMN 20.
START-OF-SELECTION.
DO 3 TIMES.
WRITE: /11 'SY-INDEX:'.
DO 10 TIMES.
WRITE sy-index.
ENDDO.
ENDDO.
"如果每一頁左邊固定的列數不一樣,則需要
"單獨為每頁進行設置,並且只能放在輸出下
"一頁的前面
SET LEFT SCROLL-BOUNDARY COLUMN 20.
DO 3 TIMES.
WRITE: / 'SY-INDEX:'.
DO 10 TIMES.
WRITE sy-index.
ENDDO.
ENDDO.
SET LEFT SCROLL-BOUNDARY COLUMN 10.
LIST布局
輸出位置
可以指定WRITE與ULINE語句在當前頁面的任何位置輸出,並且WRITE, SKIP, or ULINE在指定輸出位置時可能覆蓋現有已經的輸出。獲取當前輸出位置,可以通過下面兩個變量來獲得:
? SY-COLNO
? SY-LINNO (注:這個系統變量指的是下次Write輸出的行的位置,且是每頁都從1開始,而不像SY-LILLI那樣指整個列表屏幕中的決對行號)
ABAP提供了幾個關鍵字以絕對或相對來改變輸出位置
絕對定位
水平
ABP提供了兩種水平絕對定位方式:
第一種是WRITE與ULINE語句的AT 選項
第二種是使用POSITION語句:POSITION <col>.
<col>會存儲到SY-COLNO系統變量中
注意:對於每個WRITE語句輸出的內容只會在一行中顯示(顯示不下時會被截斷),不會換行顯示,至於換行是因為第二次使用WRITE語句輸出
垂直
SKIP TO LINE <lin>.
<lin>會存儲到SY-LINNO系統變量中,如果<lin>不在1到pagelength之間時,將忽略此語句,從上一次輸出位置后面繼續接着輸出。注意:這里所指的<lin>是指在一個分頁里的行號,而不是指定整個當前窗口,另外,<lin>包括每頁的Page Header與Page Footer行在內。
定位到Page Header下面的第一行的首列位置
BACK.
如果該語句不是放在RESERVE語句后面的行中使用時,后面的輸出將會顯示在Page Header下面開始顯示輸出。使用該語句后,系統變量SY-COLNO將設置為1,SY-LINNO將會設置為頁面的Page Header的下一行。如果與RESERVE語句一起使用時,請參考這里的使用規則
REPORT demo_list_position NO STANDARD PAGE HEADING LINE-SIZE 60 LINE-COUNT 4.
DATA: x(3) TYPE c, y(3) TYPE c.
x = sy-colno.
y = sy-linno.
TOP-OF-PAGE.
WRITE: 'Position of Header: ', x, y.
ULINE.
START-OF-SELECTION.
SKIP TO LINE 4.
POSITION 26.
x = sy-colno.
y = sy-linno.
WRITE: '* <- Position', x, y.
"超過了頁而大小,所以被忽略,下畫線從
"當前面的Page Header下面第一行開始畫
SKIP TO LINE 5.
ULINE AT 30(20).
BACK.
x = sy-colno.
y = sy-linno.
"在沒有使用上面BACK的情況下,該WRITE語句會換行后輸出,
"原因是上一次輸出畫線之后,線后面沒有足夠的空間來存儲
"該WRITE語句輸出的內容,如果線后有足夠空間輸出,則是
"會換行再輸出。但在這里由於上面的BACK語句,下面的輸出
"行的位置又回到了Page Header下的第一行開始輸出
WRITE: 'Position after BACK:', x, y.
相對定位
當使用WRITE時如果沒有使用定位選項,則其輸出位置是會相當於前一次輸出后繼位置,並且以空格分隔(在沒有加 NO-GAP選項的情況下),如果沒有足夠的空間,將會自動換行。
產生一個換行(NEW-LINE)
NEW-LINE.
SY-COLNO會被設置為1,SY-LINNO會在原來基礎上加1
定位到其他輸出的下面(WRITE …UNDER)
WRITE <f> UNDER <g>.
該語句對跨頁的<g>也有效
定位輸出到 the First Line of a Line Block
RESERVE.
.....
BACK.
如果BACK用在了RESERVE后面,則BACK后繼續的輸出會輸出到BACK與RESERVE之間的輸出行塊中的第一行。但要注意的是,RESERVE不能引起分頁,否則BACK還是會定位到Page Header的后面第一行位置上。
REPORT demo_list_position_relative_2
NO STANDARD PAGE HEADING LINE-SIZE 40 .
DATA x TYPE i.
WRITE 'Some numbers:' NO-GAP.
x = sy-colno.
ULINE AT /(x).
RESERVE 5 LINES.
DO 6 TIMES.
WRITE / sy-index.
ENDDO.
x = sy-colno.
BACK.
WRITE AT x ' <- Start of Loop'.
格式化輸出
使用WRITE、SKIP、ULINE輸出語句輸出的內容將被系統輸出傳遞到標准列表屏幕中。請參考《ABAP BC Programming.docx》
FORMAT語句
請參考《ABAP BC Programming.docx》
其他格式化輸出
上面章節講了FORMAT常用的選項,這節講一下比較特殊的選項,這些選項的格式輸出是根據特定中的數據來進行的,通常用戶會維護這些定制數據
Country-specific(國家) and User-specific(用戶)相關格式化
數字與日期字段的輸出格式是與用戶主數據相關的,用戶主數據可以使用SU3事務碼來維護(或者點擊相應菜單也可):
或者也可能通過事務碼SU01來維護:
雖然可以通過上面的設置來格式化數字與日期時間的格式化輸出,但你也可以在程序中使用下面語句來修改:
SET COUNTRY <c>.
<c>可以是國家代碼,也可以SPACE,這些國家代碼可以在T005X表中查找到
如果<c>不為SPACE,則系統會關閉掉用戶主數據的設定,而是去到T005X中查找與國家代碼<c>相對應的數據,如果在表中存在這樣的數據時,該語句執行后SY-SUBRC為0,並且后繼的所有WRITE語句都根據這個表中設定的數據來格式化輸出;如果該語句執行失敗則SY-SUBRC為4,並且后繼的WRITE語句輸出的數字的千分位以“,”顯示,小數點是“.”來顯示,日期顯示為 MM/DD/YY格式。
如果<c>設置為SPACE,系統不會讀T005X表,而是去使用用戶設置的主數據,在這種情況下SY-SUBRC總是0
REPORT demo_list_set_country LINE-SIZE 40.
DATA: num TYPE p DECIMALS 3 VALUE '123456.789'.
ULINE.
WRITE: / 'INITIAL:'.
WRITE: / num, sy-datum.
ULINE.
SET COUNTRY 'US'.
WRITE: / 'US, SY-SUBRC:', sy-subrc.
WRITE: / num, sy-datum.
ULINE.
SET COUNTRY 'GB'.
WRITE: / 'GB, SY-SUBRC:', sy-subrc.
WRITE: / num, sy-datum.
ULINE.
SET COUNTRY 'DE'.
WRITE: / 'DE, SY-SUBRC:', sy-subrc.
WRITE: / num, sy-datum.
ULINE.
SET COUNTRY 'XYZ'.
WRITE: / 'XYZ, SY-SUBRC:', sy-subrc.
WRITE: / num, sy-datum.
ULINE.
SET COUNTRY space.
WRITE: / 'SPACE, SY-SUBRC:', sy-subrc.
WRITE: / num, sy-datum.
ULINE.
Currency-specific(貨幣)格式化
WRITE <f> CURRENCY <c>.
輸出金額<f>時,會根據該語句設置的貨幣代碼<C>來決定其小數位置,如果貨幣代碼<c>在表TCURX(CURRKEY)中存在,則系統將根據TCURX-CURRDEC值來設置<f>的小數點的位置,否則將<f>轉換成具有2位小數的數字。這就意味着除非<f>本身就是類型為P(.2)(即貨幣的最大單位與最小單位換算為100時,如CNY人民幣、USD美元)的金額字段,否則需要在TCURX表中配置所對應幣種的小數位(因為不配置時會采用默認的2位)。
注意:這里的<f>一般是從數據庫里讀取出來的金額數據才需要這樣格式化輸出的,如果<f>本身存儲的就是真實的金額,則不需要格式再輸出,而是直接輸出;另外,這里的格式化只是簡單機械的根據TCURX表里所配置的小數位置來設置金額的小數點位置(而並不是乘以或除以某個轉換率),並與金額變量<f>類型本身的具有多少小數位有關:如果<f>的類型為P(6.5),值為<f> = 1.234時,且TCURX表里配置的小數位為2時,最后輸出的是 1234.00 ,而不是12.34(如果是根據轉換率來除,則結果會正確),因為在格式化前,會將小數末的0也參與處理,並不理會<f>本身原來的小位數,而是將所有的數字位(拋開小數點,但包括末尾的0)看作是待格式會的數字字符串:
DATA: p(6) TYPE p DECIMALS 5.
p = '1.234'.
WRITE: p CURRENCY 'aa'."1,234.00
TCURX:貨幣小數位置表
TCURC:貨幣代碼表
TCURR:匯率表
SAP表里存儲的並不是貨幣的最小單位,一般是以貨幣最大單位(也是常用計量單元)來存儲,不過在存儲之前會使用經過轉換:比如存儲的金額是 100,則存儲到表之前會除以一個轉換因子后再存入數據表中(該轉換因子是通過CURRENCY_CONVERTING_FACTOR函數獲得的,如比CNY的轉換因子為1,JPY為100),所以如果要取出來自己使用,則需要再次乘以每次以這個因子才能得到真正的金額數(不知道SAP為什么這么設計,或者是一個什么國際標准吧)。另外,數據庫中存儲的雖然不是最小單位,但取出來后都是放在P類型的變量中的,所以取出來在內存中統計是不會有精度丟失的(P類型相當於Java中的BigDecimal類類型)。
TCURX表中存儲的小數位實質上是根據同種幣種的最大單位與最小的換算率 = 10X 來計算的,式中的X即TCURX表中的小數位,如CNY中的最大單位元與最小單位分相差100倍,所以100 = 10X,X就為2,最后TCURX-CURRDEC存儲的就是2(但如果值為2是可以不需要在TCURX表中配置的,所以查不到CNY的配置數據,因為不配置時默認值也是2);另外,JPY日元沒有最小單位,所以最大單位與最小單位的換算率就是1,所以X就為0,所以TCURX-CURRDEC存儲的就是0。
數據庫中用來存儲金額的字段的類型都是P(.2),即帶兩位小數,因為轉換因子最大也就是100,有的是零點幾(在存入之前會將真實金額除以這個轉換因子后再存入),所以存儲類型為兩位小數的數字類型即可。用來存儲表中存儲的內部金額的變量類型一定要具有兩位類型的,否則在使用諸如CONVERT_TO_LOCAL_CURRENCY、CONVERT_TO_FOREIGN_CURRENCY轉換函數或者是格式化輸出時,都會有問題,所以在定義這些內部金額變量時,最好參照相應數據詞典類型。
從表中讀取日元並正確的格式化輸出
DATA: netpr LIKE vbap-netpr,"實際的類型為p(6.2)
waers LIKE vbap-waerk,
jpy_netpr TYPE i,
netpr1(6) TYPE p DECIMALS 3.
"通過SQL從數據庫查詢出來的是真實存儲在表里的數據,沒有經過其他轉換,日元
"存到數據庫中時縮小了100倍,所以要還原操作界面上輸入的日元金額,
"則需要使用后面的格式化輸出
SELECT SINGLE netpr waerk INTO (netpr,waers) FROM vbap WHERE waerk = 'JPY' AND vbeln = '0500001326'.
WRITE: waers,netpr."數據庫中的值,被縮小了100倍
"第一種還原方式
WRITE: / 'Format:', netpr CURRENCY waers.
"第二種轉換方式:也可以通過以下函數先獲取JPY貨幣代碼的轉換因子,再直乘以這個因子也可
DATA: isoc_factor TYPE p DECIMALS 3.
CALL FUNCTION 'CURRENCY_CONVERTING_FACTOR'
EXPORTING
currency = waers
IMPORTING
factor = isoc_factor.
jpy_netpr = netpr * isoc_factor."乘以100倍,因為在存入表中時縮小了100倍
WRITE: / 'Calc factor:', jpy_netpr.
"格式化輸出實質上是與存儲金額的變量本身的類型小數位有關:上面將從表中
"讀出的金額(小數兩位)賦值給變量netpr1(小數三位),格式化后會擴大
"10倍(因為多了一位小數位)。所以格式化正確輸出的前提是要用來接收從
"表中讀取的金額變量的類型要與數據表相應金額字段類型相同,否則格式化輸出會出錯
netpr1 = netpr.
WRITE: / netpr1, netpr1 CURRENCY waers."格式化的結果是錯誤的
SAP 貨幣轉換因子
一般而言,幣種的小數位為2,所以系統默認的位數也是2.但是有一些特殊幣種如日元JPY,沒有小數位,或者其他對於2位的小數位。只要小數位不等於2,需要在系統中特殊處理(通過轉換因子進行轉換,具體請參看后面SAP提供的函數 currency_converting_factor 實現過程)。在編程中
1、List中,當輸出CURR字段時,記得指定對應的貨幣:
如: WRITE: vbap-netwr CURRENCY vbap-waerk.
2、Screen中,對於CURR字段,需要設置對應的貨幣字段:
3、ALV中,需要對FIELD CATALOG進行設置.
如: ls_cfieldname = ‘WAERS’. "這里的WAERS是內表中的另一貨幣字段,里面存儲了相應金額的貨幣代碼。
貨幣的是:fieldcat-cfieldname、fieldcat-ctabname(內表名,可以不設置)
隨便數量也是相似的方法來處理的:
數量的是:fieldcat-qfieldname、fieldcat-qtabname(內表名,可以不設置)
下面是SAP轉換因子函數,在金額存儲與在ALV展示時都會自動除以與乘以這個轉換因子:
FUNCTION currency_converting_factor.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
* IMPORTING
*" VALUE(CURRENCY) LIKE TCURR-TCURR
*" EXPORTING
*" VALUE(FACTOR) TYPE ISOC_FACTOR
*" EXCEPTIONS
*" TOO_MANY_DECIMALS
*"----------------------------------------------------------------------
DATA: cur_factor TYPE isoc_factor.
*- determine Decimal place in currency from TCURX
CLEAR tcurx.
"首先根據幣種到db表tcurx中讀取相應的小數位數currdec
SELECT SINGLE * FROM tcurx WHERE currkey EQ currency.
"如果沒有維護相應幣別信息則默認currdec = 2
IF sy-subrc NE 0.
tcurx-currdec = 2.
ENDIF.
"如果currdec 大於了 5就報錯
IF tcurx-currdec GT 5.
*- entry in tcurx with more than 5 decimals not allowed
RAISE too_many_decimals.
ENDIF.
*- compute converting factor respecting currency
"然后默認轉換比率是100。如果表tcurx中的currdec = 0就默認轉換比率為100
cur_factor = 100.
IF tcurx-currdec NE 0.
"在currdec不等於0的情況下循環currdec次,每次將轉換比率除以10
DO tcurx-currdec TIMES.
"當表tcurx中沒有找到相應數據時則默認currdec = 2,轉換比率也就是100 / 10 / 10 = 1。其他
"的比如表tcurx中的currdec = 4,則轉換比率應該為 100 / 10 / 10 / 10 / 10 = 0.01
cur_factor = cur_factor / 10.
ENDDO.
ENDIF.
IF cur_factor = 0.
*- factor 0 not allowed; check data definition of factor
*- entry in tcurx with more than 5 decimals not allowed
RAISE too_many_decimals.
ENDIF.
factor = cur_factor.
ENDFUNCTION.
簡單的使用Function CURRENCY_CONVERTING_FACTOR,輸入幣別,就可以得到相應的轉換比率了。我們在SE16中看到的貨幣金額基本上都經過了這個轉換,如日元,都是除以100后存入數據庫的。所以當我們從數據庫中讀取日元金額時也應該作相應的轉換,乘以100 。
1、如果某貨幣的小數位不是2位,則需要通過OY04設置其小數位數,即需要在TCURX表中進行維護
2、系統中的數據表存放的日元JPY、俄盧布RUR等貨幣比前台輸入的金額小100倍,因為它們沒有小數位,所以轉換因子為100,存入表之前SAP會先將金額除以這個因子后再存入
3、系統根據轉換因子將原金額轉換成含小位小數的金額后存儲(據說根據ISO的什么標准),如日元為0位小數,轉換因子為100,120日元除以因子100后轉換后變成1.20,縮小100倍。如為USDN為5位小數,其轉換因子為100/10/10/10/10/10=0.001,12.01230除以0.001后則轉換成12012.30,擴大1000倍。SAP在金額數據存儲時會自動的轉換,其實SAP是有external及internal的數據格式,可以調用以以下函數實現相互轉換。BAPI_CURRENCY_CONV_TO_INTERNAL:轉換成跟數據庫中存儲一樣的格式數據,BAPI_CURRENCY_CONV_TO_INTERNAL’:轉換成外部實際金額
4、每次幣別的匯率更改在正式生產系統中新創建一條記錄,利用函數CONVERT_TO_LOCAL_CURRENCY自動會把當前最近的時間的匯率作為轉化的匯率,而不是直接在原紀錄上更改
5、OB07、OB08,維護各幣種之間的匯率。
6、 碰到比較變態的貨幣,例如日元,它們是沒有小數點的,系統內存儲的和你看到的不同,有個BAPI可以使用:BAPI_CURRENCY_CONV_TO_INTERNAL
7、 還有一個FM:CONVERT_TO_FOREIGN_CURRENCY,和CONVERT_TO_LOCAL_CURRENCY基本沒有區別,可以任選一個使用
貨幣內外格式轉換
"所有金額的在數據庫里(內部格式)都是帶兩位的小數數字類型
"用來存儲內部金額時,變量的類型一定要與數據庫表里的類型一致
",否則使用WRITE輸出時會不准確
DATA: usd(7) TYPE p DECIMALS 2,
jpy(7) TYPE p DECIMALS 2,
jpy_e(12) TYPE p DECIMALS 4.
DATA: usd_k TYPE waers, jpy_k TYPE waers.
DATA: ret TYPE bapireturn.
"此處為實際金額,所以不宜直接格式化(只有對內部表中存儲格式的金
"額格式化輸出才有意義,否則是錯誤的輸出),不過這里為實際的金額
"似乎也有點不對,因為日元真實金額是不會有小數的,所以變量jpy用來
"存儲外部實際金額是不妥的,jpy應該為整數類型才恰當
jpy = '10000.01'.
usd_k = 'USD'.
jpy_k = 'JPY'.
"使用CONVERT_TO_LOCAL_CURRENCY、CONVERT_TO_FOREIGN_CURRENCY
"函數時,涉及到的金額輸入輸出參數都是采用內部計算格式,所以在使用這
"些函數時,如果是外部金額,應先將它們轉換為內部金額后再傳入
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'"將一種貨幣兌換成另一種貨幣
EXPORTING
date = sy-datum
foreign_amount = jpy"該程序中的jpy本身為外部金額,但在這里會將
"它看作是內部金額,所以最后相當於外部金額1000001
foreign_currency = jpy_k
local_currency = usd_k
IMPORTING
local_amount = usd."轉換出來的也是內部格式的金額
*CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'
* EXPORTING
* date = sy-datum
* foreign_amount = '1.00'"內部金額,美元的外部金額也是1.00美元
* foreign_currency = 'USD'
* local_currency = 'JPY'
* IMPORTING
* local_amount = usd."結果為內部金額:1.15,相當於外部金額為115日元
*CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'
* EXPORTING
* date = sy-datum
* "如果內部金額沒有小數,也要補上兩位0,否則實質金額不准確,這里正是
* "因為末尾未被兩位0,所以這里的金額實質上為0.01美元,而不是1美元
* foreign_amount = '1'"內部金額,相當於外部0.01美元
* foreign_currency = 'USD'
* local_currency = 'JPY'
* IMPORTING
* local_amount = usd. "結果為:0.01內部金額,實質相當於外部金額1日元
WRITE: jpy, jpy_k,usd, usd_k.
"由於jpy本身為實際金額,所以不能在這里格式輸出;但usd為內部
"格式的金額,所以需要使用格式化輸出(但usd本身就是帶兩位小數
"的內部金額,轉換
WRITE:/ jpy CURRENCY jpy_k, jpy_k,
usd CURRENCY usd_k, usd_k.
ULINE.
jpy_e = jpy.
"將外部金額轉換為內部存儲金額,實質上過程是將外部金額
"除以轉換因子即可得到
CALL FUNCTION 'BAPI_CURRENCY_CONV_TO_INTERNAL'
EXPORTING
currency = jpy_k
amount_external = jpy_e"外部金額
max_number_of_digits = 23"沒什么作用,一般寫23即可
IMPORTING
amount_internal = jpy "轉換后的內部存儲金額
return = ret.
CALL FUNCTION 'CONVERT_TO_LOCAL_CURRENCY'
EXPORTING
date = sy-datum
foreign_amount = jpy "源貨幣金額(內部格式)
foreign_currency = jpy_k"源貨幣類型
local_currency = usd_k"目標貨幣類型
IMPORTING
local_amount = usd."目標貨幣金額(內部格式)
WRITE: jpy, jpy_k,usd, usd_k.
WRITE: / jpy CURRENCY jpy_k, jpy_k,
usd CURRENCY usd_k, usd_k.
Unit-specific(單位)格式
該語句根據Unit <u>的來設置<f>的小數位數。<u>必須要在T006中進行過配置,並且<u>的值就是T006-MSEHI字段值,T006-DECAN字段值決定<f>顯示的小數位數,如果<u>在表T006中沒有找到,將會忽略該UNIT選項。
? <f>必須是P類型的
? 如果<f>本身的小數位比<u>所配置的小數位小時,系統會忽略該選項
? 如果<f>本身的小數位比<u>所配置的要多時,並且多余的小數位全部是零時,會被截斷;如果多余的小數部分不是零時,會直接忽略該選項
注:該選項不像金額選項CURRENCY那樣,格式化后可能會改金額本身的大小(如果存儲金額的變量定義的類型中設定小數位與對應數據庫表字段類型中定義的小數位不同時會發生),但這里的格式化只是確定數量輸出時帶幾位小數而已。
DATA: num1 TYPE p DECIMALS 1 VALUE 1,
num2 TYPE p DECIMALS 4 VALUE '2.5'.
SET COUNTRY 'US'.
WRITE: 'N/A',num1 , num2,
/ 'KG', num1 UNIT 'KG', num2 UNIT 'KG',
/ 'PC', num1 UNIT 'PC', num2 UNIT 'PC',
/ '%', num1 UNIT '%', num2 UNIT '%'.
數量格式化輸出
問:通過se11 我們可以看到ekpo中menge的數據元素是BSTMG,BSTMG的域是長度13小數位3位。在程序中我參照ekpo-menge定義的變量顯示的時候后面都有3位小數,而我希望做好和me23n一樣,去掉小數點后面多余的零,請問大俠們有沒有比較好的辦法。為什么me23n中“PO數量”顯示的時候沒有多余的零,而他們的數據元素是一樣的。
答:MENGE實際上是個存儲度量衡值的字段,他的基本數據類型是QUAN,他的小數位數並不是你看到的3,而是由這個字段關聯的度量衡單位決定的,以MENGE為例,你可以在SE11的最右邊一個Tab頁,Currency/Quantity Fields里看到,他關聯的單位是EKPO-MEINS
DATA: i_menge LIKE ekpo-menge, i_meins LIKE ekpo-meins.
START-OF-SELECTION.
SELECT menge meins FROM ekpo INTO (i_menge, i_meins) WHERE ebeln = '4500000059'.
WRITE: i_menge , i_meins.
"格式化輸出后也ME23N顯示的格式是一樣的
WRITE: / i_menge UNIT i_meins, i_meins.
ENDSELECT.
不同單位之間的換算
PARAMETERS: p_in(10) TYPE c,
unit_in LIKE t006-msehi DEFAULT 'M',"米
unit_out LIKE t006-msehi DEFAULT 'MM',"毫米
round(1) TYPE c DEFAULT 'X'.
DATA: result TYPE p DECIMALS 3,
input TYPE p DECIMALS 3.
input = p_in.
CALL FUNCTION 'UNIT_CONVERSION_SIMPLE'
EXPORTING
input = input
round_sign = round"舍入方式(+ up, - down, X comm, SPACE.)
unit_in = unit_in
unit_out = unit_out
IMPORTING
output = result.
WRITE: 'Result: ',result.
交互式LIST
與屏幕一樣,你可以通過SET PF-STATUS設置STATUS。在normal screen中,用戶的動作可以觸發PAI事件,並且在screen flow logic中可以調用相應的ABAP dialog modules來處理是這個動作。但在list processing中,事件會被list processor攔截,並在以下三種LIST事件塊里進行處理(具體觸發哪一個事件塊,則與用戶的動作相關):
? AT PF<nn>(obsolete已過時的)
? AT LINE-SELECTION
? AT USER-COMMAND
在各事件塊中可以使用SY-UCOMM系統變量來捕獲用戶動作所對應的Function Code。在以上三種事件塊中的任何輸出,都會在事件塊結束后寫到新創建的detail lists中。在一個ABAP 程序中,你可以生成一個basic list與20個detail lists。
Detail Lists
如果輸出語句不是在列表事件塊(上面三種)里輸出時,都會輸出到basic list中,而在這三種事件塊里輸出的的內容都會輸出到Detail Lists中去。
系統變量SY-LSIND存儲了當前創建的list的索引,並且basic list的SY-LSIND為0。
在默認情況下,basic list具有standard list status和standard page header,並且basic list 在被創建時會觸發TOP-OF- PAGE與END-OF-PAGE事件。
在可執行報表程序中,basic list會自動地傳遞給list processor並在END-OF- SELECTION事件后顯示,否則,如果是在屏幕的PAI的ABAP dialog modules中顯示basic list,則需要使用LEAVE TO LIST-PROCESSING語句來將basic list發送給list processor處理器,並且在PAI事件塊執行完后才顯示basic list。
創建Detail Lists
SY-LSIND系統變量存儲了當前List的層級,Basic List的層級為0,后面創建出來的Detail List的層次會依據創建的先后順序自動的增加。凡事在AT PF<nn>、AT LINE-SELECTION、AT USER-COMMAND三個事件塊里輸出的內容,都會創建一個新的detail lists(每一個事件塊結束后都會創建一個新的detail list)。在ABAP程序中,你可以維護一個basic list與20個detail lists。在創建新的List時,會將前面的層級的List保存下來,並且用戶還可以選擇顯示哪層List。
默認情況下,list會完全覆蓋前層次的list,但時你可以使用dialog box的方式來顯示list。如果沒有在事件塊里為detail list設置dialog status,系統將會使用以前層次的status,但是,detail lists是沒有standard page header的。
START-OF-SELECTION.
WRITE: 'Basic List, SY-LSIND =', sy-lsind.
AT LINE-SELECTION.
WRITE: 'Detail List, SY-LSIND =', sy-lsind.
每次在雙擊行都會新創建一個Detail List:
Detail Lists不會顯示standard page header(如上面的Page Title),創建時也不會觸發TOP-OF-PAGE事件,但每個Detail Lists都會觸發TOP-OF-PAGE DURING LINE-SELECTION事件,而END-OF-PAGE事件Basic Lists與Detail Lists在滿頁時都會觸發。
Details Lists中的系統變量
Systemfield |
Information |
SY-LSIND |
Indexof thelistcreatedduringthecurrentevent(basiclist= 0) 當前事件所創建的列表層級(下一列表),默認值為SY-LISTI加一, 除非重新設置了SY-LISTI |
SY-LISTI |
Indexof thelistlevelfrom whichtheeventwastriggered 事件觸發所在列表層級(當前列表) |
SY-LILLI |
Absolutenumberof thelinefrom whichtheeventwastriggered 事件觸發所在列表行的絕對行號(指整個輸出列表的行號——所有分頁算起來,且如果是SKIP等輸出語句輸出的空行是計算在內的,如果是分頁之間的空行——嚴格的來講是空隙,是不算行號的 請注意:該變量與SY-LINNO是有區別的) |
SY-LISEL |
Contentsof thelinefrom whichtheeventwastriggered 觸發事件的行(即光標所在行)的內容(只要單擊某行,SY-LISEL的內容就是當前正被選中行的內容,即光標所在行的內容) |
SY-CUROW |
Positionof thelineinthewindowfrom whichtheeventwastriggered(countingstartswith1) 事件觸發所在窗體中的行號(這是相對於窗體來說的,指觸發事件的行在當前窗體中的行號,並且空行也算,注:每個窗體的行號只與窗口的大小有關,且窗口大小定以后,其能顯示的最大行數也就固定了) |
SY-CUCOL |
Positionof thecolumninthewindowfrom whichtheeventwastriggered(countingstartswith2) 事件觸發所在窗體中的行SY-CUROW中的列位置 |
SY-CPAGE |
Pagenumberof thefirstdisplayedpageof thelistfrom whichtheeventwas triggered 觸發事件的列表屏幕中所顯示的第一頁的頁號 |
SY-STARO |
Numberof thefirstlineof thefirstpagedisplayedof thelistfrom whichtheevent wastriggered(countingstartswith1).Thislinemaycontainthepageheader. 事件觸發所在列表中顯示出來的第一頁的第一行的行號 |
Numberof thefirstcolumndisplayedinthelistfrom whichtheeventwastriggered (countingstartswith1) 顯示在列表行中的第一列(除開已被隱藏的列)的列的列號: 該系統變量會隨着水平滾動條的滾動而變化。
|
|
SY-UCOMM |
Functioncodethattriggeredtheevent |
SY-PFKEY |
Statusof thelistcurrentlybeingdisplayed. |
Detail Lists中的消息
? A(=Abend):Termination結束,停止
.消息會顯示在彈出對話框中,且當用戶回車確認后,整個程序會結束
? E(=Error)orW(=Warning):
消息會顯示在狀態欄中。一旦用戶使用ENTER確認了這個錯誤消息,則當前的事件塊會終止並且顯示前一級別的list。如果是在創建basiclist時出現錯誤消息,則整個程序也會被終止掉
? I(=Information):
.消息會顯示在彈出對話框中。一旦用戶確認了消息(ENTER),程序會繼續處理MESSAGE語句后面的語句
? S(=status)
消息會在當前list狀態欄顯示
? X(=Exit)Runtimeerror:
該消息類型會觸發一個runtimeerror並且會產生一個shortdump
LIST屏幕導航
可以通過回退到上一級別的List。在以通過修改SY-LSIND來決定當前事件塊里的輸出內容將輸出到哪一級別層次的LIST屏幕上
注:返回時,不會根據程序的導航軌跡來回退,如程序導航軌跡為: 0 à 1 à 2 à 1 à 2 à 1 à 2,在最后一個2號LIST屏幕上點擊Back時,返回的軌跡為 2 à 1 à 0(只能回退兩次,而不是6次)
當使用sy-lsind重新定位輸出到哪個LIST屏幕上時,如果只是定位(當前事件塊中根本沒有任何的輸出時),則定位到的一下屏幕不會被重畫,而是原樣顯示歷史數據屏幕,但一旦有任何輸出,則屏幕則會被重畫。
START-OF-SELECTION.
WRITE: 'Basic List, SY-LSIND =', sy-lsind.
AT LINE-SELECTION.
WRITE: 'Detail List, SY-LSIND =', sy-lsind.
IF sy-lsind = 3.
"使用此事件塊中所有輸出都輸出到Basic List上
"此設置放在事件任何位置都不會影響最終輸出目的地,
"只是在這之前使用的sy-lsind的值沒有被更新而已
sy-lsind = 0.
ENDIF.
WRITE: 'Detail List, SY-LISTI =',sy-listi.
START-OF-SELECTION.
WRITE: 'Basic List, SY-LSIND =', sy-lsind.
AT LINE-SELECTION.
IF sy-lsind = 3.
sy-lsind = 0.
ELSE.
"當sy-lsind = 3時,這里的內容不會輸出到 Basic List上,
"此時會Basic List屏幕不會被重畫,還是顯示成最初的樣子
WRITE: 'Detail List, SY-LSIND =', sy-lsind.
WRITE: 'Detail List, SY-LISTI =',sy-listi.
ENDIF.
GUI Status for Lists
在LIST屏幕上對某行進行雙擊或按F2就會觸發相應的列表事件(AT PF<nn>、AT LINE-SELECTION、AT USER-COMMAND)。在Menu Painter中,double-click 動作與F2綁定了(F2就代表了雙擊,雙擊也即F2),如果在GUI status中將某個Function code分配給了F2鍵,當你雙擊時,就會觸發這個Function Code。
標准的 List Status(SET PF-STATUS space)及事件
你可以像普通屏幕那樣,給LIST設計GUI status,並通過SET PF-STATUS語句進行綁定(如果想為特定的層次的LIS設置GUI status,則需要使用SY-LSIND進行判斷)。
如果在報表程序(可執行程序)中沒有設置(Basic List與Detail List都未設置時)特定的GUI status,則系統會將list screen的Status設置為系統內置的default list status;在其他類型的程序中(如當你在Screen中創建一個list時),你可以明確的調用下面語句來設置成系統內置的default list status(該Status與報表程序默認的Status是一樣的):
SET PF-STATUS space.
該語句定義了Standard List所擁有的默認functions,
系統所提供的內置default list status如下(具體有以下這些Menu Bar與Standard toolbar,並且這些功能都已經被系統實現了,可以直接使用):
如果在程序中還定義了如下事件,則系統還會自動為LIST分配額外的functions:
鍵盤上的F<nn>(01 到 24)鍵不再具有系統預置功能,它們都將與function codes PF<nn>關聯,並且function codes PF<nn>與事件AT PF<nn>對應
REPORT demo_list_at_pf .
START-OF-SELECTION.
"PF5, PF6 這些Function code並沒有在Stauts中進行
"過任何定義(這里也沒有設置Status,使用的是Standard List Status)
"但按 F5, F6 這些鍵時會觸發相應的事件塊 AT PF<nn>
WRITE 'Basic List, Press PF5, PF6, PF7, or PF8'.
AT PF5.
PERFORM out.
AT PF6.
PERFORM out.
FORM out.
WRITE: 'Secondary List by PF-Key Selection',
/ 'SY-LSIND =', sy-lsind,
/ 'SY-UCOMM =', sy-ucomm.
ENDFORM.
當用戶在LIST屏幕上的某行上按F2或者鼠標雙擊時,就會觸發該事件塊,並且此時的function code默認名為PICK。注:Function code PICK觸發的前提是光標已經定位在了LIST列表中的某行上了。
REPORT demo_list_at_line_selection.
START-OF-SELECTION.
WRITE 'Basic List'.
AT LINE-SELECTION."選中某行后按F2或在某行上雙擊就會觸發
WRITE: 'Secondary List by Line-Selection',
/ 'SY-UCOMM =', sy-ucomm.
除上面PF<nn>與PICK兩個Function code以外,其他的function codes將被runtime environment攔截或者是觸發AT USER-COMMAND事件。
在LIST SCREEN中,那些觸發AT USER-COMMAND事件的Function codes(除了PF<nn>與PICK)都是自己在GUI statu中進行自定義過的;而能被runtime environment所攔截直接進行處理的,都是系統提供的standard function codes(具體是哪此Function code請參見Dialog Status for Lists中兩個表格中所提到的,但也除了PF<nn>與PICK)。
通過程序觸發事件
除了通過手動觸發LIST屏幕事件之外,還可以直接通過編程的方式來觸發:
?SET USER-COMMAND <fc>.
該語句會在當前列表事件塊里的所有輸出結束后生效(這意味着該語句放在輸出語句的前后都沒有關系),並在列表顯示之前觸發與<fc>對應的事件。其作用與用戶手動選擇了相應的Function Code是一樣的,換句話說,預置的列表function code將會被runtime environment捕獲與處理,function codes PICK與PF<nn>將會分別觸發AT LINE-SELECTION and AT PF<nn>事件,而用戶自定義的Function code將會觸發AT USER-COMMAND事件塊。
如果在創建LIST時使用好幾個SET USER-COMMAND這樣的語句,則只有最的一個語句會被執行。
示例:事件連鎖反應
REPORT DEMO_LIST_SET_USER_COMMAND NO STANDARD PAGE HEADING.
START-OF-SELECTION.
"當程序啟動后立即觸發 AT USER-COMMAND 事件
SET USER-COMMAND 'MYCO'.
"即使該輸入語句放在了上面語句后面,但該語句還是會輸出到Basic List屏幕上
"因為SET USER-COMMAND是在當前事件塊里輸出結束后才生效
WRITE 'Basic List'.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'MYCO'.
WRITE 'Secondary List from USER-COMMAND,'.
WRITE: 'SY-LSIND', sy-lsind.
"當程序觸發AT USER-COMMAND 事件后,又后立即觸發AT PF05事件
"相當於在下一Detail List屏幕上按了 F5 快捷鍵了
SET USER-COMMAND 'PF05'.
ENDCASE.
AT PF05.
"將光標定位到下一Detail LIST屏幕上的第一行。注:盡管這里將SET CURSOR LINE與SET USER-COMMAND
"語句寫在了后面兩個輸出語句的前面,最后的效果與將這兩個語句放在后面兩個輸出語句的后面
"效果是一樣的:結果都是定位到了下一Detail List屏幕上的第一行並按F2鍵
SET CURSOR LINE 1.
SET USER-COMMAND 'PICK'.
"當 AT PF05 事件觸發后會立即觸發AT LINE-SELECTION事件
WRITE 'Secondary List from PF05,'.
WRITE: 'SY-LSIND', sy-lsind.
AT LINE-SELECTION.
"當AT LINE-SELECTION事件觸發后,又會立即觸發 %SC 查找事件
SET USER-COMMAND '%SC'.
WRITE 'Secondary List from LINE-SELECTION,'.
WRITE: 'SY-LSIND', sy-lsind.
WRITE: / '-',sy-lisel NO-GAP.
最后顯示屏幕如下:
但前面的屏幕可以通過 BACK 回退時顯示
Status for Lists
可以通過Menu Painter為LIST創建dialog status,先創建普通類型的Status:
結果如下:
再選擇菜單ExtrasàAdjusttemplate,並在彈出框中選擇系統內置的“List status”Status Template來填充上面的Status:
結果如下:
上面通過內置“List status”Status模板(通過Status內在模板,這樣我們就不必一個個輸出設置了)填充的Function Code其實就是系統為List Screen提供的默認標准Status(標准的Status的具體樣子可以參照上一節內容中的截圖Standard List Status)
standard list status所提供的standard function codes分布在Menu、Standard toolbar、Function key三大Interface中,具體分如下:
Func Code |
所在的的 Menu |
所在的 Standard toolbar |
Function key |
Description |
%PC |
List |
|
|
Savelisttofile |
%SL |
List |
|
|
Savelist in SAPoffice |
%ST |
List |
|
|
Savelist inreporttree |
%PRI/ PRI |
List |
CTRL-P |
Printdisplayedlist |
|
%EX |
List |
|
Shift-F3 |
Exitprocessing |
PICK |
Edit |
|
F2 |
EventAT LINE-SELECTION |
RW |
Edit |
|
F12,ESC |
Cancelprocessing |
%SC |
Edit |
|
CTRL-F |
Find |
%SC+ |
Edit |
|
CTRL-G |
Findnext |
BACK |
Goto |
|
F3 |
Back onelevel |
P-- |
|
|
CTRL-PgUp |
Scrolltofirstwindowpage 注:這4個翻頁按鍵是對整個LIST Window起作用的,而不是針對程序軟分頁,它們的滾動是針對當前LIST所在Window,窗體高度不一樣,則滾動的長度不一樣 |
P- |
|
|
PgUp |
Scrollto previouswindowpage |
P+ |
|
|
PgDn |
Scrollto nextwindowpage |
P++ |
|
|
Ctrl-PgDn |
Scrollto lastwindowpage |
%CTX |
|
鼠標右擊 |
Shift-F10 |
Contextmenuonlist |
上表格Standard toolbar中的圖標所對應的按鍵是已經預置好了的(這些鍵不能再分配給其他Function Code了),具體如下:
另外,下面這些function codes也是系統內置的,它們並沒有在上面的Status中直接給我們進行了設置,但你可以自由的將這些Function Code在status 中定義它們來使用:
Func Code |
Description |
PF<nn> |
EventAT PF<nn> |
PP<n> |
Scrolltotopof listpage<n> |
PP-[<n>] |
Scrollback onelistpageor<n>pages |
PP+[<n>] |
Scrollforwardonelistpageor<n>pages |
PS<n> |
Scroll to column <n> |
PS-- |
Scroll to first column of the list |
PS-[<n>] |
Scroll left by one or <n> columns |
PS+[<n>] |
Scroll right by one or <n> columns |
PS++ |
Scroll to last column of the list |
PZ<n> |
Scroll to line <n> |
PL-[<n>] |
Scroll back to first line of the page or by <n>lines |
PL+[<n>] |
Scroll to last line of the page or by <n>lines |
/.... |
For other system commands |
除了PICK and PF<nn>這兩Function code以外,上面兩個表格中所列的Function code都將直接被runtime environment攔截下來進行處理,我們不需要捕捉這些Function Code,也不需要實現它們(因為這些Function Code根本不會觸發事件的,所以不能在AT USER-COMMAND中使用它們)。
只要光標在List Screen中的某行上,Function code PICK會觸發AT LINE-SELECTION事件;而function codes PF<nn>總是會觸發AT PF<nn>事件,所以不能在AT USER-COMMAND事件中使用(因為沒有觸發此事件)。
如果自己定義的Function Code名不是上面兩個表格中所預置的Function Code,則才會觸發AT USER-COMMAND 事件。
請注意下面功能鍵的分配:
? FunctionkeyF2:
雙擊相當於按功能鍵F2,所以分配給F2鍵的functionn code都將具有鼠標雙擊的功能。但要觸發AT LINE-SELECTION事件,則分配給F2的Function code只能是PICK,否同雙擊或按F2時,將會去觸發AT USER- COMMAND事件或者被runtime environment攔截處理。
? FunctionkeySHIFT-F10:
SHIFT-F10鍵相當於鼠標右擊,如果要彈出右鍵菜單,則需要將此鍵與名為%CTX的function code進行綁定。
你也可以修改上面Status圖中的由list-specific template模板所填充的默認Function code,以滿足其他需求:
? 使用自己定義的Function code名替換換掉PICK,這樣將不會再觸發AT LINE-SELECTION事件,你可以在AT USER-COMMAND中統一進行處理也可。
? 你可以刪除那些你不想要的功能Function code。例如,阻止打印與保存。
? 修改內置標准的Key(內置Key有哪此可以參看上面截圖中快捷鍵所示)所對應的Function Code。例如,你可以重新給F3分配自己的Function Code,而不是BACK,這樣按時就不會被runtime environment攔截處理,也就是說不會走系統提供的默認回退功能,我們可以在AT USER-COMMAND事件中重新來實現自己特殊的回退功能(比如在回退前彈出一個警告提示框等)
Setting Status
SET PF-STATUS <stat> [EXCLUDING <f>|<itab>] [OF PROGRAM <prog>] [IMMEDIATELY].
所有層次級別的后續List都會使用<stat>,除非重新使用語句進行了設置。系統變量SY-PFKEY存儲了當前LIST所使用的Status。
使用SET PF- STATUS SPACE語句可以設置成standard list status。
IMMEDIATELY選項是特定為list processing所設計的(即LIST Screen才具有,其他類型的屏幕沒有這個選項)。如果在創建detail list的事件塊里使用了該選項,則當前(index SY- LISTI)LISTScreen的Status也會被修改,並且當前事件塊所創建出的Detail List也會使用這個設置的Status(因為根本沒有為Detail List設置Status,所以使用前一LIST屏幕的Status);如果沒有使用該選項,將會在事件塊處理結束后修改當前后續(SY- LSIND) List屏幕的Status。
START-OF-SELECTION.
WRITE: 'SY-LSIND:', sy-lsind.
AT LINE-SELECTION.
SET PF-STATUS 'TEST' OF PROGRAM 'DEMO_LIST_SET_PF_STATUS_2' IMMEDIATELY.
上面實例程序中AT LINE-SELECTION.事件塊中沒有輸出內容,所以不會產生新的Detail List,所以SET PF-STATUS語句執行后,我們可以立刻看到Basic List的Status以修改了:
其他選項請參考SET PF-STATUS
REPORT demo_list_menu_painter.
START-OF-SELECTION.
SET PF-STATUS 'TEST'.
WRITE: 'Basic list, SY-LSIND =', sy-lsind.
AT LINE-SELECTION."按F2或雙擊行 或 點擊菜單 Edit-->Choose時觸發
WRITE: 'LINE-SELECTION, SY-LSIND =', sy-lsind.
AT USER-COMMAND.
CASE sy-ucomm."按F5或點擊工具條中的Test for demo按鍵時觸發
WHEN 'TEST'.
WRITE: 'TEST, SY-LSIND =', sy-lsind.
ENDCASE.
Setting a Title for a List
請參考SET TITLEBAR
右鍵菜單 for Lists
如果想為LIST屏幕設置右鍵菜單,先需要為Status分配Context Menu(分配后們可以在Menu Painter中看到快捷鍵Shift+F10分配一個Function Code名為%CTX,注:Function Code名一定要為%CTX,否則不會觸發右鍵菜單),然后再激活它,最后並使用SET PF-STATUS將這個分配並激活了右鍵的Status分配給LIST Screen,這樣才能使用右鍵。其分配與激活過程如下:
1、 在Dialog Status for Lists章節中創建的Status基礎上,分配右鍵Context Menu:
2、 再激活Function Code:%CTX
3、 在列表屏幕的行上右擊,則會觸發右鍵菜單並回調以下形式的Form:
FORM on_ctmenu_request USING l_menu TYPE REF TO cl_ctmenu.
在該Form中可以通過cl_ctmenu靜態的加載(加載靜態的右鍵菜單請參考Context Menus for Screen中的代碼示例)已設計好的Context Menu或動態的新增或刪除菜單項。
REPORT demo_list_context_menu.
DATA: wa_spfli TYPE spfli,
wa_sflight TYPE sflight.
START-OF-SELECTION.
"先為LIST屏幕設置Status,該設置的Status中就已經將
"右鍵Function code(%CTX)激活了,所以在列表行上右擊
"時就會觸發右鍵菜單
SET PF-STATUS 'BASIC'.
SELECT * FROM spfli INTO wa_spfli.
WRITE: / wa_spfli-carrid,
wa_spfli-connid,
wa_spfli-cityfrom,
wa_spfli-cityto.
"HIDE的使用:將List屏幕上的每一行中指定的列的內容存儲到當前層次級別的
"Hide area(即列表緩沖區,每行都會對應有一個這樣的緩沖區)
"中,使用該語句就是將列表行中指定的列的內容存儲到每一層次級別LIST所對應的
"專用的隱藏區域中
HIDE: wa_spfli-carrid, wa_spfli-connid.
ENDSELECT.
CLEAR wa_spfli.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'DETAIL'.
* CHECK NOT wa_spfli IS INITIAL.
"sy-lisel即選中列表行的內容
WRITE sy-lisel COLOR COL_HEADING.
SELECT * FROM sflight INTO wa_sflight
"wa_spfli-carrid與wa_spfli-connid都是從Hide area中讀取得到的
WHERE carrid = wa_spfli-carrid
AND connid = wa_spfli-connid.
WRITE / wa_sflight-fldate.
ENDSELECT.
CLEAR wa_spfli.
ENDCASE.
FORM on_ctmenu_request USING l_menu TYPE REF TO cl_ctmenu.
DATA lin TYPE i.
"獲取光標所在列表行的行號(列表號從1開計號)
GET CURSOR LINE lin.
"如果在是第3(或第3以后的)列表行右擊,並且列表層次是在第0層上時
IF lin > 2 AND sy-lsind = 0.
CALL METHOD l_menu->add_function
EXPORTING
fcode = 'DETAIL'"自定義Function code,需自己在AT USER-COMMAND中實現相關功能
text = text-001.
ENDIF.
CALL METHOD l_menu->add_function
EXPORTING
fcode = 'BACK'"BACK為系統提供的預置Function Code,它不會觸發AT USER-COMMAND
"已被runtime environment攔截被進行處理了
text = text-002.
ENDFORM.
以框模窗口顯示LIST
你可以WINDOW語句以對話框方式來顯示當前(indexSY-LSIND)的LIST,而不是全屏顯示(屏幕與選擇屏幕的對話框模式請參考Call屏幕、Call選擇屏幕):
WINDOW STARTING AT <left><upper> [ENDING AT <right><lower>].
<left><upper>分別指定了窗口最左上角所在的column 與 line。如果<upper>為0,將會全屏顯示。
<right><lower>分別指定了窗口最右下角所在的column 與 line。通常默認值為事件所發生的窗體的右小角所在的位置。
如果窗體指定的寬度小於了預置的列表LIST的寬度,則會出一水平滾動條。為了防止出現滾動條,可以使用下的語句來調LIST列表的輸出寬度:
NEW-PAGE LINE-SIZE<width>.
注:WINDOW語句只能用於detaillists,也就是說只能出現在上面Standard List Status及事件所提到的三種交互式事件里。
Dialog boxes(包括對話框模式的LIST、對話模式模式的屏幕與選擇屏幕)都是沒有menu bar與standard toolbar標准工具欄,並且application toolbar會顯示在LIST對話框的左下角下面,這是R/3系統的公共特點。
如果對話框模式的LIST屏幕沒有設置status,但在程序中定義了AT LINE-SELECTION 或者 AT PF<nn>事件處理塊,則系統會為dialog box使用standard list status 。
如果需要為dialog box類型的LIST定義一個Status,則在創建時需要在Menu Painter中選擇Dialog box類型的Status:
這種類型的Status系統不會為我們提供menu bar 與 standard toolbar,但在application toolbar中系統提供了預置的Function Code PRI, %SC, %SC+, and RW允許用戶打印、搜索、關閉窗口。
REPORT demo_list_window NO STANDARD PAGE HEADING.
START-OF-SELECTION.
"設置Basic List的Status
SET PF-STATUS 'BASIC'.
WRITE 'Select line for a demonstration of windows'.
AT USER-COMMAND.
CASE sy-ucomm.
"F2所默認對應PICK已被SELE替換,當按F2或在某行上雙擊或者點擊
"Select按鈕時觸發AT USER-COMMAND事件
WHEN 'SELE'.
IF sy-lsind = 1.
"設置第1個Detail List的Status
SET PF-STATUS 'DIALOG'.
SET TITLEBAR 'WI1'.
"以窗口形式顯示Detail List
WINDOW STARTING AT 5 3 ENDING AT 40 10.
WRITE 'Select line for a second window'.
ELSEIF sy-lsind = 2.
"設置第2個Detail List的Status
SET PF-STATUS 'DIALOG' EXCLUDING 'SELE'.
SET TITLEBAR 'WI2'.
WINDOW STARTING AT 45 10 ENDING AT 60 12.
WRITE 'Last window'.
ENDIF.
ENDCASE.
列表屏幕上的數據與程序間的傳遞
通過系統變量傳遞
列表交互事件觸發時會填充系統變量
REPORT demo_list_system_fields NO STANDARD PAGE HEADING
LINE-COUNT 12 LINE-SIZE 40.
DO 100 TIMES.
WRITE: / 'Loop Pass:', sy-index.
ENDDO.
"只有在創建Basic List時才觸發
TOP-OF-PAGE.
WRITE: 'Basic List, Page', sy-pagno.
ULINE.
"該事件只在創建Detail List時觸發
TOP-OF-PAGE DURING LINE-SELECTION.
WRITE 'Secondary List'.
ULINE.
AT LINE-SELECTION.
WRITE: 'SY-LSIND:', sy-lsind,"當前事件所創建的列表層級(下一列表)
/ 'SY-LISTI:', sy-listi,"事件觸發所在列表層級(當前列表)
/ 'SY-LILLI:', sy-lilli,"事件觸發所在列表行的絕對行號(指整個輸出列表的行號,不管是否有分頁,且空行不算)
/ 'SY-CUROW:', sy-curow,"事件觸發所在窗體中的行號(這是相對於窗體來說的,指觸發事件的行在當前窗體中的
"行號,並且格也算,注:每個窗體的行號只與窗口的大小有關,且窗口大小定以后,其能顯示的最大行數也就固定了)
/ 'SY-CUCOL:', sy-cucol,"事件觸發所在窗體中的行SY-CUROW中的列位置
/ 'SY-CPAGE:', sy-cpage,"事件觸發所在列表中顯示的第一頁的頁號
/ 'SY-STARO:', sy-staro,"事件觸發所在列表中顯示的第一頁的第一行的行號
/ 'SY-LISEL:',sy-lisel. "事件觸發所在列表行的內容
使用SY-LISEL
SY-LISEL類型為C(255),SY-LISEL存儲的內容最大只有255(好像一行最多也只能輸出255,請參考LINE-SIZE),所以每行輸出長度不應該超過這個數,並且它是將整行的內容都存儲下來了,所以要取得每個Field,則需要通過offset方式來截取。所以SY-LISEL只適合於取 List的Header行內容,以及檢測是否選中了行,
REPORT demo_list_sy_lisel NO STANDARD PAGE HEADING.
DATA num TYPE i.
SKIP.
"平方標題,在第4行輸出。當雙擊此行時,會求1到100各數的平方數
WRITE 'List of Quadratic Numbers between One and Hundred'.
SKIP.
"立方標題,在第6行輸出。當雙擊此行時,會求1到100各數的立方數
WRITE 'List of Cubic Numbers between One and Hundred'.
TOP-OF-PAGE.
WRITE 'Choose a line!'.
ULINE.
TOP-OF-PAGE DURING LINE-SELECTION.
"適合於將選中的行內容做為頭信息
WRITE sy-lisel.
ULINE.
AT LINE-SELECTION.
"如果選中行前四位字符串是 List 時
IF sy-lisel(4) = 'List'.
CASE sy-lilli.
WHEN 4."如果選中的是第4行時
DO 100 TIMES.
num = sy-index ** 2.
WRITE: / sy-index, num.
ENDDO.
WHEN 6."如果選中的是第6行時
DO 100 TIMES.
num = sy-index ** 3.
WRITE: / sy-index, num.
ENDDO.
ENDCASE.
ENDIF.
通過程序語句
當存儲的信息不是整行時,而是某些輸出列時,可以使用這些技術。
HIDE (列表隱藏域)
HIDE <f>.
變量<f>可以是整行或部分輸出列的變量,甚至是其他與行內容無關的變量。
當單擊(即光標所在的行)List屏幕中的行時,如果對應的行設置了隱藏字段,則HIDE隱藏字段變量<f>會自動被存儲值填充;當然也可以使用READ LINE來手動控制讀取填充。
注:局部變量不能存儲到HIDE區域中
示例請參考右鍵菜單 for Lists中的代碼示例
為了在AT LINE-SELECTION事件的處理塊中能夠訪問到用戶在上層列表屏幕上選中的行的主鍵,應該在上一級列表屏幕每一條記錄被顯示的時候將該記錄的主鍵保存到隱藏域中,這樣當用戶在上層屏幕上選中一行的時候,該行保存在隱藏域中的主鍵在AT LINE-SELECTION事件塊中將自動有效:
HIDE : wa_spfli-carrid,
wa_spfli-connid.
而且該保存語句要在本行數據被WRITE語句輸出到列表緩沖區后在后面緊着編寫(為了隱藏的數據與當前輸入的數據一致)。這樣當被雙擊時,保存在隱藏域中的字段的值將自動被傳回到原始字段中:
隱藏域是一個內表,其行結構包含了三個字段:被選中行的行號、字段名、字段值,當保存數據時,每個被保存的字段在隱藏域中形成一行。
DATA : wa_spfli TYPE spfli, wa_sflight TYPE sflight.
WRITE : AT 0(8) '航空公司',
AT 10(10) '航線編碼', AT 20(10) '出發城市' ,
AT 35(10) '到達城市', AT 50(10) '起飛時間'.
ULINE.
START-OF-SELECTION.
SELECT * FROM spfli
INTO CORRESPONDING FIELDS OF wa_spfli.
WRITE : / wa_spfli-carrid UNDER '航空公司', wa_spfli-connid UNDER '航線編碼',
wa_spfli-cityfrom UNDER '出發城市', wa_spfli-cityto UNDER '到達城市' ,
wa_spfli-deptime UNDER '起飛時間' .
HIDE : wa_spfli-carrid,
wa_spfli-connid.
ENDSELECT.
AT LINE-SELECTION.
CASE sy-lsind.
WHEN 1.
WRITE : '航空公司','航線編碼','航班日期',
AT 30(10) '最大座位', AT 45(10) '已定座位'.
ULINE.
SELECT SINGLE * FROM sflight
INTO CORRESPONDING FIELDS OF wa_sflight
WHERE carrid = wa_spfli-carrid AND connid = wa_spfli-connid.
WRITE : / wa_sflight-carrid UNDER '航空公司', wa_sflight-connid UNDER '航線編碼',
wa_sflight-fldate UNDER '航班日期',wa_sflight-seatsmax UNDER '最大座位',
wa_sflight-seatsocc UNDER '已定座位'.
WHEN 2.
WRITE : / 'currrent list leve is : ' , sy-lsind.
ENDCASE.
READ LINE
[FIELD VALUE <f1>[INTO <g1>]...<fn>[INTO <gn>]] [OF CURRENT PAGE|OF PAGE <p>].
該語句會將事件觸發所在的List((index SY-LILLI))中的第<lin>行的內容存儲到SY-LISEL系統變量中,並且隨之將<lin>行所對應的HIDE字段也進行相應填充。另外會將Write顯示輸出的名為<fn>字段的值存儲到<gn>全局變量中(如果加上了<gn>的前提下,否則會默認存儲到名為<fn>的變量中去)。如果讀取的行存在,則SY-SUBRC to 0, otherwise to 4
? INDEX<idx>
從<idx>級別的LIST屏幕上讀取行
? FIELD VALUE<f1>[INTO<g1>]... <fn>[INTO<gn>]
系統會將輸出字段<f1>的值以字符串的存儲到同名的變量中,或者當使用INTO時,存儲到<g1>變量中。在讀取與存儲的過程中會應用到相應的轉換規則。
行中使用HIDE語句輸出的字段不能使用該選項來顯示讀取(但在使用READ LINE語句會,HIDE字段會自動的被讀取填充)。如果某個字段多個顯示輸出,則系統只會讀取第一個。
此選項讀取出來的值是Write語句的格式化后的值,即會保留格式字符:
DATA: p(8) TYPE p DECIMALS 3 VALUE '123456.78',
c(8) VALUE '123'.
DATA: PC(16),CC(10).
START-OF-SELECTION.
WRITE:/ p , c RIGHT-JUSTIFIED.
END-OF-SELECTION.
CLEAR: p,c.
READ LINE 3 FIELD VALUE p INTO PC c INTO CC.
? OFCURRENTPAGE
此時的<lin>不是整個列表(包括所有分頁)中的行號,而是SY-CPAGE頁面中的行號
? OFPAGE<p>
此時的<lin>不是整個列表(包括所有分頁)中的行號,而是<p>頁面中的行號
TABLES: sflight.
DATA: box(1) TYPE c, lines TYPE i, free TYPE i.
DATA: linno TYPE sy-linno.
START-OF-SELECTION.
SET PF-STATUS 'CHECK'.
SELECT * FROM sflight UP TO 10 ROWS .
WRITE: / box AS CHECKBOX, sflight-fldate.
linno = sy-linno.
"linno是為了測試后面的READ LINE加上的輸出字段
HIDE: sflight-fldate, sflight-carrid, sflight-connid,
sflight-seatsmax, sflight-seatsocc,linno.
ENDSELECT.
END-OF-SELECTION.
"Basic List 輸出行數(包括Page Header在內兩行),sy-linno為當
"前輸出的行位置,當Write之后,為了下一個Write輸出,sy-linno會自
"動加1,所以屏幕上已輸出的實際行數需在sy-linno基礎上減1
lines = sy-linno - 1.
TOP-OF-PAGE.
WRITE: 'List of flight dates'.
ULINE.
TOP-OF-PAGE DURING LINE-SELECTION.
"sflight-fldate從Hide區域中讀取
WRITE: 'Date:', sflight-fldate.
ULINE.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'READ'.
box = space.
SET PF-STATUS 'CHECK' EXCLUDING 'READ'.
DO lines TIMES.
"該語句會將屏幕上的第sy-index行的數據讀取出來,並自動將整行的內容
"存儲到SY-LISEL中,同時也會自動去填充對應行的Hide字段(包括本行
"無關的字段,如這里的linno字段,即只要是存儲到了Hide區域的變量都
"會被自動的填充);並且在該語句中還會單獨讀取Write語句中顯示輸出的box字
"段的值並存儲到box全局變量中(可以通過調試觀察box全局變量的值的變化)
READ LINE sy-index FIELD VALUE box.
IF box = 'X'."如果選中后
"sflight-seatsmax、sflight-seatsocc從HIDE區域中讀取,它們的值是在
"前面的READ LINE之后自動填充
free = sflight-seatsmax - sflight-seatsocc.
IF free > 0.
NEW-PAGE."換頁輸出
"sflight-carrid、sflight-connid從HIDE區域中讀取,它們的值是在
"前面的READ LINE之后自動填充
WRITE: 'Company:', sflight-carrid,
'Connection: ',sflight-connid,
/ 'Number of free seats:', free.
ENDIF.
ENDIF.
ENDDO.
ENDCASE.
GET CURSOR FIELD、GET CURSOR LINE
GET CURSOR FIELD <f> [OFFSET <off>] [LINE <lin>] [VALUE <val>] [LENGTH <len>].
將光標所在字段名存儲到變量<f>中。如果光標在字段上,則SY-SUBRC to 0, otherwise to 4
輸出字段名可能是全局變量、常量、字段符號、或Form的引用參數,<f>存儲的名就是相應名稱(字段符號為所分配的變量名,而不是字段符號本身名)。對於字面常量、局部變量或Form的傳遞值方式的參數,系統會設置SY-SUBRC to 0,並且將<f>設置為SPACE
? OFFSET<off>
<off>存儲了光標所在字段里的位置。如果光標在字段的最前,則<off>=0
? LINE<lin>
存儲光標所在屏幕中位置行號(SY- LILLI)
? VALUE<val>
存儲光標所在字段的內容,包括輸出格式字符,取出的類型為字符類型,如果與<val>類型不兼容可能會發生類型轉換
? LENGTH<len>
存儲光標所在位置字段的輸出長度
GET CURSOR LINE <lin> [OFFSET <off>] [VALUE <val>] [LENGTH <len>].
將用戶選擇的行(光標所在行)的行號存儲到變量<lin>中。如果光標在列表行上,則SY-SUBRC to 0,否則為4
? OFFSET<off>
存儲光標所在行中的偏移量,如果在行首,則<off> = 0
? VALUE<val>
存儲光標所在行的內容,包括格式字符
? LENGTH<len>
存儲光標所在行的輸出長度
REPORT sapmztst NO STANDARD PAGE HEADING LINE-SIZE 40.
DATA: hotspotn(10) VALUE 'Click me!',
f(10), off TYPE i, lin TYPE i, val(40), len TYPE i.
FIELD-SYMBOLS <fs>.
ASSIGN hotspotn TO <fs>.
WRITE 'Demonstration of GET CURSOR statement'.
SKIP TO LINE 4.
POSITION 20.
WRITE <fs> HOTSPOT COLOR 5 INVERSE ON.
AT LINE-SELECTION.
WINDOW STARTING AT 5 6 ENDING AT 45 20.
GET CURSOR FIELD f OFFSET off LINE lin VALUE val LENGTH len.
WRITE: 'Result of GET CURSOR FIELD: '.
ULINE AT /(28).
WRITE: / 'Field: ', f,"字段符號所對應的名為所分配的變量名,而非字段符號本身
/ 'Offset:', off,
/ 'Line: ', lin,
/ 'Value: ', (10) val,
/ 'Length:', len.
SKIP.
GET CURSOR LINE lin OFFSET off VALUE val LENGTH len.
WRITE: 'Result of GET CURSOR LINE: '.
ULINE AT /(27).
WRITE: / 'Line: ', lin,
/ 'Offset:', off,
/ 'Value: ', val,
/ 'Length:', len.
DESCRIBE LIST獲取列表屬性
DESCRIBE LIST NUMBER OF LINES|PAGES <n> [INDEX <idx>].
計算指定層次列表屏幕上的總行數或總頁數,如果index <idx>的列表不存在,SY-SUBRC為非0
DESCRIBE LIST LINE <lin> PAGE <pag> [INDEX <idx>].
根據指定的<idx>與<lin>來確定指定行所在哪一頁,並將頁號存儲到<pag>中。如果index <idx>的列表不存在,SY-SUBRC為8,如果指定的行<lin>不存在,SY-SUBRC為4
DESCRIBE LIST PAGE <pag> [INDEX <idx>] [<options>]
取回<idx>級LIST屏幕中<pag>頁的屬性,具體取哪些屬性由<options>選項決定。如果index <idx>級的列表不存在,SY-SUBRC為8,如果指定的頁<pag>不存在,SY-SUBRC為4
<options>如下:
? LINE-SIZE<col>
將指定的頁面寬度存儲到<col>變量中
? LINE-COUNT<len>
將指定的頁面寬度允許的最大行數到<len>變量中,即程序開頭或者NEW-PAGE 所帶選項LINE-COUNT的值
? LINES<lin>
將指定的頁面中當前已輸出的行數存儲到<lin>變量中,所以<lin>只可能小於或等於上面的LINE-COUNT<len>
? FIRST-LINE<lin1>
將指定頁面的第一行(如果有Header,則指Header的第一行)所在絕對行號(SY-LILLI)存儲到<lin1>變量中
? TOP-LINES<top>
將指定頁面的header行數存儲到<top>變量中,包括standard page header與TOP-OF-PAGE里所輸出的總行數。
? TITLE-LINES<ttl>
將standard page header的行數存儲到<ttl>變量中,standard page header不包括TOP-OF-PAGE里輸出的頭所占行數,如果在程序開頭REPORT語句后加上NO STANDARD PAGE HEADING選項后,則<ttl>為0
? HEAD-LINES<head>
將standardpageheader部分中的columnheader行數存儲到<head>變量中(最多為5,其中包括了一條下划線)
? END-LINES<end>
將pagefooterlines行數存儲到<end>變量中
REPORT demo_list_describe_list LINE-SIZE 40 LINE-COUNT 11(1) .
DATA: lin TYPE i, pag TYPE i,
col TYPE i, len TYPE i, lin1 TYPE i,
top TYPE i, tit TYPE i, head TYPE i, end TYPE i.
DO 3 TIMES.
WRITE / sy-index.
ENDDO.
TOP-OF-PAGE.
WRITE 'Demonstration of DESCRIBE LIST statement'.
ULINE.
END-OF-PAGE.
ULINE.
AT LINE-SELECTION.
NEW-PAGE LINE-COUNT 0.
WINDOW STARTING AT 1 13 ENDING AT 40 25.
DESCRIBE LIST: NUMBER OF LINES lin INDEX 0,
NUMBER OF PAGES pag INDEX 0.
WRITE: 'Results of DESCRIBE LIST: '.
ULINE AT /(25).
WRITE: / '輸出的總行數: ', lin,
/ '輸出的總頁數: ', pag.
SKIP.
DESCRIBE LIST LINE sy-lilli PAGE pag INDEX 0.
WRITE: / '選擇的行絕對行號:',(2) sy-lilli NO-GAP, ',該行所在的頁號:',(1) pag NO-GAP.
SKIP.
DESCRIBE LIST PAGE pag INDEX 0 LINE-SIZE col
LINE-COUNT len
LINES lin
FIRST-LINE lin1
TOP-LINES top
TITLE-LINES tit
HEAD-LINES head
END-LINES end.
WRITE: '第' NO-GAP, (1) pag NO-GAP,'的頁面屬性如下:' NO-GAP,
/ '頁面行寬度: ', 25 col,
/ '頁面允許最大行數: ', 25 len,
/ '當前頁上已輸出的總行數: ', 25 lin,
/ '當前頁第一行的絕對行號: ', 25 lin1,
/ '頁面頭所占行數: ', 25 top,
/ '標准頭所占行數: ',25 tit,
/ 'column header行數:', 25 head,
/ '頁腳所占行數:',25 end.
操控 Detail Lists
Scrolling in Detail Lists
可以使用SCROLL語句來滾動列表,章節滾動列表描述了basic lists中如何滾動。
當你在detail lists使用SCROLL語句,需要注意以下幾點:
? 應該在所有輸出語句之后,再使用該語句
? 如果沒有指定INDEX選項,在創建下一個新secondarylist時,其滾動是針對當前事件觸發所在列表屏幕的(indexSY-LISTI),而不是新創建的下一LIST(SY-LSIND)
? 僅只有當創建basiclist時,SCROLL是針對當前正在創建的LIST
? 你可以使用INDEX選項明確的指定SCROLL作用於哪個LIST。在SCROLL之前是不需要先顯示的,可以先滾動,在顯示時會滾動條會自動定位到相應位置。如果指定的INDEX列表不存在,則SY-SUBRC為8
具體示例請參考滾動列表章節的示例
也可以使用通過程序觸發事件
設置光標位置
SETCURSOR語句只會地最近的已創建的列表(most recently-createdlist)起作用:當創建basiclist時,該語句是針對basiclist;對於正創建的detaillist,則針對以前list的(indexSY-LISTI)。
">SET CURSOR <col><lin>
SET CURSOR <col><lin>.
定位到輸出窗口中的<lin>行的<col>(窗口中顯示的第一列的<col>值為是1,即使水平滾動后也是這樣)列。系統只能將光標定准到窗體中可見的位置上,在顯示以外的區域,該語句不起作用。如果要定位目前沒有顯示出來的區域,則需要先SCROLL列表。
不能將光標定准到使用SKIP語句輸出的空行上,但輸出的下划線可以。如果<lin>超出來最大行,則會將光標定准到最后一行上面
注:<col>是基於當前窗口顯示列,而不是整個LIST Page,即已被隱藏的列不會被計算到<col>里,如下圖中使用SET CURSOR 11 3語句,使光標所在位置為第3行11列,即在第一個文本輸出框中:
當手動水平滾動到如下的位置后,再使用SET CURSOR 11 3.語句,還是會發生水平滾動,所以<col>是對於顯示出的列來算的,即窗口顯示第一列的<col>值永遠為1:
示例:
REPORT demo_list_set_cursor_1 NO STANDARD PAGE HEADING LINE-SIZE 80.
SET PF-STATUS 'SCROLLING'.
NEW-LINE NO-SCROLLING.
WRITE 'Input Fields:'.
NEW-LINE NO-SCROLLING.
WRITE '-------------'.
NEW-LINE.
DO 5 TIMES.
WRITE: ' Input', (1) sy-index, ' ' INPUT ON NO-GAP.
ENDDO.
SET CURSOR 11 3.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'LEFT'.
IF sy-staco > 1.
SCROLL LIST LEFT BY 12 PLACES.
ENDIF.
WHEN 'RGHT'.
IF sy-staco < 40.
SCROLL LIST RIGHT BY 12 PLACES.
ENDIF.
ENDCASE.
"再次向右滾動到11列前
SET CURSOR 11 3.
SET CURSOR FIELD
SET CURSOR FIELD <f> LINE <lin> [OFFSET <off>].
將光標定位到行<lin>中名為<f>的列上,如果有多個這樣的列,則定位到第一個字段上面。如果字段不存在或者字段不在顯示區,則忽略該語句,但可以先通過SCROLL語句將它滾動到顯示區再定位
使用OFFSET將光標定位到字段的<off>位置,<off> = 0表示字段的列(注:隱藏的部分也算)
注:<lin>是包括Header行在內在的
SET CURSOR LINE
SET CURSOR LINE <lin> [OFFSET <off>].
將光標定准到行<lin>。如果指定的行不存在或不在顯示區,則會忽略此語句,可以先通過SCROLL語句滾動到顯示區再定位
使用OFFSET選項會將光標定位到<lin>行中的<off>位置(<off>指整行的計數,隱藏的部分也算。<off> = 0表示行的第一列)
REPORT yjzj_list_set_cursor_3 LINE-SIZE 30 NO STANDARD PAGE HEADING.
DATA: inp(2) TYPE c, top(2) TYPE c.
SET PF-STATUS 'LINE_NUMBER'.
DO 50 TIMES.
WRITE: / 'Line ', (2) sy-index.
ENDDO.
TOP-OF-PAGE.
WRITE: 'Line number:', inp INPUT ON.
ULINE.
SKIP.
AT USER-COMMAND.
"header 的行數
DESCRIBE LIST PAGE 1 TOP-LINES top.
CASE sy-ucomm.
WHEN 'LINE'.
"文本框中輸入的要跳轉換的行號
READ LINE 1 FIELD VALUE inp.
"先滾動
SCROLL LIST TO PAGE 1 LINE inp.
inp = inp + top.
"再定位
SET CURSOR LINE inp OFFSET 6.
ENDCASE.
修改列表行(內容及輸出格式)
有以下兩種方式來修改LIST SCREEN中的行,
第一種是明確指定要修改的行:
MODIFY LINE <n> [INDEX <idx>|OF CURRENT PAGE|OF PAGE <p>] [<modifications>].
如果沒有 [INDEX <idx>|OF CURRENT PAGE|OF PAGE <p>] 選項,則修改的行為事件發生的當前LIST SCREEN(index SY-LISTI)中的<n>行,如果附加了此選項,則各選項的意思如下:
–INDEX <idx>選項指定了索引級別為<idx>中的第<n>
–OF CURRENT PAGE選項指定了當前顯示page (page number SY-CPAGE)中的第<n>行
–PAGE <p>選項指定了page <p>的line <n>
第二種是針對最近一次讀取到的行:
MODIFY CURRENT LINE [<modifications>].
該語句修改的是針對最近一次選擇(F2)的行或使用READLINE語句讀取到的行
如果沒有<modifications>選項,則上面兩個語句會直接使用系統變量SY- LISEL的內容來修改指定行的內容,並且行所對應的HIDE area也將被重寫。如果指定的行修改成功,則SY-SUBRC to 0,否則為非0
選項<modifications>可以為以下幾種:
修改行的格式
... LINE FORMAT <option1><option2>...
該選將修改整個行的輸出格式,其具體的格式請參着FORMAT語句
REPORT demo_list_modify_line_format LINE-SIZE 40
NO STANDARD PAGE HEADING.
DATA c TYPE i VALUE 1.
WRITE 'Select line to modify the background'.
AT LINE-SELECTION.
IF c = 8.
c = 0.
ENDIF.
MODIFY CURRENT LINE LINE FORMAT COLOR = c.
ADD 1 TO c.
修改字段的內容
... FIELD VALUE <f1>[FROM <g1>]<f2>[FROM <g2>]...
該語句的作用是先使用<f1>或者是<g1>變量的值來修改SY-LISEL系統變量中<f1>字段所在位置的值,然后再使用SY-LISEL系統變量的內容來進行整行內容的修改(這樣就確保了顯示的行與SY-LISEL內容一致)。如果有必要會在修改前會將值轉換為C類型。如果<f1>在行中多次出現,則僅修改第一個,如果不存在,則系統會忽略該選項
REPORT demo_list_modify_field_value LINE-SIZE 40
NO STANDARD PAGE HEADING.
DATA c TYPE i.
WRITE: ' Number of selections:', (2) c.
AT LINE-SELECTION.
ADD 1 TO c.
sy-lisel(1) = '*'.
"24的位置剛好是 c 變量輸出的位置,雖然這里進行了
"修改,但由於下面的MODIFY中的 FIELD VALUE選項給
"重新覆蓋了
sy-lisel+24(1) = '*'.
MODIFY CURRENT LINE FIELD VALUE c.
修改字段的格式
... FIELD FORMAT <f1><options1><f2><options2>...
該選將針對行中的某個字段的的輸出格式進行修改,其具體的格式請參着FORMAT語句
選項將覆蓋LINE FORMAT選項指定的相應字段的輸出格式。如果<f1>在行中多次出現,則僅修改第一個,如果不存在,則系統會忽略該選項
REPORT yjzj_list_modify_field_format NO STANDARD PAGE HEADING.
DATA: box(1) TYPE c, lines TYPE i, num(1) TYPE c.
SET PF-STATUS 'CHECK'.
DO 5 TIMES.
num = sy-index.
WRITE: / box AS CHECKBOX, 'Line', num.
HIDE: box, num.
ENDDO.
"屏幕上輸出的總行數
lines = sy-linno.
TOP-OF-PAGE.
WRITE 'Select some checkboxes'.
ULINE.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'READ'.
SET PF-STATUS 'CHECK' EXCLUDING 'READ'.
box = space.
DO lines TIMES.
"讀取屏幕上指定行中box字段的內容
READ LINE sy-index FIELD VALUE box.
IF box = 'X'.
WRITE: / 'Line', num, 'was selected'.
box = space.
MODIFY LINE sy-index
FIELD VALUE box
FIELD FORMAT box INPUT OFF
num COLOR 6 .
ENDIF.
ENDDO.
ENDCASE.
Lists 與 Screens之間的切換
當你運行一個可執行程序時,list processor(列表處理器)會在最后一個processing block(事件處理塊END-OF- SELECTION)結束時自動的運行,與此同時basic list將會被創建並顯示
如果你想在screen processing(屏幕處理)過程中顯示 lists,你必須對此進行編程控制,相反,你也可以編程從list processing(列表處理)切換到screen processing(屏幕處理)
從Screen Processing 屏幕處理切換到Lists列表輸出
CALL SCREEN屏幕調用或Tcode都會開啟screen sequence,系統會進行Screen processing。在Screen processing期間,ABAP program將會被dialog processor(對話處理器)接管控制,screen flow logic中調用的PBO 與 PAI modules將會被執行
為了將dialog processor控制權轉交給list processor,你可在PBO dialog modules 中調用下面這樣的語句:
LEAVE TO LIST-PROCESSING [AND RETURN TO SCREEN<nnnn>].
該語句可以使用在PBO 或者PAI event中。它的作用是在當前屏幕的PAI processing(一般在PBO塊里使用SUPPRESSDIALOG.或LEAVESCREEN.語句后不會顯示這個屏幕,此時在PBO事件塊結束后立即顯示Basic List)結束后開始list processor並顯示Basic List。調用該語句所在屏幕的PBO and PAI modules中的list output(列表輸出)都會被輸出到Basic List中緩存起來,待該屏幕處理完后(如果沒有使用SUPPRESSDIALOG.或LEAVE SCREEN.語句,則在PAI結束后顯示;如果使用了這兩個語句,則會在PBO塊結束后就會顯示)。如果在ABAP Program事件塊AT LINE-SELECTION,AT USER-COMMAND中輸出了內容,將會產生更多層次的detail lists
可以使用以下兩種方式來離開list processing:
? 在basiclist中點擊Back,Exit,orCancel
? 在list processing程序中使用:LEAVE LIST-PROCESSING.
以上兩種方式都會使控制權從list processor轉交到dialog processor。
在默認的情況下,不帶AND RETURN TO SCREEN選項的LEAVE TO LIST-PROCESSING語句在當list processor 處理結束后(如關閉list列表輸出窗體時),dialog processor將會又會返回到LEAVE TO LIST-PROCESSING語句調用所在屏幕的PBO事件塊,並重新執行PBO事件塊(所以這樣使用會出現死循環:關不掉List列表輸出窗口);選項AND RETURN TO SCREEN允許你指定當前屏幕序列(即LEAVE TO LIST-PROCESSING語句調用所在屏幕所在的屏幕序列)中的某個屏幕,當list processor 處理結束后,dialog processor將會回到指定的屏幕並執行其相應的PBO事件塊;另外可以通過下面語句:
LEAVE TO LIST-PROCESSING AND RETURN TO SCREEN 0.
來實現當結束List列表輸出窗口時,結束當前屏幕序列(即LEAVE TO LIST-PROCESSING語句調用所在屏幕所在的屏幕序列),並返回到該屏幕序列啟動(調用)的地方(如果是該屏幕序列是在屏幕的PAI事件塊里的某個MODULE里開啟的,則返回到PAI事件塊里的相應MODULE調用語句處,並繼續后面的PAI事件塊語句的執行;如果該屏幕序列是在ABAPProgram中開啟的,則會回到 ABAP程序中call screen語句處,繼續執行后面程序):
如果你想在screen processing屏幕處理中顯示 lists 列表輸出屏幕時(即從Screen 切換到 List 屏幕輸出時),你需要為這個將要輸出的Basic List 屏幕設計一個單獨的空的Screen,並在這個空的屏幕(不需要PAI事件塊)的PBO事件塊中某個module里創建(使用上面語句LEAVE TO LIST-PROCESSING來創建)與顯示Basic List,這個空屏幕可以使用CALL SCREEN語句在任何想調用的地方進行調用即可。
實際上,如果在PBO MODULE里沒有使用 SUPPRESS DIALOG. 或 LEAVE SCREEN. 語句時,調用LEAVE TO LIST-PROCESSING語句的屏幕還是會顯示出來,這時我們只需要在該屏幕上觸發一下Function code即可(回車、雙擊都可)切換到由該屏幕PBO MODULE生成的Basic List,並顯示Basic List。
只要切換到了List輸出屏幕,則可以對List屏幕進行相關事件的編程
從屏幕生成的Basic List的SY-DYNNR還是為當前屏幕的屏幕號,不過所有的Detail List的屏幕號都為 120
REPORT demo_leave_to_list_processing.
TABLES demo_conn.
DATA: wa_spfli TYPE spfli,
flightdate TYPE sflight-fldate.
CALL SCREEN 100.
MODULE status_0100 OUTPUT.
SET PF-STATUS 'SCREEN_100'.
ENDMODULE. "status_0100 OUTPUT
MODULE cancel INPUT.
LEAVE PROGRAM.
ENDMODULE. "cancel INPUT
MODULE user_command_0100.
CALL SCREEN 500.
"如果這里不設置為100,就會結束整個程序,因為當前100屏幕的
"Next屏幕默認為0,所以如果不重新指定下一屏幕,則會結束屏幕
"序列,而該程序沒有選擇屏幕,所以最后會導致結束整個屏幕
"這里設置的100的意思是:當前屏幕(100)的下一屏幕還是100,
"當PAI事件塊結束后,會又去調用100屏幕的PBO事件
"當前也可以注掉此名,而像下面那樣將LEAVE TO LIST-PROCESSING
"語句的返回屏幕設置為 100 也可
SET SCREEN 100.
ENDMODULE. "user_command_0100
MODULE call_list_500 OUTPUT.
"意思是:當生成Basic List結束之后,返回到100屏幕並觸發其PBO事件
* LEAVE TO LIST-PROCESSING AND RETURN TO SCREEN 100.
LEAVE TO LIST-PROCESSING AND RETURN TO SCREEN 0.
SET PF-STATUS space.
SUPPRESS DIALOG.
SELECT carrid connid cityfrom cityto
FROM spfli
INTO CORRESPONDING FIELDS OF wa_spfli
WHERE carrid = demo_conn-carrid.
WRITE: / wa_spfli-carrid, wa_spfli-connid,
wa_spfli-cityfrom, wa_spfli-cityto.
HIDE: wa_spfli-carrid, wa_spfli-connid.
ENDSELECT.
CLEAR: wa_spfli-carrid.
ENDMODULE. "call_list_500 OUTPUT
TOP-OF-PAGE.
WRITE text-001 COLOR COL_HEADING.
ULINE.
TOP-OF-PAGE DURING LINE-SELECTION.
WRITE sy-lisel COLOR COL_HEADING.
ULINE.
AT LINE-SELECTION.
CHECK NOT wa_spfli-carrid IS INITIAL.
SELECT fldate
FROM sflight
INTO flightdate
WHERE carrid = wa_spfli-carrid AND
connid = wa_spfli-connid.
WRITE / flightdate.
ENDSELECT.
CLEAR: wa_spfli-carrid.
從List Processing 中調用SCREEN
從list processing處理過程中調用Screen:
CALL SCREEN <nnnn>.
該語句會將生成一個screen sequence,並將它穿插到list processing處理過程中,list processor會將控制權交給dialog processor,並且直到dialog processor處理screen sequence中的Screen 0才會結束dialog processor,並再次將控制權從dialog processor轉交到list processing,繼續執行CALL SCREEN后面的語句
示例請參考:demo_call_screen_from_list
LIST 打印輸出
在默認情況下,系統會將list(basic list and secondary lists)輸出到screen。該章節將討論將lists發送到SAP spool system來代替output screen。
一般來講,我們將list發送到SAP spool system叫 'printing lists'(打印列表),也就是說,不需要真正的將list輸出到打印機上,而是使用spool system臨時存儲。
ABAP提供了兩種打印list方式:標准打印與編程控制打印輸出。
在使用系統提供的標准打印時,有時不能立即輸出打印內容,可以像下面這樣來設置立即打印與默認打印設備:
使用系統提供的標准打印
使用標准打印會出現以下幾個問題:
? 如果list屏幕輸出中,某邏輯頁行數超過了實際打印輸出的頁大小時,會將這一邏輯頁分成多(具體多個與打印輸出設備有關)個物理頁面,系統會將每個物理頁面的pageheader設置成該邏輯頁的pageheader,這時如果page header含有頁號(SY-PAGNO)是時,就會有問題:頁號不會自動更新
REPORT XXX NO STANDARD PAGE HEADING LINE-SIZE 60 .
TOP-OF-PAGE.
WRITE: sy-title, 20 'SY-LINSZ:', sy-linsz, 40 'Page', sy-pagno.
ULINE.
START-OF-SELECTION.
DO 64 TIMES.
WRITE / sy-index.
ENDDO.
? 如果REPORT或者NEW-PAGE語句中使用了LINE-COUNT,且指定的頁面大小超過了實際輸出設置的頁面大小時,超出的部分不會打印出來(這與未設置LINE-COUNT時超出部分會打印到下一個物理頁面是不一樣的):
REPORT XXX NO STANDARD PAGE HEADING LINE-SIZE 60 LINE-COUNT 166(2) .
TOP-OF-PAGE.
WRITE: sy-title, 20 'SY-LINSZ:', sy-linsz, 40 'Page', sy-pagno.
ULINE.
END-OF-PAGE.
ULINE.
WRITE: /30 'Page', sy-pagno.
START-OF-SELECTION.
DO 163 TIMES.
WRITE / sy-index.
ENDDO.
打印時,會彈出警告框:
? 如果REPORT語句中設置的行LINE-SIZE大於打印設備的最大行寬時,超出的部分是不會打印出來的
? 使用標准的打印時,不能寫printcontrol語句來控制打印輸出
通過編程來控制打印輸出
在程序中向打印輸出設置輸出時,系統會根據打印輸出設備來格式化List,系統會根據打印輸出設備的格式來確定頁寬與頁長,物理頁滿后會自動換頁。
在選擇屏幕上點擊“執行與打印”
SET_PRINT_PARAMETERS函數的各輸入參數與彈出的打印輸出設置對話框中的參數相對應,打印輸出設置對話框中的參數都可以在該函數中進行設置:
REPORT sapmztst NO STANDARD PAGE HEADING LINE-COUNT 0(2).
PARAMETERS p TYPE i.
INITIALIZATION.
通過程序對彈出的打印對話框中的默認值進行設置,在打印時,彈出的打印參數對話框中的參數默認值就是該函數所設置的值。注:該函數與GET_PRINT_PARAMETERS不一樣,SET_PRINT_PARAMETERS本身不會彈出打印參數設置對話框,它只是起到設置默認打印參數的一個作用,而通過GET_PRINT_PARAMETERS除可以設置某些打印參數,而且會自動彈出打印參數設置對話框(不過也可以設置不彈出):
CALL FUNCTION 'SET_PRINT_PARAMETERS'
EXPORTING
archive_mode = '3'
copies = '1'
department = 'BASIS'
destination = 'LP01'
expiration = '2'
immediately = 'X'
layout = 'X_65_132'
line_count = 14
line_size = 50
list_name = 'Test'
list_text = 'Test for User''s Guide'
new_list_id = 'X'
receiver = 'CNZHJIA6'
release = ' '
sap_cover_page = ' '.不打印SAP提供的封面頁
START-OF-SELECTION.
DO p TIMES.
WRITE / sy-index.
ENDDO.
TOP-OF-PAGE.
WRITE: 'Page', sy-pagno.
ULINE.
END-OF-PAGE.
ULINE.
WRITE: 'End of', sy-pagno.
注:SET_PRINT_PARAMETERS函數只是對彈出的打印參數設置對話框中的默認值有影響,輸出的內容是否能得到正確的格式化,還是看你運行程序時,點擊的是“執行”按鈕還是“執行與打印”按鈕(或者在程序中使用NEW-PAGE PRINT ON語句來強制輸入到Spool System過程進行格式化,在選擇屏幕上點擊“執行”時,普通的Write語句會直接輸了到List屏幕中,而不管里前面是否調用SET_PRINT_PARAMETERS函數):
1、 點擊選擇屏幕上工具條中的“執行與打印”按鈕,輸出的PDF與SAP spool System中的List內容的格式都是已按照程序中設置的打印參數格式化了
2、 如果還是先點擊“執行”,然后在輸出List屏幕上點擊“打印”,雖然此時彈出的打印參數設置對話框中的默認值為程序中SET_PRINT_PARAMETERS函數所設置的值,但此時打印出來的格式是未格式化的內容,這與點擊上面執行與打印按鈕輸出是不一樣的,因為此時的輸出是直接Write到了屏幕上,然不是輸出到了SAP spool System中:
從程序中啟動打印
如果想在創建List時啟動打印處理,使用帶PRINT ON選項的NEW-PAGE語句:
NEW-PAGE PRINT ON[NEW-SECTION] [PARAMETERS<pripar>]
[ARCHIVEPARAMETERS<arcpar>]
[NODIALOG].
該語句后的所有輸出不再直接輸出到屏幕上,而是輸出到spool system中
在已經有過向spool system輸出List后,如果不使用NEW-SECTION選項,則NEW-PAGE PRINT ON語句將失效。如果使用了NEW-SECTION選項,將會重置SY-PAGNO系統字段為1。如果系統已經向spool系統中輸出過List,則NEW-SECTION選項有如下作用:
? 如果當前List指定的了打印參數(PARAMETERS )中的PRNEW為SPACE,系統不會創建新的spool request
? 如果當前List沒有指定打印參數(PARAMETERS )中PRNEW打印參數,或者指定了但不為SPACE時,系統會關掉當前spool reques並重新創建新的spool request
事件結束時會自動的結束打印處理。如果要明確的結束當前List輸出到spool system中,則使用以下語句:
NEW-PAGE PRINT OFF.
該語句的作用是結束向spool system中輸出,此語句后的輸出會直接顯示輸出到屏幕上顯示
REPORT sapmztst NO STANDARD PAGE HEADING.
DATA: val,
pripar LIKE pri_params,
arcpar LIKE arc_params,
lay(16),
lines TYPE i,
rows TYPE i.
"獲取用戶配置的默認打印設置
CALL FUNCTION 'GET_PRINT_PARAMETERS'
EXPORTING
"彈出打印參數設置對話框,可以修改默認打印參數
no_dialog = ' '
IMPORTING
out_parameters = pripar "接收打印輸出參數
out_archive_parameters = arcpar "接收歸檔參數
valid = val "參數是否有效
EXCEPTIONS
archive_info_not_found = 1
invalid_print_params = 2
invalid_archive_params = 3
OTHERS = 4.
"如果驗證通過
IF val <> space AND sy-subrc = 0.
SET PF-STATUS 'PRINT'.
WRITE ' Select a format!'.
ENDIF.
TOP-OF-PAGE DURING LINE-SELECTION.
WRITE: 'Page', sy-pagno.
ULINE.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'PORT'.
lay = 'X_65_80'.
lines = 60.
rows = 55.
PERFORM format.
WHEN 'LAND'.
lay = 'X_65_132'.
lines = 60.
rows = 110.
PERFORM format.
ENDCASE.
FORM format.
"以前面獲取到的arcpar、pripar為基礎,重新構建arcpar、pripar
CALL FUNCTION 'GET_PRINT_PARAMETERS'
EXPORTING
in_archive_parameters = arcpar
in_parameters = pripar
"下面3個參數會重新修改 pripar 中相應的參數
layout = lay
line_count = lines
line_size = rows
no_dialog = 'X'"重新構建打印參數時不用顯示對話框
IMPORTING
out_archive_parameters = arcpar "重新構建的arcpar
out_parameters = pripar "重新構建的pripar
valid =
val
EXCEPTIONS
archive_info_not_found = 1
invalid_print_params = 2
invalid_archive_params = 3
OTHERS = 4.
IF val <> space AND sy-subrc = 0.
PERFORM list.
ENDIF.
ENDFORM. "FORMAT
FORM list.
"使用前面獲得的 打印輸出參數pripar 與 打印歸檔參數arcpar
"進行打印處理
NEW-PAGE PRINT ON
NEW-SECTION
PARAMETERS pripar
ARCHIVE PARAMETERS arcpar
NO DIALOG."不用顯示打印參數設置對應框了,因為前面已經顯示
"所以參數都是驗證通過的
DO 440 TIMES.
WRITE (3) sy-index.
ENDDO.
ENDFORM.
SUBMIT 程序時打印List
如果將通過SUBMIT語句被調用的reports的輸出發送到spool system中,可以使用TO SAP-SPOOL選項:
SUBMIT<rep>TO SAP-SPOOL
[SPOOLPARAMETERS<pripar>]
[ARCHIVEPARAMETERS<arcpar>]
[WITHOUTSPOOLDYNPRO].
如果使用TO SAP-SPOOL選項,List在創建時會使用格式化打印,然后將格式化后的List輸出到spool system。SPOOLPARAMETERS與ARCHIVEPARAMETERS參數與NEW-PAGE PRINT ON語句是一樣的。如果不想彈出打印參數設置對話框
與Spool對話框:
,可以使用WITHOUT SPOOL DYNPRO選項進行壓制。如果使用了WITHOUT SPOOL DYNPRO選項,則不會顯示Spool對話框,此時如果想看Spool system中的格式化List,可以選擇菜單:
System → Own Spool Requests
REPORT YJZJ_TEST NO STANDARD PAGE HEADING.
DATA: val,
pripar LIKE pri_params,
arcpar LIKE arc_params.
CALL FUNCTION 'GET_PRINT_PARAMETERS'
EXPORTING
layout = 'X_65_132'
line_count = 65
line_size = 132
IMPORTING
out_parameters = pripar
out_archive_parameters = arcpar
valid = val
EXCEPTIONS
archive_info_not_found = 1
invalid_print_params = 2
invalid_archive_params = 3
OTHERS = 4.
IF val <> space AND sy-subrc = 0.
SUBMIT YJZJ_TEST2 TO SAP-SPOOL
SPOOL PARAMETERS pripar
ARCHIVE PARAMETERS arcpar
WITHOUT SPOOL DYNPRO.
ENDIF.
REPORT yjzj_test2.
START-OF-SELECTION.
DO 100 TIMES.
WRITE: sy-index.
ENDDO.
Print Control
SET MARGIN 與 PRINT-CONTROL語句僅對輸出到spool系統中的List起作用,對直接顯示在屏幕上的List ,並使用List → Print打印是無效的
限定左邊距與上邊距
SETMARGIN<x>[<y>].
該語句指定了左邊與上邊的空白,以列(X)和行(Y)為單位。並將X與Y分別存儲到SY-MACOL與SY-MAROW系統變量中,在打印輸出時,系統會使用這兩個系統變量來決定頁面的左邊距與上邊距。該語句對所有后續頁面都起作用,除非一下個這樣的語句重新設定。
REPORT sapmztst LINE-SIZE 60.
SET MARGIN 10 6.
PARAMETERS: c.
START-OF-SELECTION.
DO 100 TIMES.
WRITE: sy-index.
ENDDO.
PRINT-CONTROL
PRINT-CONTROL { { formats|{FUNCTION code}
[LINE line] [POSITION col] }
| { INDEX-LINE index_line } }.
該語句只對通過NEW-PAGE PRINT ON, SUBMIT TO SAP-SPOOL或者是選擇屏幕上的“Execute and Print”按鈕創建的print lists起作用,對“Print”打印screen list(已顯示在屏幕上的列表)是不起作用。
... formats|{FUNCTION code} [LINE line] [POSITION col]
該選項對從當前Page的line行col列所有后續輸出內容的print format進行設置,如果沒有設置line與col,則從當前位置(sy-linno, sy-colno)開始格式化,line會存儲到sy-linno中,col會存儲到sy-colno。
Formats參數選項可以是下表中的列表的選項,在運行時系統會將這些選項轉換printer-independent (與打印機無關)的相應code,當List在實際打印時,這些code又會翻譯成printer-specific(與打印相關)的control characters:
<formats> |
Code |
Meaning |
CPI<cpi> |
CI<cpi> |
Charactersper inch |
LPI<lpi> |
LI<lpi> |
Linesper inch |
COLORBLACK |
CO001 |
Colorblack |
COLORRED |
CO002 |
Colorred |
COLORBLUE |
CO003 |
Colorblue |
COLORGREEN |
CO004 |
Colorgreen |
COLORYELLOW |
CO005 |
Color yellow |
COLORPINK |
CO006 |
Colorpink |
LEFTMARGIN<lfm> |
LM<lfm> |
Spacefrom theleftmargin |
FONT<fnt> |
FO<fnt> |
Font |
SIZE siz |
SIsiz |
font size |
FUNCTION<code> |
<code> |
Fordirectlyspecifyinga code |
<formats>可以這樣使用:PRINT-CONTROL COLOR GREEN.,但好像沒起作用?
Code可以使用FUNCTION方式來調用:PRINT-CONTROL FUNCTION t022d-prctl.
[LINE line] [POSITION col]選項表示設置的格式從哪行哪列起作用
將Code轉換成device-specific(打印設備相關)的control characters是根據TSP03 與 T022D兩個表來確定的,某個設備類型有效的print control codes可以通過事務碼SPAD來查看:
REPORT sapmztst.
PARAMETERS: c.
TABLES: t022d.
SELECT * FROM t022d WHERE typ = 'CNSAPWIN'.設備類型,與事務碼SPAD中設置相同
PRINT-CONTROL FUNCTION t022d-prctl.
WRITE :/ t022d-prctl.
ENDSELECT.
點擊選擇屏幕上的“Execute and Print”按鈕,運行結果如下:
輸出設備與設備類型:
TSP03中存儲了輸出設備:
T022D中存儲了每種設備類型所對應的打印指令(輸出設備屬於某種設備類型):
將文本文件轉換成PDF
REPORT zzdw_text_to_pdf LINE-SIZE 132.
TYPES: BEGIN OF typ_file,
text(132) TYPE c,
END OF typ_file.
DATA: iw_file TYPE typ_file,
it_file TYPE TABLE OF typ_file,
it_pdf TYPE TABLE OF tline,
g_size TYPE i,
g_spid TYPE rspoid,
g_para TYPE pri_params,
g_flag TYPE c.
PARAMETERS: p_from(128) TYPE c OBLIGATORY LOWER CASE
DEFAULT 'C:\data\char.txt',
p_to(128) TYPE c OBLIGATORY LOWER CASE
DEFAULT 'C:\data\char.pdf'.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_from.
PERFORM f_get_filename.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_to.
PERFORM f_set_filename.
START-OF-SELECTION.
PERFORM f_read_file.
CALL FUNCTION 'GET_PRINT_PARAMETERS'
EXPORTING
no_dialog = 'X'
IMPORTING
* out_archive_parameters =
out_parameters = g_para
valid = g_flag
* valid_for_spool_creation =
EXCEPTIONS
archive_info_not_found = 1
invalid_print_params = 2
invalid_archive_params = 3
OTHERS = 4
.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
CHECK g_flag = 'X'.
NEW-PAGE
NO-TITLE
NO-HEADING
PRINT ON PARAMETERS g_para
NO DIALOG.
LOOP AT it_file INTO iw_file.
WRITE: /1 iw_file-text.
CLEAR iw_file.
ENDLOOP.
NEW-PAGE PRINT OFF.
"* SPOOL to PDF
g_spid = sy-spono."Spool Number of List Print
CALL FUNCTION 'CONVERT_ABAPSPOOLJOB_2_PDF'
EXPORTING
src_spoolid = g_spid
no_dialog = ' '
* dst_device =
* pdf_destination =
IMPORTING
pdf_bytecount = g_size
* pdf_spoolid =
* list_pagecount =
* btc_jobname =
* btc_jobcount =
TABLES
pdf = it_pdf
EXCEPTIONS
err_no_abap_spooljob = 1
err_no_spooljob = 2
err_no_permission = 3
err_conv_not_possible = 4
err_bad_destdevice = 5
user_cancelled = 6
err_spoolerror = 7
err_temseerror = 8
err_btcjob_open_failed = 9
err_btcjob_submit_failed = 10
err_btcjob_close_failed = 11
OTHERS = 12
.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
PERFORM f_save_file.
*&---------------------------------------------------------------------*
*& Form F_GET_FILENAME
*&---------------------------------------------------------------------*
FORM f_get_filename .
DATA: l_rc TYPE i,
it_file TYPE filetable.
DATA:l_obj TYPE REF TO cl_gui_frontend_services.
CREATE OBJECT l_obj.
CALL METHOD l_obj->file_open_dialog
EXPORTING
file_filter = '.txt'
initial_directory = 'C:\data'
CHANGING
file_table = it_file
rc = l_rc.
CHECK l_rc = 1.
READ TABLE it_file INTO p_from INDEX 1.
ENDFORM. " F_GET_FILENAME
*&---------------------------------------------------------------------*
*& Form F_READ_FILE
*&---------------------------------------------------------------------*
FORM f_read_file .
DATA: l_fname TYPE string.
l_fname = p_from.
CALL FUNCTION 'GUI_UPLOAD'
EXPORTING
filename = l_fname
filetype = 'ASC'
* has_field_separator = ' '
* header_length = 0
* read_by_line = 'x'
* dat_mode = ' '
* codepage = ' '
* ignore_cerr = abap_true
* replacement = '#'
* check_bom = ' '
* virus_scan_profile =
* no_auth_check = ' '
* IMPORTING
* filelength =
* header =
TABLES
data_tab = it_file
EXCEPTIONS
file_open_error = 1
file_read_error = 2
no_batch = 3
gui_refuse_filetransfer = 4
invalid_type = 5
no_authority = 6
unknown_error = 7
bad_data_format = 8
header_not_allowed = 9
separator_not_allowed = 10
header_too_long = 11
unknown_dp_error = 12
access_denied = 13
dp_out_of_memory = 14
disk_full = 15
dp_timeout = 16
OTHERS = 17
.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM. " F_READ_FILE
*&---------------------------------------------------------------------*
*& Form F_SET_FILENAME
*&---------------------------------------------------------------------*
FORM f_set_filename .
DATA: l_rc TYPE i,
it_file TYPE filetable,
l_name TYPE string,
l_path TYPE string,
l_fpath TYPE string.
DATA:l_obj TYPE REF TO cl_gui_frontend_services.
CREATE OBJECT l_obj.
CALL METHOD l_obj->file_save_dialog
EXPORTING
file_filter = '.pdf'
initial_directory = 'C:\data'
CHANGING
filename = l_name
path = l_path
fullpath = l_fpath
user_action = l_rc.
CHECK l_rc <> 9.
p_to = l_fpath.
ENDFORM. " F_SET_FILENAME
*&---------------------------------------------------------------------*
*& Form F_SAVE_FILE
*&---------------------------------------------------------------------*
FORM f_save_file .
DATA:l_file TYPE string.
l_file = p_to.
CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
bin_filesize = g_size
filename = l_file
filetype = 'BIN'
IMPORTING
filelength = g_size
TABLES
data_tab = it_pdf.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
WRITE 'SAVED SUCCESSFULLY!'.
ENDFORM. " F_SAVE_FILE
輸出到PDF打印
現在大家都在提倡節約能源,珍惜不可再生資源,減少大氣二氧化碳排放量。IT界也提出了綠色IT的口號,要使現綠色IT就從減少打印做起吧。企業在應用SAP ERP時,可能需要大量打印通信文檔如催款單,對賬單,付款通知等。通過生成PDF格式的通信文件然后用電子郵件的方式發給客戶或供應商,不僅大在降低打印成本和郵遞費用,加快了與業務合作伙伴的信息溝通,而且還能可達到環保的目的,可謂一舉三得。在SAP ERP中安裝PDF打印機的方法如下:
1、使用T-Code:SPAD啟動打印配置管理
2、在 “Configuration” 菜單下,執行"Output Device"
3.按“修改”按鈕進入修改模式,用 "Output Device " 菜單上 "Create"
4.輸入Output Device 的命字,例如LP02;設置Device Type 為“CNSAPWIN : MS Windows driver via SAPLPD” ,並將Device Class設置為 "Standard".
5. 在 "Access Method" Tab的參數中設置如下:F 前端打印表示在打印時可以手動選擇本地計算機上安裝的打印機。
6. 需要打印時,系統會提示選擇客戶端安裝的PDF生成器,用戶可選擇立即打印;也可選擇提交到打印池中,稍后用T-Code: SP02手工執行批量打印。
以下是我們公司的使用本地設備進行打印的配置如下:
這是相應后台打印設備配置:
注:當使用函數CONVERT_OTF、或SX_OBJECT_CONVERT_OTF_PDF等函數轉換PDF時,使用的是服務器上的PDF插件,不是使用的本地安裝的軟件,上面這種本地打印是使用的是本機的打印設備或軟件,需要安裝相應軟件才有。
PDF生成器向大推薦PDF XChnageF 3.0,可以設置批量生成文件到指定文件夾,單張紙面上打印多頁內容等,比Adobe Acrobat帶的PDF生成器更強大。