iT邦幫忙

0

ABAP OO-ALV 客製報表呈現

  • 分享至 

  • xImage
  •  

隨著產業日漸成熟,客戶對於需求也越來困難,ABAPER 為了生存不可避免也必須不斷精進自我,而這篇文章也是自己在學習路上的一份積累。
報表程式是 ABAP 中最常開發的功能之一,其中 ALV 報表必是ABAPER 無法避免的課題,在使用者沒有要求時,大多會CALL Function 來呈現,下方列出部分常用 ALV fcnction:

  1. REUSE_ALV_FIELDCATALOG_MERGE
  2. REUSE_ALV_GRID_DISPLAY
  3. REUSE_ALV_LIST_DISPLAY
  4. REUSE_ALV_GRID_DISPLAY_LVC

然而在部分需求中,如:搜尋條件要與 ALV 報表在相同介面時,此時便須要ALV-OO 才能達成目的
實現介面如下
https://ithelp.ithome.com.tw/upload/images/20210210/2013500885vS4WOcTw.png
https://ithelp.ithome.com.tw/upload/images/20210210/20135008PNa1Ow7FfD.png

在開始介紹範例程式時,會運用到下方觀念

  1. Dynamic program
  2. Dialog program
  3. OOP 基礎概念
    如想更加了解此類型程式執行方式,可以往此方向做研究。
    首先先附上程式碼
    TOP 區
TYPE-POOLS:abap.


DATA: lt_table         LIKE TABLE OF dntab,
      ls_table         TYPE dntab,
      d_ref            TYPE REF TO data,
      lt_comp          TYPE abap_component_tab,
      lt_alv_cat       TYPE TABLE OF lvc_s_fcat,
      ls_alv_cat       LIKE LINE OF lt_alv_cat,
      gv_noinput       TYPE c,
      gv_modify        TYPE c.

*----- For Dialog Program Logic flow
FIELD-SYMBOLS <gv_screen_no> TYPE any ."VALUE '1000'.
DATA ok_code LIKE sy-ucomm.

*----- Field Symbol
FIELD-SYMBOLS: <dyn_table>     TYPE STANDARD TABLE ,
               <dyn_tmp_struc> TYPE any,
               <dyn_wa>        TYPE any ,
               <dyn_tmp_table> TYPE table.

*-------- For ALV
DATA: g_container           TYPE scrfname VALUE 'ALV_P',
      g_container_1         TYPE scrfname VALUE 'ALV_P2',
      grid1                 TYPE REF TO cl_gui_alv_grid,
      grid2                 TYPE REF TO cl_gui_alv_grid,
      gs_print              TYPE lvc_s_prnt,
      gs_print_1            TYPE lvc_s_prnt,
      gs_layout             TYPE lvc_s_layo,
      gs_layout_1           TYPE lvc_s_layo,
      g_custom_container_ma TYPE REF TO cl_gui_custom_container,
      g_custom_container    TYPE REF TO cl_gui_custom_container,
      lt_fieldcat           TYPE slis_t_fieldcat_alv WITH HEADER LINE,
      ir_data_changed       TYPE REF TO cl_alv_changed_data_protocol.
*----Excel open
DATA: lv_rc TYPE i.
DATA: lt_file_table TYPE filetable. 

**SEREEN **

SELECTION-SCREEN BEGIN OF SCREEN 1100 AS SUBSCREEN.
PARAMETERS: p_tab_n  LIKE tabname .
PARAMETERS: p_infile TYPE localfile DEFAULT 'C:\temp\upload.xlsx' .
  SELECTION-SCREEN  BEGIN OF  BLOCK lc_2 WITH FRAME TITLE TEXT-002 .
     PARAMETERS: r_ins   TYPE c RADIOBUTTON GROUP g1.
     PARAMETERS: r_mod   TYPE c RADIOBUTTON GROUP g1.
  SELECTION-SCREEN END OF  BLOCK lc_2.
SELECTION-SCREEN END OF SCREEN 1100 .

