用RTTI实现动态可维护ALV表的DEMO( A Demo with RTTI and dynamic ABAP )

ABAP为动态编程提供了RTTI技术,我们可以通过一系列descriptor获取DDIC对象的属性,也能通过这些属性创建DDIC对象。根据这个特性,我们就可以根据输入的透明表名,动态地生成可编辑地ALV。

ABAP offers RTTI technology for dynamic programing, we can use a series of descriptor to get the attributes of DDIC objects and also can use those attributes to create DDIC objects. With this character, we can generate a editable ALV through a transparent table’s name.

 

输入界面,动态地输入表名。如果我们希望筛选数据,则可以用下面的按钮动态地生成筛选条件。

In input Screen, we need to enter the table name we want to maintain. If we need extra filter function, we could click the “Filter records” button which could generate a filter dynamically.

 

比如,我们输入的表名是图书在库情报,那么就会动态生成图书在库情报的筛选条件。

For example, we could enter a table name like “Library Storage Records”, then the program generate the filter dynamically.

 

生成效果示例(同样是图书在库情报)。

The data what we will get could be like this( which are the storage records ).

 

事务代码SE16可以看到数据已成功维护进了透明表。

With transaction SE16, we can see if the data are maintained successfully.

代码如下:

(注意: 本程序使用了自定义的pf_status,如果其他人希望本程序运行,需要在自己的pf_status中增加&SAVE, &ADD, &DEL等按钮 )

Here are the codes:

( Notice: this program uses a customizing pf_status, that if you want to run this program, you need to add command like &SAVE, &ADD, &DEL into your own pf_status )

*&---------------------------------------------------------------------*
*& Report ZYREPO1_PREPARE
*&---------------------------------------------------------------------*
*& ID: ZZ06AF
*&---------------------------------------------------------------------*
REPORT zyrepo1_prepare.

TABLES:
  dd02l, "Table Names
  dd03l. "Table Fields

DATA:
  g_flag   TYPE i VALUE 0,
  lr_table TYPE REF TO data,
  lr_tab01 TYPE REF TO data,
  lr_str01 TYPE REF TO data,
  lo_table TYPE REF TO cl_abap_tabledescr, "Source table descr
  lo_tab01 TYPE REF TO cl_abap_tabledescr, "Target table descr
  lo_struc TYPE REF TO cl_abap_structdescr, "Source structure descr
  lo_str01 TYPE REF TO cl_abap_structdescr. "Target Structure descr

DATA:
  lt_list TYPE ddfields,          "field list
  wa_list LIKE LINE OF lt_list,   "components
  lt_comp TYPE abap_component_tab.

FIELD-SYMBOLS:
  <ft_table> TYPE STANDARD TABLE,
  <ft_tab01> TYPE STANDARD TABLE,
  <fs_line>  TYPE any,
  <fs_field> TYPE any.

DATA:
  gt_fieldcat TYPE lvc_t_fcat,
  gs_fieldcat TYPE lvc_s_fcat,
  gs_layout   TYPE lvc_s_layo.

DATA:
  lv_selection_id  TYPE rsdynsel-selid,
  lt_tables_tab    TYPE STANDARD TABLE OF rsdstabs,
  ls_tables_tab    TYPE rsdstabs,
  lt_fields_tab    TYPE STANDARD TABLE OF rsdsfields,
  lt_where_clauses TYPE rsds_twhere,
  wa_where_clauses LIKE LINE OF lt_where_clauses,
  lt_lines         TYPE rsds_where_tab,
  wa_lines         TYPE rsdswhere,
  l_where_string   TYPE string.

DATA:
  ex_root              TYPE REF TO cx_root,
  ex_create_data_error TYPE REF TO cx_sy_create_data_error.

SELECTION-SCREEN BEGIN OF BLOCK b1.

PARAMETERS:
  p_tabnam TYPE dd02l-tabname OBLIGATORY.

SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN PUSHBUTTON 5(20) p_flt USER-COMMAND flt.
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN END OF BLOCK b1.

INITIALIZATION.
  p_flt = '@4G@ Filter records'.
  PERFORM refresh_tables.

AT SELECTION-SCREEN.
  PERFORM table_check.
  IF sy-ucomm = 'FLT'.
    PERFORM free_selections.
  ENDIF.

START-OF-SELECTION.
  TRY.
      PERFORM get_tab_info.
      PERFORM set_fieldcat.
      PERFORM show_alv.

      "When we catch an exception, deal with it
    CATCH cx_sy_create_data_error INTO ex_create_data_error.
      MESSAGE 'The Table Doesn''t Exist' TYPE 'S' DISPLAY LIKE 'E'.
      LEAVE LIST-PROCESSING.
    CATCH cx_root INTO ex_root.
      MESSAGE 'Other Exceptions' TYPE 'S' DISPLAY LIKE 'E'.
      LEAVE LIST-PROCESSING.
  ENDTRY.

