ABAP程序设计的一点建议
?
一、規范化程序中的命名規則。有些在變量與內表命名的時候簡直是隨心所欲,毫無規律可言。同一類的表名多了,干脆直接XXX_1、XXX_2、XXX_3地排列下去。我們的ABAP程序雖然不能使用微軟的匈牙利命名法,但是這種毫無意義的命名法更是不可取的。
?
二、多定義一些程序,使用子程序將程序功能模塊化。SAP的ABAP編輯器是很不錯的一個編輯器,它左邊有導航條,通過雙擊可以輕易定位到每個子程序名與變量。使用子程序模塊化程序后,定位程序功能非常的方便。
?
三、不要輕易使用INCLUDE程序。ABAP開發的程序培訓教材中,曾經提到過模塊化程序的兩種方式,INCLUDE程序與子程序FORM。系統程序因為代碼量大,大量使用了INCLUDE程序。有些人看到這里,就有樣學樣,在自己的開發程序中大量使用INCLUDE程序。其實這是完全沒必要的。一般的自開發程序,如果代碼規范良好的話,不會超過3000行,放在一個主程序里足夠了。有些人把程序分成變量定義、選擇屏幕與事件、PAI、PBO、子程序等四五個INCLUDE程序,自以為很給力。而實際上呢,子程序部分占所有代碼的80%以上,而這個INCLUDE程序里定義的子程序卻有聊聊無幾,結果跟蹤調試程序麻煩的要死。又因為與變量在不同的INCLUDE程序里,結果新增變量時比較麻煩,轉而大量使用局部變量,使用程序的可讀性更加糟糕。
?
四、靈活地使用宏。MACRO這個東西從C語言提出來以后,可以說常盛不衰。當然如果不愿意使用宏,用子程序來代替也是可以的。一個比較典型的例子就是給ALV的FIELDCAT內表添加輸出字段。曾經見過一個輸出50列的ALV報表,這部分的代碼就寫了400多行。查找字段時要翻好多屏才能找到。如果使用宏的話,這部分代碼五六十行就夠了。
?
五、控制嵌套縮進的空格數。大家會發現ABAP代碼一行限制在72個字符之內,當然我們也可以取消這個限制。這其實提示我們,在嵌套縮進的時候,兩個空格就夠了,不要太多的縮進。以前有個同事喜歡縮進四個空格,結果子程序一層,LOOPAT循環一層,里面隨便出現一個IF ESLE的判斷。寫到中間,代碼都在每一行的中間開始,一行里根本寫不多少東西。
?
六、控制嵌套的層數。有人可能會大聲反對,我的程序就是需要這么多判斷,我的程序就是需要雙層循環。我很想問一句,真的是必須要這樣做嗎?我看到過一些人的代碼,是的,IF判斷就嵌套了三四層,再加上子程序一層、循環一層,搞得代碼邏輯相當復雜。我只想提醒一句,有時候我們用一個CHECK判斷一下就行,沒必要一定嵌套進去。
 