CALL SCREEN 1000.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_infile.

  CALL METHOD cl_gui_frontend_services=>file_open_dialog
    EXPORTING
      window_title = '打開文件'
    CHANGING
      file_table   = lt_file_table
      rc           = lv_rc.
  IF sy-subrc = 0.
    READ TABLE lt_file_table INTO DATA(wa_file_table) INDEX 1.
    p_infile = wa_file_table-filename.
  ENDIF.

FROM and MODULE

*&---------------------------------------------------------------------*
*&      Form  authorization_check
*&---------------------------------------------------------------------*
*& Begin Date  : 2021/02/02
*& Author      : Kevin Yu
*& Description : 權限及輸入條件確認及卡控
*----------------------------------------------------------------------*
*& Version     :
*----------------------------------------------------------------------*
FORM authorization_check.
 "  UNASSIGN <dyn_table>.
 "  UNASSIGN <dyn_tmp_struc>.
  IF p_tab_n IS INITIAL OR p_infile IS INITIAL.
     MESSAGE 'Table or Path cannot be null!!' TYPE 'I' DISPLAY LIKE 'E'.
  ELSE.

    SELECT SINGLE dd02l~tabname FROM dd02l INTO @DATA(lv_tabname)
           WHERE dd02l~tabname EQ @p_tab_n.

    IF sy-subrc EQ 0.
       PERFORM get_dynamic_itab.
       PERFORM excel_upload TABLES <dyn_table> .
       "CHECK <dyn_table> IS NOT INITIAL.
       PERFORM display_data USING <dyn_table> .
       IF     r_ins EQ 'X' AND r_mod  EQ ''.

       ELSEIF r_mod EQ 'X' AND r_ins  EQ ''.

       ENDIF.
    ELSE.
      MESSAGE 'Table Not Active, Please check!!' TYPE 'I' DISPLAY LIKE 'E'.
    ENDIF.
  ENDIF.
ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  get_dynamic_itab
*&---------------------------------------------------------------------*
*& Begin Date  : 2021/02/02
*& Author      : Kevin Yu
*& Description : 依輸入 TABLE 名產出對應欄位
*----------------------------------------------------------------------*
*& Version     :
*----------------------------------------------------------------------*
FORM get_dynamic_itab.

*取出結構字段目錄
CALL FUNCTION 'NAMETAB_GET'
  EXPORTING
    langu                     = sy-langu
    tabname                   = p_tab_n

  TABLES
    nametab                   = lt_table.

  IF sy-subrc NE 0.
     MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
     WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

*依字段目錄產出參考目錄

CLEAR lt_alv_cat.
LOOP AT lt_table ASSIGNING FIELD-SYMBOL(<fs_table>).
   ls_alv_cat-fieldname = ls_alv_cat-ref_field = <fs_table>-fieldname.
   ls_alv_cat-ref_table = p_tab_n.
   APPEND ls_alv_cat TO lt_alv_cat.
   CLEAR: <fs_table>,ls_alv_cat.
ENDLOOP.
UNASSIGN <fs_table>.


CALL METHOD cl_alv_table_create=>create_dynamic_table
  EXPORTING
    it_fieldcatalog           = lt_alv_cat

  IMPORTING
    ep_table                  = d_ref.

  IF sy-subrc NE 0.
     MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
     WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ASSIGN d_ref->* TO <dyn_table>.
ASSIGN d_ref TO <dyn_tmp_struc>.

ENDFORM.
*&---------------------------------------------------------------------*
*&      Form  excel_upload
*&---------------------------------------------------------------------*
*& Begin Date  : 2021/02/02
*& Author      : Kevin Yu
*& Description : 將 Excel data 從本地端傳至宣告的 Table 中
*----------------------------------------------------------------------*
*& Version     :
*----------------------------------------------------------------------*
FORM excel_upload TABLES table.

 DATA: lt_data_in_file TYPE TABLE OF          zalsmex_tabline,
       ls_data_in_file TYPE                   zalsmex_tabline,
       lv_count        TYPE i,
       lv_count_2      TYPE i.
