ALV 对象注册事件

如果我们想处理 ALV Grid 实例触发的事件,我们应该定义并实现一个事件处理程序类。 创建 ALV Grid 实例后,我们必须注册此事件处理程序类的实例来处理 ALV Grid 事件。

(1) HANDLE_TOOLBAR:这个事件用于给 ALV 加自定义工具条按钮。

(2) HANDLE_CLICK:用于给 ALV 点击其中一行后处理代码段。

(3) HANDLE_COMMAND:事件用于接收用户按了自定义按钮后,触发的代码段。

(4) HANDLE_DOUBLE_CLICK:双击事件处理。

(5) DATA_CHANGED:可编辑字段的数据发生变化时触发,可用来检查数据的输入正确性。

(6) DATA_CHANGED_FINISHED:当数据修改完成后触发,数据没有被修改,当失去焦点或回车时触发。

(7) HANDLE_F4_HELP:F4 搜索帮助

事件类定义

CLASS lcl_event_receiver DEFINITION.
  PUBLIC SECTION.
    "声明单击事件的方法"
    METHODS handle_hotspot_click
      FOR EVENT hotspot_click OF cl_gui_alv_grid
      IMPORTING e_row_id e_column_id.
    "声明双击事件方法"
    METHODS handle_double_click
      FOR EVENT double_click OF cl_gui_alv_grid
      IMPORTING e_row e_column.
    "声明 Toolbar 事件方法"
    METHODS handle_toolbar
      FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING e_object e_interactive.
    "声明 USER-COMMAND 事件方法"
    METHODS handle_command
      FOR EVENT user_command OF cl_gui_alv_grid
      IMPORTING e_ucomm.
    "声明数据修改事件"
    METHODS handle_data_changed 
      FOR EVENT data_changed OF cl_gui_alv_grid
      IMPORTING er_data_changed e_onf4_before e_onf4_after e_ucomm.
    "F4 Help"
    METHODS handle_f4_help
      FOR EVENT onf4 OF cl_gui_alv_grid
      IMPORTING e_fieldname es_row_no er_event_data et_bad_cells e_display.
ENDCLASS.                    "cl_event_receiver DEFINITION"

事件类实现

CLASS lcl_event_receiver IMPLEMENTATION.
  "单击事件方法的实现"
  METHOD handle_hotspot_click.
    CONDENSE e_row_id     NO-GAPS.
    CONDENSE e_column_id  NO-GAPS.
    MESSAGE i001(00) WITH ' 单击事件 -> 行号:' e_row_id  '、列名:' e_column_id.
  ENDMETHOD.                    "handle_HOTSPOT_CLICK"
  "双击事件方法的实现"
  METHOD handle_double_click.
    CONDENSE e_row     NO-GAPS.
    CONDENSE e_column  NO-GAPS.
    MESSAGE i001(00) WITH ' 双击事件 -> 行号:' e_row  '、列名:' e_column.
  ENDMETHOD.                    "handle_double_click"
  "实现 Toolbar 事件方法"
  METHOD handle_toolbar.
    DATA: ls_toolbar TYPE stb_button.
    CLEAR: ls_toolbar.
    ls_toolbar-butn_type = 3.   "分隔符"
    APPEND ls_toolbar TO e_object->mt_toolbar.
    CLEAR: ls_toolbar.
    ls_toolbar-function = 'DISP'.    "功能码"
    ls_toolbar-icon = icon_display.  "图标名称"
    ls_toolbar-quickinfo = ' 显示'.   "图标的提示信息"
    ls_toolbar-butn_type = 0.        "0 表示正常按钮"
    ls_toolbar-disabled = ''.        "X 表示灰色,不可用"
    ls_toolbar-text = 'btn1'.      "按钮上显示的文本"
    APPEND ls_toolbar TO e_object->mt_toolbar.
  ENDMETHOD.                    "handle_toolbar"
  "实现 USER-COMMAND 事件方法"
  METHOD handle_command.
    CASE e_ucomm.
    WHEN 'DISP'.
       MESSAGE i001(00) WITH 'Toolbar 事件 + USER-COMMAND 事件 '.
    ENDCASE.
  ENDMETHOD.                    "HANDLE_COMMAND"
  "F4 Help"
  METHOD handle_f4_help.
    FIELD-SYMBOLS: <fs_alv> TYPE alv.
    CASE e_fieldname.
    WHEN 'XXXX'.
      READ TABLE alv assiging <fs_alv> INDEX es_row_no-row_id.
      IF sy-subrc = 0.
        PERFORM frm_get_f4_value CHANGING <fs_alv>-xxxx.
      ENDIF.
    ENDCASE.
    CALL METHOD go_grid->refresh_table_display.
  ENDMETHOD.
ENDCLASS.                    "cl_event_receiver IMPLEMENTATION"

注册事件

在创建 ALV GRID 实例后注册事件

CLASS lcl_event_receiver DEFINITION DEFERRED.
DATA event_receiver TYPE REF TO lcl_event_receiver.
CREATE OBJECT event_receiver. "创建事件"
"注册事件 handler 方法"
SET HANDLER event_receiver->handle_hotspot_click  FOR go_grid.
SET HANDLER event_receiver->handle_double_click   FOR go_grid.
SET HANDLER event_receiver->handle_toolbar        FOR go_grid.
SET HANDLER event_receiver->handle_command        FOR go_grid.
SET HANDLER event_receiver->handle_data_changed   FOR go_grid.
SET HANDLER event_receiver->handle_f4_help        FOR go_grid.

控制数据变化

ALV 提供给我们控制数据的输入,有两个事件:data_changeddata_changed_finished 。第一个事件在可编辑字段的数据发生变化时触发,可用来检查数据的输入;第二个事件是当数据修改完成后触发。