七、合理地使用INNERJOIN。內連接,大家都是會的。國內某大型集團曾提出一個硬性要求,SQL語句的表連接不能超過3個,多么傻的一個要求呀。不合理的連接,兩個連在一塊就會要人命;而合理的連接有四五個表在一起也是沒問題的。曾經遇到過一個極品ABAP顧問,一個1500行的程序,光數據處理的全局內表就定義了28個,程序中幾乎沒有一個連接取數的。當然,過多的連接也是不行的。當年培訓一個JAVA出身的程序員,出了一個題目,就是要求取銷售訂單及后續交貨單、發貨過賬的一些數據。這哥們沒寫,還振振有詞地說太簡單了,在系統中建立三個視圖VBAK-VBAP-VBUK、LIKP-LIPS、MKPF-MSEG,然后視圖內連接就出來了。哥當時真的是無話可說了,夏蟲不可語冰,他還真以為SAP的ERP系統是他自己開發的ACCESS數據庫呢!
?
八、注意一下小技巧的使用。ABAP程序的一些語句在處理一些特定的問題時特別有用,不要有意無意地忽略了這些語句。比如LOOPAT循環中的AT事件。有人在將一組數分類匯總并插到內表中時,又是內表,又是排序,搞得相當復雜。比如,財務的某一科目段,要按科目匯總一次,按科目的前6位匯總一次,按科目的前4位匯總一次,按科目的前2位匯總一次。這樣的匯總,如果靈活使用ATENDOF事件,一個循環就能搞定。再比如,財務的月度報表,求期末匯總時,有人就會判斷一個月份,然后再從上年結轉到當月等一系列字段加起來。累不累呀?ADDHSLVT THEN HSL01 UNTILL HSLXX GIVING XXX,這語句多好用呀。
?
九、注意清空中間內表。有人不喜歡清空中間內表,認為程序結束后會自動清空。要是用戶在結果屏幕上待上半天呢?何況有些處理大數量的程序如果不及時清空,本身跑起來就會耗費大量的內存資源。曾經一個報表,就一個CLEAR語句,就解決了其性能問題。
?
十、多了解點業務。有時候業務顧問給的數據邏輯能解決問題,但絕對不是最優的。我們完全可以采用更好的數據邏輯來處理數據。新項目上可能不用這樣想,但一些優化項目上這么做是必須的。
 
一般情況下,我開發ABAP程序的時候,變量及類型的命名采用以下命名規則??赡懿皇亲顑灥?#xff0c;但能回避相當多的問題。如果自己沒制定出成形的命名規則,不妨使用一下,肯定比胡亂命名要好的多。
?
1、選擇屏幕
 ?·P_XXXX:PARAMETERS 定義的單值輸入框
 ?·S_XXXX:SELECT-OPTIONS 定義的范圍輸入框
 ?·RADX:PARAMETERS 定義的 RADIOBUTION 類型的單選按鈕
 ?·CB_XXX:PARAMETERS 定義的 CHECKBOX 類型的復選框
 ?·XXXX:選擇屏幕上定義的輸出塊
2、程序內常用的變量與類型命名規則:使變量名稱盡可能的表明變量的類型
 ?·CON_XXX: 程序常量
 ?·TYP_XX:程序內定義的結構類型
 ?·TYP_T_XX:程序內定義的內表類型的結構類型
?·R_XXXX:程序內定義的RANGES變量
 ?·G_XXXX:程序內定義的全局變量
 ?·GW_XXX:程序內定義的工作區:全局變量 也可以用 WA_XXX
 ?·GT_XXX:程序內定義的內表:全局變量
 ?·CL_XXX:全局類的變量聲明
 ?· 全局的字段符聲明,下劃線前的兩個字母根據字段符的類型確定
 ?·MCR_XXXX:程序內定義的宏
 ?·SUB_XXX:程序內定義的字程序
 ?·LR_XXX: 子程序內定義的RANGE變量
 ?·L_XXXX: 子程序內定義的局部變量
 ?·LW_XXX:? 子程序內定義的工作區:局部變量
 ?·LT_XXX:? 子程序內定義的內表:局部變量
 ?·LC_XXXX:程序內定義的類 子程序內不建議定義類,如果定義使用此命名規則
 ?·MCR_XXX?宏定義在一個程序中用的不是特別多,命名規則可以和全局宏的命名規則相同。