DATA truxs_t_text_data(4096) TYPE c OCCURS 0. "不影響回傳資料,僅因 FUNCTION 需求而設
"DATA: gt_data         TYPE alsmex_tabline OCCURS 0 WITH HEADER LINE."不影響回傳資料,僅因 FUNCTION 需求而設

CLEAR table.
CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
    EXPORTING
*     I_FIELD_SEPERATOR          =
      i_line_header              =  'X'
      i_tab_raw_data             =  truxs_t_text_data
      i_filename                 =  p_infile
    TABLES
      i_tab_converted_data       =  table
   EXCEPTIONS
     conversion_failed          = 1
     OTHERS                     = 2
            .
  IF sy-subrc NE 0.
     MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
     WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  display_data
*&---------------------------------------------------------------------*
*& Begin Date  : 2021/02/02
*& Author      : Kevin Yu
*& Description : 呈現 Excel 上傳至 table 中的資料 --OO ALV
*----------------------------------------------------------------------*
*& Version     :
*----------------------------------------------------------------------*
FORM display_data USING table.



"如要再 PAI 做 OO ALV 跳轉時,要REFRESH ALV 物件及 GUI
" refresh_table_display & SAPGUI_SET_FUNCTIONCODE
   IF grid1 IS INITIAL.
           g_custom_container       = NEW cl_gui_custom_container( g_container ).
           grid1                    = NEW cl_gui_alv_grid( g_custom_container  ).
           CALL METHOD grid1->set_table_for_first_display
               EXPORTING i_structure_name = p_tab_n
                         is_print         = gs_print
                         is_layout        = gs_layout
               CHANGING  it_outtab        = table.

           CALL METHOD grid1->refresh_table_display
              EXCEPTIONS
                 finished = 1
                 OTHERS   = 2.

    ELSE.
        CALL METHOD grid1->set_table_for_first_display
               EXPORTING i_structure_name = p_tab_n
                         is_print         = gs_print
                         is_layout        = gs_layout
               CHANGING  it_outtab        = table.

        CALL METHOD grid1->refresh_table_display
              EXCEPTIONS
                 finished = 1
                 OTHERS   = 2.

    ENDIF.
        IF sy-subrc <> 0.
* Implement suitable error handling here
    ENDIF.

CALL FUNCTION 'SAPGUI_SET_FUNCTIONCODE' " 人為觸發 PBO
           EXPORTING
             functioncode           = 'REFRESH'
           EXCEPTIONS
             function_not_supported = 1
             OTHERS                 = 2.

ENDFORM.
*&---------------------------------------------------------------------*
*& Module PBO OUTPUT
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
MODULE pbo OUTPUT.
  SET PF-STATUS 'STANDARD'.
  IF gv_noinput EQ cl_abap_typedescr=>true.
   ASSIGN '1200' TO <gv_screen_no>.
  ELSE.
   ASSIGN '1100' TO <gv_screen_no>.
  ENDIF.
  CHECK grid1 IS NOT INITIAL.
*  IF  gv_modify EQ 'X'.
*    PERFORM alv_modify.
*  ENDIF.
  CALL METHOD grid1->refresh_table_display
  EXCEPTIONS
  finished = 1
  OTHERS   = 2.

ENDMODULE.
*&---------------------------------------------------------------------*
*&      Module  PAI  INPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
MODULE pai INPUT.

"CALL METHOD cl_gui_cfw=>dispatch. "人為觸發 PAI
  CLEAR gv_noinput.
 CASE ok_code.

    WHEN  'ENDE' OR 'ECAN'.
      PERFORM exit_program.
    WHEN  'EXE' OR 'ONLI' .
     PERFORM authorization_check.
    WHEN  'GET'.
      PERFORM exit_program.
    WHEN  'E'.
      IF gs_layout-edit EQ cl_abap_typedescr=>true. "'X'.
      gs_layout-edit = cl_abap_typedescr=>false.
      PERFORM authorization_check.
      ENDIF.
    WHEN  'CHANGE_MODE'.
      CHECK grid1 IS NOT INITIAL.
      gv_noinput = cl_abap_typedescr=>true. "X"
      gv_modify  = cl_abap_typedescr=>true. "X"
      PERFORM alv_modify TABLES <dyn_table>.
    WHEN  'SPOS'.
    PERFORM alv_modify TABLES <dyn_table>.
    WHEN 'ENTRY_DATA'.
    PERFORM data_entry.

  ENDCASE.
  CLEAR ok_code.
