目录
前言
一、data_changed 数据变更事件
核心能力与常用方法
(1)获取所有被修改过的单元格清单(pr_data->mt_mod_cells)
a. 是什么
b. 关键字段(最重要3个)
c. 作用
(2)取最新编辑值(pr_data->get_cell_value)
a. 是什么
b. 入参出参
c. 作用
(3)ALV 单元格级消息提示(add_protocol_entry)
a. 是什么
b. 示例代码
c. 参数详细说明
(4)标准函数检查字符串是否为数字
a. 是什么
b. 完整代码
c. 参数说明
二、data_changed_finished 数据变更事件
三、handle_hotspot_click 单击热点事件
a. 前置条件
b. 实现案例:
四、handle_onf4 自定义搜索帮助事件
a. 事件作用
b. 事件定义
c. 方法实现
五、handle_toolbar 工具栏定制事件
a. 事件作用
b. 动态工具栏按钮示例
c. 动态刷新工具栏
六、handle_user_command 用户功能码事件
a. 事件定位
b. 最佳实践
c. 实现案例
七、handle_double_click 双击事件
a. 事件作用
b. 参数说明
c. 代码示例
前言
在 OO ALV 开发中,CL_GUI_ALV_GRID基于 SAP Control Framework 采用「事件驱动 + 回调处理」的交互模式:用户在网格上执行编辑、点击、按钮触发等操作时,ALV 实例会抛出对应事件(如data_changed、 handle_modify、 hotspot_click),我们通过自定义事件接收类绑定处理方法,即可实现各类业务逻辑。
一、 data_changed 数据变更事件
用户修改单元格内容、回车 / 切走焦点后立刻触发(编辑过程中实时触发)。
CLASS lcl_event_receiver DEFINITION. PUBLIC SECTION. METHODS data_changed FOR EVENT data_changed OF cl_gui_alv_grid IMPORTING er_data_changed e_onf4 e_onf4_before e_onf4_after e_ucomm. ENDCLASS. "LCL_EVENT_RECEIVER DEFINITION * CLASS lcl_event_receiver IMPLEMENTATION * 定义方法 * ----------------------------------------------------------------------* CLASS lcl_event_receiver IMPLEMENTATION. METHOD data_changed. PERFORM handle_data_changed USING er_data_changed. ENDMETHOD. ENDCLASS. "LCL_EVENT_RECEIVER IMPLEMENTATION| 核心参数 | 说明 |
|---|---|
| er_data_changed | 变更协议对象,类型为CL_ALV_CHANGED_DATA_PROTOCOL,是所有校验操作的入口 |
| e_onf4 | 本次事件由 F4 搜索帮助触发时为ABAP_TRUE,可用于区分触发来源 |
| e_ucomm | 触发事件的功能码,例如回车对应ENTER |
核心能力与常用方法
(1)获取所有被修改过的单元格清单(pr_data->mt_mod_cells)
a. 是什么
系统标准内表 LVC_T_MODI,记录所有被修改的单元格明细,是遍历校验的数据源。
b. 关键字段(最重要3个)
- row_id:ALV 界面行唯一ID(关键定位字段)
- fieldname:被修改的字段名
- tabix:对应ALV内表真实行号
c. 作用
用于循环遍历所有改动单元格,性能高。
FORM handle_data_changed USING pr_data TYPE REF TO cl_alv_changed_data_protocol. LOOP AT pr_data->mt_mod_cells INTO DATA(ls_mod). "被修改单元格清单内表 * 逐行处理每个修改的字段 READ TABLE gt_alv ASSIGNING <gfs_alv> INDEX ls_mod-row_id. "ALV 界面行唯一ID IF sy-subrc = 0. ... ENDIF. ENDLOOP. ENDFORM.(2)取最新编辑值(pr_data->get_cell_value)
a. 是什么
ALV 标准方法,专门用来读取界面刚修改、还没刷新到内表的新值。
- 直接读取内表 → 获取旧值
- 调用 get_cell_value → 获取用户最新输入值
b. 入参出参
- i_row_id:mt_mod_cells-row_id
- i_fieldname:mt_mod_cells-fieldname
- e_value:返回界面最新输入值
" 单单元格取值 CALL METHOD pr_data->get_cell_value EXPORTING i_row_id = ls_mod-row_id i_fieldname = ls_mod-fieldname IMPORTING e_value = DATA(lv_new_value).c. 作用
ALV 回调事件中,主内表 gt_alv 里还是旧值!peri
只要在 DATA_CHANGED 事件里:
- 直接读内表 = 旧值
- 调用 get_cell_value = 用户刚输入的新值
与上面第一条中获取哪些单元格修改过搭配使用:
FORM handle_data_changed USING pr_data TYPE REF TO cl_alv_changed_data_protocol. LOOP AT pr_data->mt_mod_cells INTO DATA(ls_mod). * 逐行处理每个修改的字段 READ TABLE gt_alv ASSIGNING <gfs_alv> INDEX ls_mod-row_id. IF sy-subrc = 0. "封装写法 begin PERFORM sub_get_cell_data USING ls_mod-fieldname "被修改的字段名 pr_data "修改单元格清单 ls_mod-row_id "ALV 界面行唯一ID CHANGING lv_tsl. "用户修改的值 "封装写法 end ENDIF. ENDLOOP. ENDFORM. FORM sub_get_cell_data USING VALUE(p_value) pr_data TYPE REF TO cl_alv_changed_data_protocol VALUE(pv_id) CHANGING pc_value. CALL METHOD pr_data->get_cell_value EXPORTING i_row_id = pv_id i_fieldname = p_value IMPORTING e_value = pc_value. ENDFORM.(3)ALV 单元格级消息提示(add_protocol_entry)
a. 是什么
该方法是 CL_ALV_CHANGED_DATA_PROTOCOL 标准方法,专属 DATA_CHANGED 事件,用于给指定编辑单元格挂载单元格级警告/错误提示,精准定位报错位置。
b. 示例代码
CALL METHOD pr_data->add_protocol_entry EXPORTING i_msgid = '00' i_msgty = 'W' i_msgno = '001' i_msgv1 = '输入的批号已在工厂打印,请注意包号' i_fieldname = ls_mod-fieldname i_row_id = ls_mod-row_id.c. 参数详细说明
- i_msgid:消息类,00为系统通用基础消息类,搭配通用消息号可自定义文本
- i_msgty:消息类型,核心区分业务逻辑;W(Warning 黄色警告):仅提示,不拦截数据保存,可正常提交;E(Error 红色报错):单元格标红,强制拦截数据保存,必须修改后才能提交;I(信息提示):终止程序(ALV编辑场景几乎不用)
- i_msgno:消息编号,配合00通用消息类,用于承载自定义提示文本
- i_msgv1:自定义提示文案,界面最终展示给用户的提示内容
- i_fieldname:绑定报错字段,精准挂载到用户当前编辑的字段上
- i_row_id:绑定报错行,精准定位到用户当前编辑的ALV行
(4)标准函数检查字符串是否为数字
a. 是什么
该函数是SAP标准工具函数,用于清洗字符字段、校验纯数值内容,专门解决 CHAR 字段带空格、隐形字符、无法数值判断的问题
b. 完整代码
CALL FUNCTION 'IF_CA_MAKE_STRING_NUMERICAL' EXPORTING input_string = 【待校验字符串】 EXCEPTIONS not_numerical = 1. IF sy-subrc <> 0. " 包含非数字字符,校验不通过 ENDIF.c. 参数说明
- input_string:需要校验的字符型字段
- EXCEPTIONS-not_numerical:存在非数字内容时触发
- sy-subrc = 0:纯数字(含空格)合法
- sy-subrc = 1:非法字符,不是纯数字
注意❌:DATA_CHANGED 内禁止直接调用refresh_table_display,会导致事件递归触发引发程序 Dump,刷新操作请放到 DATA_CHANGED_FINISHED 中执行。
二、 data_changed_finished 数据变更事件
DATA_CHANGED_FINISHED 是 ALV 网格在用户完成所有单元格编辑后触发的事件,用于统一处理所有修改过的数据,常配合 ET_GOOD_CELLS 参数逐行检查并响应数据变更。
CLASS lcl_event_receiver DEFINITION. PUBLIC SECTION. CLASS-METHODS: handle_finished FOR EVENT data_changed_finished OF cl_gui_alv_grid IMPORTING e_modified et_good_cells. ENDCLASS. CLASS lcl_event_receiver IMPLEMENTATION. METHOD handle_finished. CHECK e_modified EQ abap_true."已修改 READ TABLE et_good_cells ASSIGNING FIELD-SYMBOL(<ls_cell>) INDEX 1. CHECK: sy-subrc EQ 0. READ TABLE gt_out ASSIGNING FIELD-SYMBOL(<ls_out>) INDEX <ls_cell>-row_id. ...数据处理逻辑 ENDMETHOD. ENDCLASS.| 核心参数 | 说明 |
|---|---|
| e_modified | 布尔值,本次操作是否有数据被修改 |
| et_good_cells | 校验通过的单元格清单,结构同mt_mod_cells |
| et_bad_cells | 校验不通过的单元格清单 |
这是项目中最常见的需求:用户输入物料号自动带出描述、单位,输入供应商自动带出名称,输入采购订单自动控制字段可编辑性。
三、 handle_hotspot_click 单击热点事件
a. 前置条件
字段目录中对应字段的hotspot属性需设为'X',字段会显示为蓝色带下划线的链接样式。
CLASS lcl_event_receiver DEFINITION. PUBLIC SECTION. CLASS-METHODS handle_hotspot_click FOR EVENT hotspot_click OF cl_gui_alv_grid IMPORTING e_row_id e_column_id es_row_no. ENDCLASS.| 参数名 | 类型 | 描述 |
|---|---|---|
e_row_id | int4 | 当前点击行的索引。 |
e_column_id | lvc_s_fcat | 一个包含当前点击列信息的结构。最常用的组件是e_column_id-fieldname,它包含了被点击字段的名称。 |
es_row_no | lvc_s_roid | 当前点击行的行信息结构。通常包含es_row_no-row_id用于读取内表中的行。 |
b. 实现案例:
METHOD handle_hotspot_click. " 转换为内表物理行号,兼容排序、筛选场景 DATA(lv_tabix) = go_alv->get_table_line_index( i_row_id = es_row_no-row_id ). CHECK lv_tabix > 0. READ TABLE gt_stock ASSIGNING FIELD-SYMBOL(<ls_stock>) INDEX lv_tabix. CHECK sy-subrc EQ 0. " 根据点击字段执行不同逻辑 CASE e_column_id-fieldname. WHEN 'EBELN'. " 采购单号跳转ME23N SET PARAMETER ID 'BES' FIELD <ls_stock>-ebeln. CALL TRANSACTION 'ME23N' AND SKIP FIRST SCREEN. WHEN 'MATNR'. " 物料号弹出详情 PERFORM frm_show_material_detail USING <ls_stock>-matnr. ENDCASE. ENDMETHOD.四、 handle_onf4 自定义搜索帮助事件
a. 事件作用
覆盖标准搜索帮助,实现自定义的取值逻辑,例如根据当前行物料限定可选批号范围。
b. 事件定义
CLASS lcl_event_receiver DEFINITION. PUBLIC SECTION. CLASS-METHODS handle_onf4 FOR EVENT onf4 OF cl_gui_alv_grid IMPORTING e_fieldname e_fieldvalue es_row_no er_event_data et_bad_cells e_display. ENDCLASS.c. 方法实现
METHOD handle_onf4. CASE e_fieldname. WHEN 'CHARG'. PERFORM frm_open_shlp_dialog USING es_row_no-row_id. ENDCASE. " 标记事件已处理,阻止标准搜索帮助叠加弹出 er_event_data->m_event_handled = abap_true. ENDMETHOD.五、 handle_toolbar 工具栏定制事件
a. 事件作用
ALV 工具栏渲染前触发,用于新增自定义按钮、隐藏标准按钮、动态控制按钮显隐。
按钮类型说明:
| butn_type 值 | 类型 | 说明 |
|---|---|---|
| 0 | 普通按钮 | 最常用,单击触发对应功能码 |
| 1 | 菜单按钮 | 带下拉箭头,可挂载子菜单 |
| 2 | 分隔线 | 垂直分隔线,用于按钮分组 |
| 3 | 空白分隔 | 空白占位,拉开按钮间距 |
b. 动态工具栏按钮示例
可以根据不同业务模式(新增 / 修改 / 删除 / 查询)动态显示不同按钮,也可以为分割成不同 alv 的屏幕设置工具按钮:
CLASS lcl_event_receiver DEFINITION. PUBLIC SECTION. CLASS-METHODS: "自定义 ALV 工具栏按钮 handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid IMPORTING sender e_object. ENDCLASS. CLASS lcl_event_receiver IMPLEMENTATION. "设置工具栏 METHOD handle_toolbar. " 移除本地标准按钮 DELETE e_object->mt_toolbar WHERE function CS |LOCAL|. DATA: ls_toolbar TYPE stb_button. CASE sender. WHEN go_alv1. "采购收货ALV1 专属按钮 APPEND VALUE stb_button( butn_type = 3 ) TO e_object->mt_toolbar. APPEND VALUE stb_button( function = 'CRE' text = TEXT-004 ) TO e_object->mt_toolbar. APPEND VALUE stb_button( function = 'DEL' text = TEXT-008 ) TO e_object->mt_toolbar. WHEN go_alv2. "生产投料ALV2 只显示保存 APPEND VALUE stb_button( butn_type = 3 ) TO e_object->mt_toolbar. APPEND VALUE stb_button( function = 'SAVE' text = TEXT-007 ) TO e_object->mt_toolbar. WHEN go_alv3. "生产入库ALV3 新增+导出 APPEND VALUE stb_button( butn_type = 3 ) TO e_object->mt_toolbar. APPEND VALUE stb_button( function = 'CRE' text = TEXT-004 ) TO e_object->mt_toolbar. APPEND VALUE stb_button( function = 'EXPORT' text = '导出入库数据' ) TO e_object->mt_toolbar. WHEN go_alv4. "销售出库ALV4 仅查询按钮 APPEND VALUE stb_button( butn_type = 3 ) TO e_object->mt_toolbar. APPEND VALUE stb_button( function = 'QUERY' text = '重新查询出库' ) TO e_object->mt_toolbar. ENDCASE. ENDMETHOD. ENDCLASS.c.为 ALV 绑定 toolbar 事件
CREATE OBJECT go_alv1 EXPORTING i_parent = go_cc_alv1. SET HANDLER lcl_event_receiver=>handle_toolbar FOR go_alv1.d. 动态刷新工具栏
运行中切换模式时,调用以下方法可重新触发 toolbar 事件,更新按钮状态:
go_alv->set_toolbar_interactive( ).六、 handle_user_command 用户功能码事件
a. 事件定位
所有自定义工具栏按钮的点击逻辑都在此事件中处理,替代传统列表 ALV 的 AT USER-COMMAND 块。
b. 最佳实践
方法开头必须调用check_changed_data( ),强制将界面上未回车的编辑值同步到内表,避免用户改完数据直接点按钮导致修改丢失。
c. 实现案例
METHOD handle_user_command. " 强制同步界面未保存的编辑数据,核心最佳实践 DATA(lv_valid) = go_alv->check_changed_data( ). IF lv_valid = abap_false. MESSAGE '数据校验不通过,请修正红色单元格后再操作' TYPE 'E'. ENDIF. " 处理行选中标记 PERFORM frm_mark_selection USING 01. CASE e_ucomm. WHEN 'CRE'. PERFORM frm_create. WHEN 'DEL'. PERFORM frm_delete. WHEN 'SAVE'. PERFORM frm_check. " 数据业务校验 PERFORM frm_save. " 数据保存 WHEN 'PRINT'. PERFORM frm_print_function. ENDCASE. go_alv->refresh_table_display( is_stable = VALUE lvc_s_stbl( row = abap_true col = abap_true ) ). PERFORM frm_mark_selection USING 10. ENDMETHOD.七、 handle_double_click 双击事件
a. 事件作用
用户双击任意单元格时触发,常用于行级详情查看、事务跳转。与热点点击的选型区别:
- 热点点击:单击触发,仅作用于指定字段,适合单据号跳转
- 双击事件:双击触发,作用于整行任意位置,适合查看行详情
b. 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
sender | TYPE REF TO cl_gui_alv_grid | 触发事件的ALV对象。通过此参数可以判断双击发生在哪一个ALV中 |
es_row_no | lvc_s_roid | 包含用户双击行的行ID。后续方法使用es_row_no-row_id从内表中读取对应行的数据 |
c. 代码示例
CLASS lcl_event_receiver DEFINITION. PUBLIC SECTION. CLASS-METHODS: handle_double_click FOR EVENT double_click OF cl_gui_alv_grid IMPORTING sender es_row_no. ENDCLASS. CLASS lcl_event_receiver IMPLEMENTATION. METHOD handle_double_click. IF sender = go_alv1. PERFORM frm_alv1_link_alv2 USING es_row_no. ELSEIF sender = go_alv2. PERFORM frm_alv2_link_alv3 USING es_row_no. ELSEIF sender = go_alv3. PERFORM frm_alv3_link_alv4 USING es_row_no. ENDIF. ENDMETHOD. ENDCLASS.写的不完善的地方请多包容,欢迎指正
本文会持续补充更新~