以上命名的一個大規則就是,全局變量用一個母或是G加相應的類別字母開頭;局部變量以L加相應的類別字母開頭。子程序的形式參數的命名規則尊守局部變量的命名規則。
*? 以下命名規則不是必須的
 ?·STATUSX:程序內定義的狀態
 ?·PF_STATUS:程序內定義的用戶狀態
 3、內表與變量的命名規則:使變量名稱盡可能的表明變量的意義
  ·內表與工作區命名規則
   GT_EKKO:使用數據庫表的表名,使內表名稱表明主要保存的是哪個數據庫表的數據
   GT_SUM_EKKO:在數據庫表的表名前加一個簡寫單詞,表明內表的主要用途,而不是用1\2\3等數字代替
   GT_RESULT:使用比較固定的單詞,表明內表的主要使用目的,類似的常用內表名還有GT_EXCEL、GT_FIELD、GT_FIELDCAT
   GT_EVENTS:特定的地方,使用相對固定的內表名稱(此名稱是用在ALV的事件處理上的)
   GT_ITEMX: BAPI函數的內表則主要標明變量類別,意義則采用BAPI函數上的名稱
 ·變量的命名規則:使變量名稱盡可能的表明變量的意義
   G_DMBTR: 使用字段表明字段的類型與意義
   G_INDEX: 使用單詞表明字段的意義,再如:G_ROW、G_COLWN、G_INDIC
   CL_GRID: 使用類別名或特定的字段來用到特定的對象上(此字段是ALV輸出時常用的一個字段)
   G_MSG:  使用單詞的簡寫來表明此字段的意義
   G_HSLXX: 當內容相近的字段比較多時,可以使用中文首母或數字來表明字段的內容(期間金額)
常用的ABAP程序模版,使用以下模版就不錯。
*@---------------------------------------------------------------------*
 *@ Report? ZTESTXUE68 常用的程序模版
 *@ T-code
 *@---------------------------------------------------------------------*
 *@ Created by Xavery Hsueh(薛現軍) on 2011-03-06
 *@
 *@ Lasted Edited date:
 *@---------------------------------------------------------------------*
 REPORT ztestxue68 NO STANDARD PAGE HEADING.
************************************************************************
 **? 聲明數據庫表 Declaration ofdatabase?????????????????????????????**
 ************************************************************************
 TABLES:coep,
 ??????coss.??? "
 ************************************************************************
 **? 定義結構類型 Define the structure'stype?????????????????????????**
 ************************************************************************
 ************************************************************************
 **? 定義變量與內表 Define the variants and Internaltables???????????**
 ************************************************************************
 ************************************************************************
 **? 宏定義 Define themacro??????????????????????????????????????????**
 ************************************************************************
 DEFINE mcr_range.
 ? clear &1.
 ? &1-sign = 'I'.
 ? &1-option = &2.
 ? &1-low = &3.
 ? &1-high = &4.
 ? append &1.
 END-OF-DEFINITION.
 ************************************************************************
 **? 選擇屏幕 Customize theselection-screen??????????????????????????**
 ************************************************************************
 SELECTION-SCREEN BEGIN OF BLOCK xavery WITH FRAME TITLEtext_001.
 PARAMETERS: p_erdat TYPE dats DEFAULTsy-datum.??????"統計日期
 PARAMETERS: p_kokrs TYPE kokrsOBLIGATORY.???????????"控制范圍
 SELECT-OPTIONS s_kstar FORcoep-kstar.???????????????"成本要素
 SELECTION-SCREEN END OF BLOCK xavery.
 ************************************************************************
 **? 執行程序事件 Executing the program'sevents??????????????????????**
 ************************************************************************
 INITIALIZATION.
 ? PERFORM sub_init_cond.
?
START-OF-SELECTION.
? PERFORM sub_query_vbak.
??PERFORM sub_query_likp.
? PERFORM sub_query_text.
? PERFORM sub_prcess_data.
? PERFORM sub_process_text.
?
END-OF-SELECTION.
? 輸出結果內表的子程序調用
 *@---------------------------------------------------------------------*
 *@?????Form? SUB_INIT_COND
 *@---------------------------------------------------------------------*
 *??????初始化選擇條件
 *----------------------------------------------------------------------*
 FORM sub_init_cond .
 ? text_001 = '選擇屏幕'.
 ENDFORM.???????????????????" SUB_INIT_COND