FORM refresh_tables.
  REFRESH:
    lt_list,
    lt_comp,
    gt_fieldcat,
    lt_tables_tab,
    lt_fields_tab,
    lt_where_clauses,
    lt_lines.

  CLEAR:
    wa_list,
    gs_fieldcat,
    gs_layout,
    ls_tables_tab,
    wa_where_clauses,
    wa_lines,
    l_where_string.

ENDFORM.

FORM table_check.
  "Only customizing table are allowed to be modified for security
  IF p_tabnam IS NOT INITIAL AND p_tabnam+0(1) <> 'Z'.
    MESSAGE 'Please input a customizing table' TYPE 'I' DISPLAY LIKE 'E'.
    LEAVE PROGRAM.
  ELSE.

    "This program only can process transparent table
    SELECT COUNT(*)
      FROM dd02l
      WHERE tabname = p_tabnam
        AND tabclass = 'TRANSP'.

    IF sy-subrc = 0.
    ELSEIF sy-subrc = 4.
      MESSAGE 'Please choose a transparent table' TYPE 'I' DISPLAY LIKE 'E'.
      LEAVE PROGRAM.
    ELSE.
      MESSAGE 'SQL Exceptions' TYPE 'I' DISPLAY LIKE 'E'.
      LEAVE PROGRAM.
    ENDIF.

  ENDIF.
ENDFORM.

FORM free_selections.

  ls_tables_tab-prim_tab = p_tabnam.
  APPEND ls_tables_tab TO lt_tables_tab.

  CALL FUNCTION 'FREE_SELECTIONS_INIT'
    EXPORTING
      kind                     = 'T'
    IMPORTING
      selection_id             = lv_selection_id
    TABLES
      tables_tab               = lt_tables_tab
    EXCEPTIONS
      fields_incomplete        = 1
      fields_no_join           = 2
      field_not_found          = 3
      no_tables                = 4
      table_not_found          = 5
      expression_not_supported = 6
      incorrect_expression     = 7
      illegal_kind             = 8
      area_not_found           = 9
      inconsistent_area        = 10
      kind_f_no_fields_left    = 11
      kind_f_no_fields         = 12
      too_many_fields          = 13
      dup_field                = 14
      field_no_type            = 15
      field_ill_type           = 16
      dup_event_field          = 17
      node_not_in_ldb          = 18
      area_no_field            = 19
      OTHERS                   = 20.

  IF sy-subrc = 0.
    CALL FUNCTION 'FREE_SELECTIONS_DIALOG'
      EXPORTING
        selection_id    = lv_selection_id
        title           = 'Data Filter'
        frame_text      = 'Select Conditions'
        as_window       = 'X'                "不显示成窗口
      IMPORTING
        where_clauses   = lt_where_clauses[]  "返回选择条件
      TABLES
        fields_tab      = lt_fields_tab     "选择画面中选中字段
      EXCEPTIONS
        internal_error  = 1
        no_action       = 2
        selid_not_found = 3
        illegal_status  = 4
        OTHERS          = 5.

    IF sy-subrc = 0.

      IF lt_where_clauses[] IS NOT INITIAL.

        LOOP AT lt_where_clauses INTO wa_where_clauses.

          lt_lines = wa_where_clauses-where_tab.

          LOOP AT lt_lines INTO wa_lines.

            CONCATENATE l_where_string wa_lines-line INTO l_where_string SEPARATED BY ' '.

          ENDLOOP.

        ENDLOOP.

      ENDIF.

    ELSE.
      MESSAGE 'Free Selections Problem' TYPE 'I' DISPLAY LIKE 'E'.
      LEAVE PROGRAM.
    ENDIF.

  ELSE.
    MESSAGE 'Free Selections Problem' TYPE 'I' DISPLAY LIKE 'E'.
    LEAVE PROGRAM.
  ENDIF.

ENDFORM.

FORM get_tab_info RAISING cx_sy_create_data_error.

  "If the table doesn't exist
  "we need to throw the exception to main table
  TRY.
      "Create source table
      CREATE DATA lr_table TYPE TABLE OF (p_tabnam).
      ASSIGN lr_table->* TO <ft_table>.
    CATCH cx_sy_create_data_error INTO ex_create_data_error.
      RAISE EXCEPTION TYPE cx_sy_create_data_error.
  ENDTRY.

  "Fill source table if value exist
  IF l_where_string IS INITIAL.
    SELECT *
      FROM (p_tabnam)
      INTO CORRESPONDING FIELDS OF TABLE <ft_table>.
  ELSE.
    SELECT *
      FROM (p_tabnam)
      INTO CORRESPONDING FIELDS OF TABLE <ft_table>
    WHERE (l_where_string).
  ENDIF.

  IF sy-subrc = 0 OR
     sy-subrc = 4.  "SQL result

    "Get structure, field, component info from source table
    lo_table ?= cl_abap_typedescr=>describe_by_data( <ft_table> ).
    lo_struc ?= lo_table->get_table_line_type( ).
    lt_list = lo_struc->get_ddic_field_list( ).
    lt_comp = lo_struc->get_components( ).

    "Create target table
    lo_tab01 = cl_abap_tabledescr=>create( p_line_type = lo_struc ).
    CREATE DATA lr_tab01 TYPE HANDLE lo_tab01.
    ASSIGN lr_tab01->* TO <ft_tab01>.

    "Assign records from source table to target table
    IF lines( <ft_table> ) > 0.

      LOOP AT <ft_table> ASSIGNING <fs_line>.

        APPEND <fs_line> TO <ft_tab01>.

      ENDLOOP.

    ENDIF.

    "Give an extra void line to target table
    lo_str01 = cl_abap_structdescr=>create( lt_comp ).
    CREATE DATA lr_str01 TYPE HANDLE lo_str01.
    ASSIGN lr_str01->* TO <fs_line>.
    APPEND <fs_line> TO <ft_tab01>.

  ELSE.

    MESSAGE 'SQL Exceptions' TYPE 'S' DISPLAY LIKE 'E'.
    LEAVE LIST-PROCESSING.

  ENDIF."SQL Result