ENDMODULE.
FORM exit_program.
* CALL METHOD G_CUSTOM_CONTAINER->FREE.
*  CALL METHOD CL_GUI_CFW=>FLUSH.
  LEAVE TO SCREEN 0.
ENDFORM.
*&---------------------------------------------------------------------*
*&      Form  alv_modify
*&---------------------------------------------------------------------*
*& Begin Date  : 2021/02/03
*& Author      : Kevin Yu
*& Description :
*----------------------------------------------------------------------*
*& Version     :
*----------------------------------------------------------------------*
FORM    alv_modify  TABLES pt_list .

IF gs_layout-edit = cl_abap_typedescr=>true.
   gs_layout-edit = cl_abap_typedescr=>false.
ELSE.
   gs_layout-edit = cl_abap_typedescr=>true.
ENDIF.

 CALL METHOD grid1->register_edit_event
    EXPORTING i_event_id = cl_gui_alv_grid=>mc_evt_enter.

 CALL METHOD grid1->set_table_for_first_display
               EXPORTING i_structure_name = p_tab_n
                         is_print         = gs_print
                         is_layout        = gs_layout
               CHANGING  it_outtab        = <dyn_table>.

 CALL METHOD grid1->refresh_table_display
              EXCEPTIONS
                 finished = 1
                 OTHERS   = 2.
ENDFORM.

首先為了使Selection Screen 與 ALV 呈現在相同介面
必須要先自製自己的 Screen,並將ALV 包入物件中,並使用Custom Control 來呈現 ALV 物件
https://ithelp.ithome.com.tw/upload/images/20210210/20135008RcKnUo20Ze.png
https://ithelp.ithome.com.tw/upload/images/20210210/20135008OyMxKsz5Jn.png

而為了使介面呈現Selection Screen 的部分,在PBO 及 PAI 皆要調用其作為subscreen,如此便可讓兩者同時
存在於同一畫面中
https://ithelp.ithome.com.tw/upload/images/20210210/201350089i4v15mM1F.png

而接著便是創建 ALV 相關物件
可參照程式TOP做宣告類型 ,運用宣告類型如下

g_container           TYPE scrfname VALUE 'ALV_P'
grid1                 TYPE REF TO cl_gui_alv_grid
gs_print              TYPE lvc_s_prnt
gs_layout             TYPE lvc_s_layo
g_custom_container    TYPE REF TO cl_gui_custom_container

物件創建如下

           g_custom_container       = NEW cl_gui_custom_container( g_container ).
           grid1                    = NEW cl_gui_alv_grid( g_custom_container  ).

準備好相關參數後接著調用 Method->set_table_for_first_display
便可在所設計的custom control 位置中呈現 alv

 CALL METHOD grid1->set_table_for_first_display
               EXPORTING i_structure_name = p_tab_n
                         is_print         = gs_print
                         is_layout        = gs_layout
               CHANGING  it_outtab        = <dyn_table>.

而其中要注意的便是 alv 刷新問題
通常在刷新 alv 會調用Method->refresh_table_display

 CALL METHOD grid1->refresh_table_display
              EXCEPTIONS
                 finished = 1
                 OTHERS   = 2.

然而因此範例並非再 PBO 處理,故要自行觸發PBO 刷新 GUI 介面

CALL FUNCTION 'SAPGUI_SET_FUNCTIONCODE' " 人為觸發 PBO
           EXPORTING
             functioncode           = 'REFRESH'
           EXCEPTIONS
             function_not_supported = 1
             OTHERS                 = 2.

至於其他細節就提供給各位看官自行研究啦~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言