?
使用以上程序模版,將類型、變量、宏、子程序等放到相應的注釋下,再加上SAP的導航欄,操作起來是非常方便的,這比使用INCLUDE程序要方便的多。
常用的ABAPALV程序模版。ABAP程序開發中,ALV報表的輸出占了一半以上,基于這一點的考慮,ALV報表我一般使用如下的模版。?
*&---------------------------------------------------------------------*
 *& Report? ZTESTXUE56 采購訂單發貨跟蹤表
 *&
 *&---------------------------------------------------------------------*
 *& Created by Xavery Hsueh on 2014-02-13
 *&
 *&---------------------------------------------------------------------*
 REPORT? ztestxue56 NO STANDARD PAGE HEADING.
 ************************************************************************
 **? 聲明數據庫表 Declaration ofdatabase?????????????????????????????**
 ************************************************************************
 TABLES:ekko,
 ??????ekpo,
 ??????ekbe,
 ??????lfa1.??? "
 ************************************************************************
 **? 定義結構類型 Define the structure'stype?????????????????????????**
 ************************************************************************
 TYPES:BEGIN OF typ_result,
 ???????ebeln TYPE ekpo-ebeln,
 ???????ebelp TYPE ekpo-ebelp,
 ???????lifnr TYPE ekko-lifnr,
 ???????name1 TYPE lfa1-name1,
 ???????matnr TYPE ekpo-matnr,
 ???????maktx TYPE makt-maktx,
 ???????matkl type mara-matkl,
 ???????menge TYPEekpo-menge,????"采購訂單數量
 ???????bdmng TYPEekpo-menge,????"收貨數量
 ???????inmng TYPEekpo-menge,????"發票校驗數量
 ???????box?? TYPE c,
 ?????END OF typ_result.
TYPES:BEGIN OF typ_lfa1,
 ???????lifnr TYPE lfa1-lifnr,
 ???????name1 TYPE lfa1-name1,
 ?????END OF typ_lfa1.
TYPES:BEGIN OF typ_ekbe,
 ???????ebeln TYPE ekbe-ebeln,
 ???????ebelp TYPE ekbe-ebelp,
 ???????vgabe TYPE ekbe-vgabe,
 ???????menge TYPE ekbe-menge,
 ???????bwart TYPE ekbe-bwart,
 ?????END OF typ_ekbe.
 ************************************************************************
 **? 定義變量與內表 Define the variants and Internaltables???????????**
 ************************************************************************
 DATA:gt_result?? TYPE TABLE OFtyp_result WITH HEADER LINE,
 ????gt_makt????TYPE TABLE OF makt WITH HEADER LINE,
 ????gt_lfa1????TYPE TABLE OF typ_lfa1 WITH HEADER LINE,
 ????gt_ekbe????TYPE TABLE OF typ_ekbe WITH HEADER LINE,
 ????gt_sum_ekbe TYPE TABLE OF typ_ekbe WITH HEADER LINE.
FIELD-SYMBOLS: TYPE typ_result.
TYPE-POOLS:slis.
 DATA: cl_grid TYPE REF TO cl_gui_alv_grid,
 ?????g_repid????????????LIKE sy-repid,
 ?????g_structure_name???TYPE tabname,
 ?????g_command??????????TYPE slis_formname,
 ?????g_title????????????TYPE lvc_title,
 ?????g_setting??????????TYPE lvc_s_glay,
 ?????wa_print???????????TYPE slis_print_alv,
 ?????gt_list_top_of_page TYPE slis_t_listheader,
 ?????gt_events??????????TYPE slis_t_event WITH HEADER LINE,
 ?????gt_sort????????????TYPE slis_t_sortinfo_alv,
 ?????wa_sort????????????TYPE slis_sortinfo_alv,
 ?????wa_layout??????????TYPE slis_layout_alv,
 ?????gt_fieldcat????????TYPE slis_t_fieldcat_alv,
 ?????wa_fieldcat????????LIKE LINE OF gt_fieldcat,
 ?????g_field????????????TYPE char30,
 ?????g_save?????????????TYPE c,
 ?????g_con_mark?????????TYPE slis_fieldcat_alv-fieldname VALUE 'MARK',
 ?????g_length???????????TYPE i,
 ?????g_pos??????????????TYPE i.
