ALV 그리드 셀에서 F4(검색도움) 키를 누르면 보통 SAP 가 기본 도움말을 띄웁니다. 그런데 내가 직접 만든 커스텀 도움말 팝업을 ALV 셀에서 띄우고 싶을 때 쓰는 이벤트가 ON_F4 입니다. 셀렉션 스크린의 F4 매크로(F4IF_INT_TABLE_VALUE_REQUEST) 와는 다른 ALV 전용 이벤트입니다.
핵심 메커니즘은 3단계입니다. Field Catalog 에서 F4 가능 표시(f4availabl) → register_f4_for_fields 로 어떤 컬럼에 ON_F4 를 걸지 등록 → ON_F4 이벤트 핸들러에서 도움말 팝업 호출. 마지막에 m_event_handled = abap_true 로 "내가 처리했다" 표시까지 해야 SAP 가 기본 도움말을 추가로 띄우지 않습니다.
이 글에서는 이벤트 등록 → 컬럼 F4 활성화 → 도움말 팝업 호출 → 선택값 반영까지 정리합니다. 데이터는 SAP 스탠다드 학습 환경 테이블 SFLIGHT + 플랜트 검색용 컬럼 예시.
핵심 — ON_F4 3단계 메커니즘
| 단계 | 설정 | 의미 |
|---|---|---|
| 1 | Field Catalog f4availabl = abap_true |
해당 컬럼에 F4 아이콘 표시 (도움말 가능 표시) |
| 2 | register_f4_for_fields(it_f4) |
그 컬럼에서 F4 누를 때 표준 도움말이 아니라 ON_F4 이벤트 가 발생하도록 등록 |
| 3 | handle_on_f4 핸들러 |
도움말 팝업 호출 + 선택값을 셀에 반영 + m_event_handled = abap_true |
흐름을 그림으로 정리하면:
fcat: f4availabl = abap_true (해당 컬럼에 F4 아이콘)
↓
register_f4_for_fields (F4 누름 → ON_F4 이벤트 발생)
↓
사용자가 셀에서 F4 누름
↓
ON_F4 이벤트 → e_fieldname / es_row_no / er_event_data
↓
HELP_VALUES_GET_WITH_TABLE_EXT (도움말 팝업)
↓
사용자가 값 선택
↓
선택값 → gt_data 에 반영 + DYNP_VALUES_UPDATE 화면 갱신
↓
er_event_data->m_event_handled = abap_true (★ 표준 도움말 안 뜨게)
3번의 m_event_handled = abap_true 가 빠지면 내 도움말이 뜬 뒤 SAP 기본 도움말이 또 한 번 뜨는 이상 동작이 나옵니다. 반드시 표시해 줘야 합니다.
1단계 — 전역 선언 + 이벤트 핸들러 클래스
ON_F4 이벤트와 도움말 팝업(HELP_VALUES_GET_WITH_TABLE_EXT) 호출에 필요한 데이터를 모두 선언합니다.
* ALV F4 등록 테이블
DATA: gt_f4_help TYPE lvc_t_f4,
gs_f4_help TYPE lvc_s_f4.
* 도움말 팝업에 넘길 itab
DATA: gt_fieldtab TYPE TABLE OF help_value, " 보여줄 필드 정의
gt_help_vtab TYPE TABLE OF help_vtab, " 사용자가 선택한 결과
gt_valuetab TYPE TABLE OF help_vtab. " 도움말에 표시할 값들
이벤트 핸들러 클래스의 시그니처는 다음과 같습니다.
CLASS lcl_event DEFINITION.
PUBLIC SECTION.
METHODS handle_on_f4
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.
CLASS lcl_event IMPLEMENTATION.
METHOD handle_on_f4.
PERFORM on_f4 USING e_fieldname e_fieldvalue es_row_no
er_event_data et_bad_cells e_display.
ENDMETHOD.
ENDCLASS.
ONF4 이벤트의 핵심 인자는 다음과 같습니다.
| 인자 | 의미 |
|---|---|
e_fieldname |
F4 가 눌린 컬럼 이름 |
es_row_no |
F4 가 눌린 행 정보 (row_id 로 인덱스 접근) |
er_event_data |
cl_alv_event_data 참조. m_event_handled = abap_true 표시용 |
e_fieldvalue · et_bad_cells · e_display |
현재 값 / 잘못된 셀 / 표시 모드 여부 (필요 시 사용) |
2단계 — Field Catalog: f4availabl = abap_true
F4 도움말을 쓸 컬럼에 f4availabl 을 켭니다. 이게 있어야 셀 옆에 F4 아이콘이 나타납니다.
FORM set_fcat.
DATA: lr_str TYPE REF TO cl_abap_structdescr.
lr_str ?= cl_abap_structdescr=>describe_by_data( gs_data ).
DATA(lt_fcat) = cl_salv_data_descr=>read_structdescr( lr_str ).
gt_fcat = CORRESPONDING #( lt_fcat MAPPING ref_table = reftable
ref_field = reffield ).
CALL FUNCTION 'LVC_FIELDCAT_COMPLETE'
CHANGING ct_fieldcat = gt_fcat.
LOOP AT gt_fcat INTO DATA(ls_fcat).
CASE ls_fcat-fieldname.
WHEN 'PLANT_CODE'. " F4 검색도움 쓸 컬럼
ls_fcat-f4availabl = abap_true.
ls_fcat-edit = abap_true. " 편집 가능해야 입력값 받음
ENDCASE.
MODIFY gt_fcat FROM ls_fcat.
ENDLOOP.
ENDFORM.
edit = abap_true 도 같이 켜야 선택된 값을 셀에 입력할 수 있습니다(읽기 전용 컬럼이면 도움말은 떠도 값이 안 들어갑니다).
3단계 — register_f4_for_fields: ON_F4 이벤트 등록
f4availabl 만 켜면 SAP 기본 도움말이 뜹니다. 내 ON_F4 이벤트를 발생시키려면 따로 register_f4_for_fields 로 등록해야 합니다.
FORM set_onf4.
CLEAR: gt_f4_help, gs_f4_help.
gs_f4_help-fieldname = 'PLANT_CODE'. " 등록할 컬럼
gs_f4_help-register = abap_true. " F4 가로채기
APPEND gs_f4_help TO gt_f4_help.
go_grid->register_f4_for_fields(
EXPORTING it_f4 = gt_f4_help ).
ENDFORM.
register = abap_true 가 곧 "이 컬럼의 F4 는 내가 가로채서 ON_F4 이벤트로 받겠다" 는 의미입니다. 이벤트 핸들러는 SET HANDLER 로 연결.
FORM set_event.
event_receiver = NEW #( ).
SET HANDLER event_receiver->handle_on_f4 FOR go_grid.
ENDFORM.
4단계 — ON_F4 핸들러: 도움말 팝업 호출
이벤트가 발생하면 e_fieldname 으로 어느 컬럼인지 분기하고, 표준 도움말 FM HELP_VALUES_GET_WITH_TABLE_EXT 로 팝업을 띄웁니다.
FORM on_f4 USING p_fieldname TYPE lvc_fname
p_fieldvalue TYPE lvc_value
p_row_no TYPE lvc_s_roid
p_event_data TYPE REF TO cl_alv_event_data
p_bad_cells TYPE lvc_t_modi
p_display TYPE char01.
READ TABLE gt_data INTO gs_data INDEX p_row_no-row_id.
CHECK sy-subrc = 0.
CASE p_fieldname.
WHEN 'PLANT_CODE'.
PERFORM f4_plant USING p_row_no-row_id.
ENDCASE.
* ★ "내가 처리했다" 표시 — 표준 F4 가 추가로 뜨지 않게
p_event_data->m_event_handled = abap_true.
PERFORM set_refresh.
ENDFORM.
플랜트 검색 FORM 은 보여줄 컬럼 정의(help_value) 와 값 목록(help_vtab) 을 준비한 뒤 도움말 FM 을 호출합니다.
FORM f4_plant USING p_row_id.
* 1) 도움말에 보여줄 필드 정의 (T001W 플랜트 마스터)
CLEAR: gt_fieldtab, gt_help_vtab.
APPEND VALUE #( tabname = 'T001W'
fieldname = 'WERKS'
selectflag = abap_true ) TO gt_fieldtab.
APPEND VALUE #( tabname = 'T001W'
fieldname = 'NAME1'
selectflag = abap_false ) TO gt_fieldtab.
* 2) 도움말에 표시할 값 목록 — T001W 에서 SELECT
DATA: lv_index TYPE i,
lt_t001w TYPE TABLE OF t001w.
CLEAR gt_valuetab.
SELECT werks, name1
FROM t001w
INTO TABLE @lt_t001w.
LOOP AT lt_t001w INTO DATA(ls_t001w).
APPEND VALUE #( value = ls_t001w-werks ) TO gt_valuetab.
APPEND VALUE #( value = ls_t001w-name1 ) TO gt_valuetab.
ENDLOOP.
* 3) 도움말 팝업 호출
CALL FUNCTION 'HELP_VALUES_GET_WITH_TABLE_EXT'
EXPORTING
display = ''
IMPORTING
index = lv_index
TABLES
fields = gt_fieldtab
select_values = gt_help_vtab
valuetab = gt_valuetab.
* 4) 사용자가 값을 선택한 경우 (lv_index > 0)
IF lv_index > 1.
READ TABLE gt_help_vtab INTO DATA(gs_help_vtab) INDEX 2.
CONDENSE gs_help_vtab-value NO-GAPS.
gs_data-plant_code = gs_help_vtab-value.
MODIFY gt_data FROM gs_data INDEX p_row_id
TRANSPORTING plant_code.
* 선택된 값을 현재 화면에도 즉시 반영
DATA(it_dyn_update) = VALUE dynpread_tabtype(
( fieldname = 'PLANT_CODE'
fieldvalue = gs_help_vtab-value ) ).
CALL FUNCTION 'DYNP_VALUES_UPDATE'
EXPORTING
dyname = sy-repid
dynumb = sy-dynnr
TABLES
dynpfields = it_dyn_update
EXCEPTIONS
OTHERS = 8.
ENDIF.
ENDFORM.
HELP_VALUES_GET_WITH_TABLE_EXT 의 index 가 0보다 크면 사용자가 값을 선택했다는 뜻입니다. 선택값은 gt_help_vtab 에 담겨 돌아오고, DYNP_VALUES_UPDATE 로 현재 화면 셀에도 즉시 반영합니다.
자주 빠뜨리는 함정
m_event_handled 미설정
er_event_data->m_event_handled = abap_true 를 빠뜨리면, 내 도움말 팝업이 뜬 뒤 SAP 기본 F4 도움말까지 한 번 더 뜹니다. 반드시 마지막에 설정.
register_f4_for_fields 미호출 — 표준 F4 만 뜸
f4availabl = abap_true 만 켜면 SAP 기본 도움말이 뜹니다. 내 ON_F4 이벤트로 받으려면 register_f4_for_fields 호출이 필수.
edit = abap_false 인 컬럼
편집 불가 컬럼에는 F4 가 떠도 값이 안 들어갑니다. edit = abap_true 같이 켜야 합니다. 편집 ALV 자체가 필요하면 set_ready_for_input(1) 도.
DYNP_VALUES_UPDATE 누락 — 화면이 안 바뀜
내부 테이블(gt_data) 만 바꾸면 화면 셀에는 즉시 반영이 안 됩니다. DYNP_VALUES_UPDATE 또는 refresh_table_display 로 화면 갱신을 강제해야 사용자에게 즉시 보입니다.
es_row_no-row_id 와 인덱스 혼동
es_row_no 구조의 row_id 가 내부 테이블 인덱스입니다. row_no 같은 다른 필드와 혼동하지 않도록 주의.
셀렉션 스크린 F4 와 혼동
셀렉션 스크린의 F4 도움말은 AT SELECTION-SCREEN ON VALUE-REQUEST FOR ... + F4IF_INT_TABLE_VALUE_REQUEST 패턴입니다. ALV 의 ON_F4 와는 다른 메커니즘이니 혼동하지 마세요.
전체 코드 — 복사용 통합본
아래는 SAP 스탠다드 모듈풀 구조에 맞춰 메인 + 6개 INCLUDE(T / C / SCR / O / I / F) 로 나눈 통합본입니다. SE38 에서 메인 프로그램과 각 INCLUDE 를 만들고, Screen 100 의 Layout 은 빈 상태로 두고 Flow Logic 에 status_0100 · set_alv (PBO) · user_command_0100 (PAI) 를 연결합니다. INCLUDE 는 T → C → SCR → O → I → F 순서로 로드됩니다.
*&---------------------------------------------------------------------*
*& Report ZRXX_ALV_ON_F4 (메인 프로그램)
*&---------------------------------------------------------------------*
REPORT zrxx_alv_on_f4.
INCLUDE zrxx_alv_on_f4_t. " TOP - 전역 선언
INCLUDE zrxx_alv_on_f4_c. " CLASS - 로컬 클래스
INCLUDE zrxx_alv_on_f4_scr. " SCR - 셀렉션 스크린
INCLUDE zrxx_alv_on_f4_o. " PBO - OUTPUT 모듈
INCLUDE zrxx_alv_on_f4_i. " PAI - INPUT 모듈
INCLUDE zrxx_alv_on_f4_f. " FORM - 서브루틴
START-OF-SELECTION.
SELECT * UP TO 20 ROWS
INTO CORRESPONDING FIELDS OF TABLE gt_data
FROM sflight.
CALL SCREEN 100.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_ON_F4_T (TOP - 전역 선언)
*&---------------------------------------------------------------------*
DATA: go_docking TYPE REF TO cl_gui_docking_container,
go_grid TYPE REF TO cl_gui_alv_grid.
DATA: ok_code TYPE sy-ucomm.
DATA: gs_layo TYPE lvc_s_layo,
gt_fcat TYPE lvc_t_fcat.
* SFLIGHT + 플랜트 검색용 컬럼
DATA: BEGIN OF gs_data.
INCLUDE STRUCTURE sflight.
DATA: plant_code TYPE werks_d, " ★ F4 검색도움 대상
END OF gs_data,
gt_data LIKE TABLE OF gs_data.
* ALV F4 등록 + 도움말 팝업용 itab
DATA: gt_f4_help TYPE lvc_t_f4,
gs_f4_help TYPE lvc_s_f4,
gt_fieldtab TYPE TABLE OF help_value,
gt_help_vtab TYPE TABLE OF help_vtab,
gt_valuetab TYPE TABLE OF help_vtab.
DATA event_receiver TYPE REF TO lcl_event. " C INCLUDE 의 클래스 참조
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_ON_F4_C (CLASS - 로컬 클래스)
*&---------------------------------------------------------------------*
CLASS lcl_event DEFINITION.
PUBLIC SECTION.
METHODS handle_on_f4
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.
CLASS lcl_event IMPLEMENTATION.
METHOD handle_on_f4.
PERFORM on_f4 USING e_fieldname e_fieldvalue es_row_no
er_event_data et_bad_cells e_display.
ENDMETHOD.
ENDCLASS.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_ON_F4_SCR (SCR - 셀렉션 스크린)
*&---------------------------------------------------------------------*
* 이 글은 셀렉션 스크린(SELECT-OPTIONS/PARAMETERS) 을 쓰지 않습니다.
* Screen 100 은 SE51 에서 정의 (Docking 사용, Custom Control 없음).
* 셀렉션 조건이 필요하면 여기에 SELECT-OPTIONS 를 선언.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_ON_F4_O (PBO - OUTPUT 모듈)
*&---------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
SET PF-STATUS 'S100'.
ENDMODULE.
MODULE set_alv OUTPUT.
IF go_docking IS INITIAL.
go_docking = NEW #( dynnr = sy-dynnr extension = 3000 ).
go_grid = NEW #( i_parent = go_docking ).
PERFORM set_fcat.
PERFORM set_event.
PERFORM set_onf4. " ★ ON_F4 등록
gs_layo-zebra = abap_true.
gs_layo-cwidth_opt = abap_true.
go_grid->set_ready_for_input( i_ready_for_input = 1 ).
go_grid->set_table_for_first_display(
EXPORTING
is_layout = gs_layo
CHANGING
it_outtab = gt_data
it_fieldcatalog = gt_fcat ).
ENDIF.
ENDMODULE.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_ON_F4_I (PAI - INPUT 모듈)
*&---------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
CASE ok_code.
WHEN 'BACK' OR 'EXIT' OR 'CANC'.
LEAVE TO SCREEN 0.
ENDCASE.
ENDMODULE.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_ON_F4_F (FORM - 서브루틴)
*&---------------------------------------------------------------------*
* Field Catalog — F4 가능 컬럼 표시
FORM set_fcat.
DATA: lr_str TYPE REF TO cl_abap_structdescr.
lr_str ?= cl_abap_structdescr=>describe_by_data( gs_data ).
DATA(lt_fcat) = cl_salv_data_descr=>read_structdescr( lr_str ).
gt_fcat = CORRESPONDING #( lt_fcat MAPPING ref_table = reftable
ref_field = reffield ).
CALL FUNCTION 'LVC_FIELDCAT_COMPLETE'
CHANGING ct_fieldcat = gt_fcat.
LOOP AT gt_fcat INTO DATA(ls_fcat).
CASE ls_fcat-fieldname.
WHEN 'PLANT_CODE'.
ls_fcat-f4availabl = abap_true. " ★ F4 아이콘 표시
ls_fcat-edit = abap_true.
ENDCASE.
MODIFY gt_fcat FROM ls_fcat.
ENDLOOP.
ENDFORM.
* 이벤트 등록
FORM set_event.
event_receiver = NEW #( ).
SET HANDLER event_receiver->handle_on_f4 FOR go_grid.
ENDFORM.
* ★ register_f4_for_fields — ON_F4 이벤트로 가로채기
FORM set_onf4.
CLEAR: gt_f4_help, gs_f4_help.
gs_f4_help-fieldname = 'PLANT_CODE'.
gs_f4_help-register = abap_true.
APPEND gs_f4_help TO gt_f4_help.
go_grid->register_f4_for_fields(
EXPORTING it_f4 = gt_f4_help ).
ENDFORM.
* ★ ON_F4 핸들러
FORM on_f4 USING p_fieldname TYPE lvc_fname
p_fieldvalue TYPE lvc_value
p_row_no TYPE lvc_s_roid
p_event_data TYPE REF TO cl_alv_event_data
p_bad_cells TYPE lvc_t_modi
p_display TYPE char01.
READ TABLE gt_data INTO gs_data INDEX p_row_no-row_id.
CHECK sy-subrc = 0.
CASE p_fieldname.
WHEN 'PLANT_CODE'.
PERFORM f4_plant USING p_row_no-row_id.
ENDCASE.
p_event_data->m_event_handled = abap_true. " ★ 표준 F4 차단
PERFORM set_refresh.
ENDFORM.
* 플랜트 검색 팝업
FORM f4_plant USING p_row_id.
CLEAR: gt_fieldtab, gt_help_vtab, gt_valuetab.
APPEND VALUE #( tabname = 'T001W'
fieldname = 'WERKS'
selectflag = abap_true ) TO gt_fieldtab.
APPEND VALUE #( tabname = 'T001W'
fieldname = 'NAME1'
selectflag = abap_false ) TO gt_fieldtab.
DATA: lv_index TYPE i,
lt_t001w TYPE TABLE OF t001w.
SELECT werks, name1
FROM t001w
INTO TABLE @lt_t001w.
LOOP AT lt_t001w INTO DATA(ls_t001w).
APPEND VALUE #( value = ls_t001w-werks ) TO gt_valuetab.
APPEND VALUE #( value = ls_t001w-name1 ) TO gt_valuetab.
ENDLOOP.
CALL FUNCTION 'HELP_VALUES_GET_WITH_TABLE_EXT'
EXPORTING
display = ''
IMPORTING
index = lv_index
TABLES
fields = gt_fieldtab
select_values = gt_help_vtab
valuetab = gt_valuetab.
IF lv_index > 1.
READ TABLE gt_help_vtab INTO DATA(gs_help_vtab) INDEX 2.
CONDENSE gs_help_vtab-value NO-GAPS.
gs_data-plant_code = gs_help_vtab-value.
MODIFY gt_data FROM gs_data INDEX p_row_id
TRANSPORTING plant_code.
DATA(it_dyn_update) = VALUE dynpread_tabtype(
( fieldname = 'PLANT_CODE' fieldvalue = gs_help_vtab-value ) ).
CALL FUNCTION 'DYNP_VALUES_UPDATE'
EXPORTING
dyname = sy-repid
dynumb = sy-dynnr
TABLES
dynpfields = it_dyn_update
EXCEPTIONS
OTHERS = 8.
ENDIF.
ENDFORM.
* 화면 갱신
FORM set_refresh.
go_grid->refresh_table_display(
EXPORTING is_stable = VALUE #( col = abap_true row = abap_true ) ).
ENDFORM.
요약
| 단계 | FORM | 핵심 |
|---|---|---|
| 1 | set_fcat |
f4availabl = abap_true + edit = abap_true |
| 2 | set_onf4 |
register_f4_for_fields 로 ON_F4 가로채기 |
| 3 | handle_on_f4 |
HELP_VALUES_GET_WITH_TABLE_EXT 팝업 호출 |
| 4 | 결과 반영 | 선택값 → gt_data + DYNP_VALUES_UPDATE + m_event_handled = abap_true |
ALV ON_F4 의 본질은 "해당 컬럼의 F4 키를 SAP 기본 도움말 대신 내 이벤트로 가로채기". f4availabl 로 아이콘을 표시하고, register_f4_for_fields 로 이벤트를 등록하면 끝입니다. 핸들러 안에서 도움말 팝업을 띄우고 선택값을 셀에 반영한 뒤, m_event_handled 표시만 잊지 않으면 자연스러운 ALV 커스텀 서치헬프가 완성됩니다. 셀렉션 스크린의 F4 매크로와는 메커니즘이 다르니 혼동하지 마세요.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.
CL_GUI_ALV_GRID 의 ONF4 이벤트 시그니처(e_fieldname·es_row_no·er_event_data·et_bad_cells·e_display) 와 register_f4_for_fields 메소드, HELP_VALUES_GET_WITH_TABLE_EXT·DYNP_VALUES_UPDATE FM 은 NetWeaver 스탠다드 정의(ECC 6.0 / S/4HANA on-premise 기준) 입니다. 적용 환경 버전에 따라 일부 차이가 있을 수 있으니 실제 적용 시 SE24 의 클래스 정의를 확인하시기 바랍니다. SFLIGHT · T001W 는 SAP 스탠다드 학습 환경(IDES) 테이블이라 운영 시스템에는 없을 수 있으니, 실무 적용 시 운영 테이블로 교체하시기 바랍니다.