ENDFORM.

FORM set_fieldcat.

  "Generate fieldcat dynamically
  IF lt_list IS NOT INITIAL.

    LOOP AT lt_list INTO wa_list.
      gs_fieldcat-fieldname = wa_list-fieldname.
      gs_fieldcat-seltext = wa_list-fieldtext.
      gs_fieldcat-coltext = gs_fieldcat-seltext.
      gs_fieldcat-col_opt = 'X'.
      gs_fieldcat-edit = 'X'.
      APPEND gs_fieldcat TO gt_fieldcat.
      CLEAR gs_fieldcat.
    ENDLOOP.

  ENDIF.

ENDFORM.

FORM show_alv.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_callback_program       = sy-repid
      is_layout_lvc            = gs_layout
      it_fieldcat_lvc          = gt_fieldcat[]
      i_callback_user_command  = 'ALV_COMMAND'
      i_callback_pf_status_set = 'ALV_PF_STATUS'
      i_save                   = 'A'
      "i_grid_title             = g_title
      "it_sort_lvc              = gt_sort[]
      "it_events                = gt_events[]
    TABLES
      t_outtab                 = <ft_tab01>
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.


ENDFORM.

FORM alv_pf_status USING rt_extab TYPE slis_t_extab.

  DATA:
    fcode LIKE LINE OF rt_extab.

  "Customizing pf_status
  SET PF-STATUS 'PF_STATUS1' EXCLUDING rt_extab.

ENDFORM.

FORM alv_command
    USING ucomm LIKE sy-ucomm
        selfield TYPE slis_selfield.

  DATA:
    ref_grid    TYPE REF TO cl_gui_alv_grid,
    lt_filtered TYPE lvc_t_fidx,
    stbl        TYPE lvc_s_stbl,
    l_index     LIKE LINE OF lt_filtered.

  "Get ALV grid
  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
    IMPORTING
      e_grid = ref_grid.

  CALL METHOD ref_grid->check_changed_data.

  "React to command
  CASE ucomm.
    WHEN '&SAVE'.
      PERFORM save_data.
    WHEN '&ADD'.
      PERFORM add_line.
    WHEN '&DEL'.
      PERFORM del_line USING selfield-tabindex.
  ENDCASE.

  "Refresh
  IF ref_grid IS NOT INITIAL.

    CALL METHOD ref_grid->check_changed_data.

    stbl-row = 'X'.
    stbl-col = 'X'.
    CALL METHOD ref_grid->refresh_table_display
      EXPORTING
        is_stable = stbl.

  ENDIF.

ENDFORM.

FORM save_data.

  DATA:
    l_success TYPE i VALUE 0.

  LOOP AT <ft_tab01> ASSIGNING <fs_line>.

    IF <fs_line> IS NOT INITIAL.
      MODIFY (p_tabnam)
        FROM <fs_line>.
      IF sy-subrc = 0.

      ELSE.
        l_success = sy-subrc.
        EXIT.
      ENDIF.
    ENDIF.

  ENDLOOP.

  IF l_success = 0.
    COMMIT WORK AND WAIT.
    MESSAGE 'Update Successed' TYPE 'S'.
  ELSE.
    ROLLBACK WORK.
    MESSAGE 'Update Failed, Rollback Already' TYPE 'S' DISPLAY LIKE 'E'.
  ENDIF.

ENDFORM.

FORM add_line.

  ASSIGN lr_str01->* TO <fs_line>.
  APPEND <fs_line> TO <ft_tab01>.

ENDFORM.

FORM del_line USING tab_index.

  READ TABLE <ft_tab01> ASSIGNING <fs_line> INDEX tab_index.
  DELETE (p_tabnam) FROM <fs_line>.
  DELETE <ft_tab01> INDEX tab_index.

ENDFORM.

原文地址:https://www.cnblogs.com/Intercalaryland/p/12036270.html