FIELD-SYMBOLS:.
 ************************************************************************
 **? 宏定義 Define themacro??????????????????????????????????????????**
 ************************************************************************
 DEFINE mcr_range.
 ? clear &1.
 ? &1-sign = 'I'.
 ? &1-option = &2.
 ? &1-low = &3.
 ? &1-high = &4.
 ? append &1.
 END-OF-DEFINITION.
 * 給FILEDCAT ALV內表賦值
 DEFINE mcr_field.
 ? clear wa_fieldcat.
 ? clear g_field.
 ? g_pos = g_pos + 1 .
 ?wa_fieldcat-col_pos??????=? g_pos.
 ? wa_fieldcat-fieldname = &1.
 ?wa_fieldcat-no_zero????= 'X'.
 ? wa_fieldcat-tabname = 'GT_RESULT'.
 * wa_fieldcat-no_out ='X'.?????"field no display, choose from layout
 ? wa_fieldcat-key =&2.????????"SUBTOTAL KEY
 ? wa_fieldcat-seltext_l = &3.
 * 計算輸出字段的長度
 ? concatenate 'GT_RESULT-' &1 intog_field.
 ? assign (g_field) to .
 ? describe field output-length?g_length.
 ? wa_fieldcat-outputlen = g_length.
 ? append wa_fieldcat to gt_fieldcat.
 END-OF-DEFINITION.
 ************************************************************************
 **? 選擇屏幕 Customize theselection-screen??????????????????????????**
 ************************************************************************
 SELECTION-SCREEN BEGIN OF BLOCK xavery WITH FRAME TITLEtext-001.
 PARAMETERS:p_bsart TYPE ekko-bsart OBLIGATORY DEFAULT 'NB'.
 SELECT-OPTIONS: s_lifnr FOR lfa1-lifnr,
 ???????????????s_ekorg FOR ekko-ekorg,
 ???????????????s_bedat FOR ekko-bedat.
 SELECTION-SCREEN END OF BLOCK xavery.
 ************************************************************************
 **? 執行程序事件 Executing the program'sevents??????????????????????**
 ************************************************************************
 INITIALIZATION.
 ? PERFORM sub_init_cond.
START-OF-SELECTION.
 ? PERFORM sub_query_ekbe.
 ? PERFORM sub_process_result.
 ? PERFORM sub_query_text.
 ? PERFORM sub_process_text.
END-OF-SELECTION.
 ? PERFORM sub_create_fieldcat.
 ? PERFORM sub_init_layout.
 ? PERFORM sub_display_as_alv.?"以ALV的方式輸出結果表
 *@---------------------------------------------------------------------*
 *@?????Form? SUB_INIT_COND
 *@---------------------------------------------------------------------*
 *??????初始化選擇條件
 *----------------------------------------------------------------------*
 FORM sub_init_cond .
ENDFORM.???????????????????" SUB_INIT_COND
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_QUERY_EKBE
 *&---------------------------------------------------------------------*
 *??????查詢采購訂單相關的數據
 *----------------------------------------------------------------------*
 FORM sub_query_ekbe .
 ? SELECT ekko~ebeln
 ????????ekpo~ebelp
 ????????ekpo~matnr
 ????????ekpo~menge
 ????????ekpo~matkl
 ????????ekpo~elikz
 ????????ekko~lifnr
 ?????FROM ekko INNER JOIN ekpo ON ekko~ebeln = ekpo~ebeln
 ?????INTO CORRESPONDING FIELDS OF TABLE gt_result
 ?????WHERE bsart EQ p_bsart AND
 ???????????ekorg IN s_ekorg AND
 ???????????lifnr IN s_lifnr AND
 ???????????bedat IN s_bedat.