除了设置 FIELDCAT 的 EDIT 属性。还需要在显示 ALV 后添加触发数据改变事件,必须设置一种方式,否则不会触发数据更新事件。

CALL METHOD ALV_GRID->REGISTER_EDIT_EVENT
  EXPORTING
    I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_ENTER. 
CALL METHOD ALV_GRID->REGISTER_EDIT_EVENT
  EXPORTING
    I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVT_MODIFIED. 
  • I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVENT_ENTER.

    • 在单元格修改后回车或者执行其他操作时触发事件,此类型可用于多个单元格修改后一起检查修改的值
  • I_EVENT_ID = CL_GUI_ALV_GRID=>MC_EVENT_MODIFIES.

  • 当光标焦点移开被修改单元格后既触发事件,此类型可用于每个每个单元个的实时更新检查

获取 ALV 字段修改信息

为了获取 ALV 里字段修改的一些信息,DATA_CHANGED 事件会把参考CL_ALV_CHANGED_DATA_PROTOCOL 创建的实例通过参数 ER_DATA_CHANGED 传递给 ALV。通过该参数我们可以知道哪些单元格发生了变化。

  • 类 CL_ALV_CHANGED_DATA_PROTOCOL 的一些方法

    Methods Desc
    GET_CELL_VALUE 获取单元格值
    MODIFY_CELL 修改单元格
    ADD_PROTOCOL_ENTRY 增加日志记录
    PROTOCOL_IS_VISIBLE 是否允许错误表可见
    REFRESH_PROTOCOL 刷新日志记录
  • 类 CL_ALV_CHANGED_DATA_PROTOCOL 的一些属性

    Attributes Desc
    MT_MOD_CELLS 包含带有行和字段名称的已修改单元格的数据
    MT_MOD_ROWS 包含修改的行数据,类型是数字
    MT_GOOD_CELLS 包含当前单元格的值
    MT_DELETED_ROWS 包含从列表中删除的行
    MT_INSERTED_ROWS 包含列表中新插入的行

实现 DATA Change 事件方法

METHOD handle_data_changed.
  DATA: mod_data TYPE lvc_s_modi,  "Modify Row"
        ins_data TYPE lvc_s_moce,  "Insert Row"
        ls_output TYPE str_output,
        lv_menge  TYPE ekpo-netwr,
        lv_menge_ori TYPE ekpo-netwr.
  FIELD-SYMBOLS: <fs> TYPE table.
  
  SORT er_data_changed->mt_good_cells BY row_id.
  LOOP AT er_data_changed->mt_good_cells INTO mod_data.
    CLEAR: ls_output,lv_menge.
    IF mod_data-fieldname = 'NETWR'.
      READ TABLE gt_output INDEX mod_data-row_id INTO ls_output.
      IF sy-subrc = 0.
        CALL METHOD er_data_changed->get_cell_value
          EXPORTING
            i_row_id    = mod_data-row_id
            i_fieldname = mod_data-fieldname
          IMPORTING
            e_value     = lv_menge.
        ......
       lv_menge_ori = mod_data-value.
       CALL METHOD er_data_changed->add_protocol_entry
         EXPORTING
           i_msgid     = '00'
           i_msgty     = 'E'
           i_msgno     = '001'
           i_msgv1     = 'Data Format Error'
           i_msgv2     = lv_menge
           i_msgv3     = '.'
           i_fieldname = mod_data-fieldname.
        ......
        CALL METHOD er_data_changed->modify_cell
          EXPORTING
            i_row_id    = mod_data-row_id
            i_fieldname = mod_data-fieldname
            i_value     = lv_menge.
      ENDIF.
    ENDIF.
  ENDLOOP.
  LOOP AT er_data_changed->mt_inserted_rows INTO ins_data.
    ASSIGN er_data_changed->mt_mod_rows->* TO <fs>.
    LOOP AT <fs> INTO ls_outtab.
      ls_outtab-xxx = 'XX'.
      MODIFY <fs> FROM ls_outtab INDEX sy-tabix.
    ENDLOOP.
  ENDLOOP.
ENDMETHOD.

F4 Help

定义 fieldcat 属性

fieldcat-f4availabl = 'X'.
fieldcat-edit = 'X'.

F4 事件注册到 ALV

DATA: lt_f4 TYPE lvc_t_f4,
      ls_f4 TYPE lvc_s_f4.
CALL METHOD go_grid->set_table_for_first_display.
CLEAR: ls_f4.
ls_f4-fieldname = 'XXXX'.
ls_f4-register  = 'X'.
ls_f4-getbefore = 'X'.
ls_f4-chngeafter = ''.
ls_f4-internal = ''.
INSERT ls_f4 INTO TABLE lt_f4.

CALL METHOD go_grid->register_f4_for_fields
  EXPORTING
    it_f4 = lt_f4.

自定义 F4,获取数据

FORM frm_get_f4_value USING i_matnr TYPE xxx
                      CHANGING e_value TYPE xxx.
  DATA: value_tab TYPE TABLE OF xxxx WITH HEADER LINE.
  DATA: lt_ret_tab TYPE TABLE OF ddshretval WITH HEADER LINE.
  CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
    EXPORTING
      retfield        = 'SUB_NAME_M'
      value_org       = 'S'
    TABLES
      value_tab       = value_tab
      return_tab      = lt_ret_tab
    EXCEPTIONS
      parameter_error = 1
      no_values_fount = 2
      others          = 3.
  IF sy-subrc = 0.
    READ TABLE lt_ret_tab INDEX 1.
    IF sy-subrc = 0 AND lt_ret_tab-fieldval IS NOT INITIAL.
      e_value = lt_ret_tab-fieldval.
    ENDIF.
  ENDIF.
ENDFORM.