? CHECK gt_result[] IS NOT INITIAL.
 ? SELECT ebeln
 ????????ebelp
 ????????vgabe
 ????????menge
 ????????bwart
 ?????FROM ekbe
 ?????INTO TABLE gt_ekbe
 ?????FOR ALL ENTRIES IN gt_result
 ?????WHERE ebeln = gt_result-ebeln AND
 ???????????ebelp = gt_result-ebelp.
? SORT gt_ekbe BY ebeln ebelp vgabe.
 ? LOOP AT gt_ekbe.
 ??? AT NEWvgabe.
 ?????CLEAR gt_sum_ekbe.
 ??? ENDAT.
 ???gt_sum_ekbe-ebeln = gt_ekbe-ebeln.
 ???gt_sum_ekbe-ebelp = gt_ekbe-ebelp.
 ???gt_sum_ekbe-vgabe = gt_ekbe-vgabe.
??? IFgt_ekbe-bwart = '101' OR gt_ekbe-bwart = ''.
 ?????gt_sum_ekbe-menge = gt_sum_ekbe-menge + gt_ekbe-menge.
 ??? ELSEIFgt_ekbe-bwart = '102'.
 ?????gt_sum_ekbe-menge = gt_sum_ekbe-menge - gt_ekbe-menge.
 ??? ENDIF.
??? AT END OFvgabe.
 ?????APPEND gt_sum_ekbe.
 ??? ENDAT.
 ? ENDLOOP.
 * 釋放中間內表
 ? FREE:gt_ekbe.
 ENDFORM.???????????????????" SUB_QUERY_EKBE
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_QUERY_TEXT
 *&---------------------------------------------------------------------*
 *??????查詢文本描述信息
 *----------------------------------------------------------------------*
 FORM sub_query_text .
 ? CHECK gt_result[] IS NOT INITIAL.
 ? SELECT * FROM makt
 ?????INTO TABLE gt_makt
 ?????FOR ALL ENTRIES IN gt_result
 ?????WHERE matnr = gt_result-matnr AND
 ???????????spras = sy-langu.
? SELECT lifnr
 ????????name1
 ?????FROM lfa1
 ?????INTO TABLE gt_lfa1
 ?????FOR ALL ENTRIES IN gt_result
 ?????WHERE lifnr = gt_result-lifnr.
 ENDFORM.???????????????????" SUB_QUERY_TEXT
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_PROCESS_RESULT
 *&---------------------------------------------------------------------*
 *??????將采購訂單數據更新到結果內表
 *----------------------------------------------------------------------*
 FORM sub_process_result .
 ? SORT gt_sum_ekbe BY ebeln ebelp vgabe.
 ? LOOP AT gt_result ASSIGNING .
 ??? CLEARgt_sum_ekbe.
 ??? READ TABLEgt_sum_ekbe WITH KEY ebeln = -ebeln
 ???????????????????????????????????ebelp = -ebelp
 ???????????????????????????????????vgabe = 1
 ???????????????????????????????????BINARY SEARCH.
 ??? IF sy-subrc= 0.
 ?????-bdmng = gt_sum_ekbe-menge.
 ??? ENDIF.
??? CLEARgt_sum_ekbe.
 ??? READ TABLEgt_sum_ekbe WITH KEY ebeln = -ebeln
 ???????????????????????????????????ebelp = -ebelp
 ???????????????????????????????????vgabe = 2
 ???????????????????????????????????BINARY SEARCH.
 ??? IF sy-subrc= 0.
 ?????-inmng = gt_sum_ekbe-menge.
 ??? ENDIF.
 ? ENDLOOP.
 * 釋放中間內表
 ? FREE:gt_sum_ekbe.
 ENDFORM.???????????????????" SUB_PROCESS_RESULT
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_PROCESS_TEXT
 *&---------------------------------------------------------------------*
 *??????將文本信息更新到結果內表
 *----------------------------------------------------------------------*
 FORM sub_process_text .
 ? SORT gt_makt BY matnr.
 ? SORT gt_lfa1 BY lifnr.
 ? LOOP AT gt_result ASSIGNING .
 ??? CLEARgt_makt.
 ??? READ TABLEgt_makt WITH KEY matnr = -matnr
 ???????????????????????????????BINARY SEARCH.
 ??? IF sy-subrc= 0.
 ?????-maktx = gt_makt-maktx.
 ??? ENDIF.
??? CLEARgt_lfa1.
 ??? READ TABLEgt_lfa1 WITH KEY lifnr = -lifnr
 ???????????????????????????????BINARY SEARCH.
 ??? IF sy-subrc= 0.
 ?????-name1 = gt_lfa1-name1.
 ??? ENDIF.
 ? ENDLOOP.
 * 釋放中間內表
 ? FREE:gt_makt,
 ??????gt_lfa1.
 ENDFORM.???????????????????" SUB_PROCESS_TEXT
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_CREATE_FIELDCAT
 *&---------------------------------------------------------------------*
 *??????給輸出的結果內表指定字段
 *----------------------------------------------------------------------*
 FORM sub_create_fieldcat .
 ? CLEAR gt_fieldcat[].
 ? mcr_field?'EBELN'???'X'??? '采購訂單號'.
 ? mcr_field?'EBELP'???'X'??? '訂單行項目'.
 ? mcr_field?'LIFNR'???''????'供應商賬號' .
 ? mcr_field?'NAME1'???''????'供應商名稱' .
 ? mcr_field?'MATNR'???''????'物料編號' .
 ? mcr_field?'MATKL'???''????'物料組'.
 ? mcr_field?'MAKTX'???''????'物料描述'.
 ? mcr_field?'MENGE'???''????'訂單數量' .
 ? mcr_field?'BDMNG'???''????'收貨數量' .
 ? mcr_field?'INMNG'???''????'發票校驗數量' .
 ENDFORM.???????????????????" SUB_CREATE_FIELDCAT
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_INIT_LAYOUT
 *&---------------------------------------------------------------------*
 *??????設置常用的輸出布局參數
 *----------------------------------------------------------------------*
 FORM sub_init_layout .
 ?wa_layout-zebra????????????= 'X'.
 ?wa_layout-window_titlebar?? ='采購發貨跟蹤表'.
 ? wa_layout-colwidth_optimize = 'X'.
 ?wa_layout-box_fieldname????= 'BOX'.
 ?wa_layout-header_text??????= '選擇'.
 ENDFORM.???????????????????" SUB_INIT_LAYOUT
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_DISPLAY_AS_ALV
 *&---------------------------------------------------------------------*
 *??????調用 ALV 的FUNCTION來輸出結果
 *----------------------------------------------------------------------*
 FORM sub_display_as_alv .
 ? g_repid = sy-repid.
 ? g_setting-coll_top_p ='X'.??????"最小化 CALLBACK-TOP-OF-PAGE.
 * ABAP List Viewer
 ? CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
 ???EXPORTING
 ?????i_callback_program??????= g_repid
 ?????i_structure_name????????= 'TYP_RESULT'
 ?????i_grid_title????????????= g_title
 ?????i_grid_settings?????????= g_setting
 ?????i_callback_user_command? ='SUB_USER_COMMAND'
 ?????i_callback_pf_status_set = 'SUB_SET_PF_STATUS'
 ?????i_save??????????????????= g_save
 ?????is_layout???????????????= wa_layout
 ?????it_fieldcat?????????????= gt_fieldcat[]
 ??? TABLES
 ?????t_outtab????????????????= gt_result
 ???EXCEPTIONS
 ?????program_error???????????= 1
 ?????OTHERS??????????????????= 2.
 ENDFORM.???????????????????" SUB_DISPLAY_AS_ALV
 *@---------------------------------------------------------------------*
 *@??????FORMSUB_SET_PF_STATUS???????????????????????????????????????*
 *@---------------------------------------------------------------------*
 *? 設置ALV菜單
 *?通過SE41,拷貝程序SAPLSLVC_FULLSCREEN的狀態STANDARD_FULLSCREEN過來
 *@---------------------------------------------------------------------*
 FORM sub_set_pf_status USING rt_extab TYPE slis_t_extab.
 ? SET PF-STATUS 'STANDARD_FULLSCREEN'.
 ENDFORM.???????????????????"sub_set_pf_status
 *@--------------------------------------------------------------------*
 *@?????Form? sub_user_command
 *@--------------------------------------------------------------------*
 *?????-->R_UCOMM????事務功能碼
 *?????-->RS_SELFIELD ALV相關的數據
 *---------------------------------------------------------------------*
 FORM sub_user_command USINGr_ucomm?? LIKE sy-ucomm
 ???????????????????????rs_selfield TYPE slis_selfield.
 ? DATA l_ebeln TYPE ekko-ebeln.
 ? l_ebeln = rs_selfield-value+0(10).
 ? CASE r_ucomm.
 ??? WHEN'&IC1'.????????????????"雙擊事件的功能碼
 ?????PERFORM sub_ucomm_double_click USING l_ebeln.
 ??? WHEN'EDIT'.?????????????"刷新訂單的特性值
 *?????PERFORM sub_ucomm_update.
 ??? WHENOTHERS.
 ? ENDCASE.
 * 刷新ALV報表
 ? rs_selfield-refresh = 'X'.
ENDFORM.???????????????????"sub_user_command
 *&---------------------------------------------------------------------*
 *&?????Form? SUB_UCOMM_DOUBLE_CLICK
 *&---------------------------------------------------------------------*
 *??????實現ALV 的雙擊跳轉功能
 *----------------------------------------------------------------------*
 FORM sub_ucomm_double_click USING l_ebeln TYPE ekko-ebeln.
 ? CALL FUNCTION'ME_DISPLAY_PURCHASE_DOCUMENT'
 ???EXPORTING
 ?????i_ebeln?????????????= l_ebeln
 ???EXCEPTIONS
 ?????not_found???????????= 1
 ?????no_authority????????= 2
 ?????invalid_call????????= 3
 ?????preview_not_possible = 4
 ?????OTHERS??????????????= 5.
 ? IF sy-subrc <> 0.
 ??? MESSAGE IDsy-msgid TYPE sy-msgty NUMBER sy-msgno
 ???????????WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
 ? ENDIF.
 ENDFORM.???????????????????" SUB_UCOMM_DOUBLE_CLICK
?
本程序是一個項目上的實用程序,幾經修訂后變成了我常用的ALV程序的模版。
?
1、首先,ALV的變量是比較全的。一般情況下的ALV報表輸出,不用再新增輸出格式相關的變量。再是ALV報表的幾個子程序也是固定的,使用ALV 輸出,只要將這些子程序COPY過去,再做簡單的修改就可以滿足了。
?
2、本程序的命名規則也是很規范的。本程序曾經擴展到2000多行,業務延伸到了應付賬款及賬齡分析。在命名統一、子程序模塊化的情況下,一點都不雜亂。移交給客戶時非常的簡單明了。不會因為邏輯的混亂而產生什么誤解。
?
3、注意子程序的模塊化。雖然只是五六百行的小程序,但取數與處理部分仍然分成了四個子程序。這在閱讀程序的時候,只要雙擊一下START-OF-SELECTION,就可以找到相應的目錄,非常簡單位。擴展的時候也是先在事件下添加子程序調用,再雙擊子程序創建的。若一個子程序的代碼超過三四百行,此程序的可讀性就大大降低了。
?
4、程序的縮進與SQL的查詢都很規范??s進就不說了,一目了然。SQL的查詢中,本程序使用了一定的內連接,簡化了代碼。在循環處理進又采用了BINARYSEARCH等小技巧,程序性能相當地出眾。每個子程序的結束都將過期的內表釋放掉,節約了內存。
總結
以上是生活随笔為你收集整理的ABAP程序设计的一点建议的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: BAPI FOR MD61,MD62,M
- 下一篇: 修改SAP系统字段描述的方法
