본문 바로가기
ALV · 화면 · 리포트

[SAP ABAP] ALV 셀에서 F4 누르면 커스텀 서치헬프 띄우기 — ON_F4 이벤트 (register_f4_for_fields + HELP_VALUES_GET)

by Song.sh 2026. 6. 2.

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_EXTindex 가 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_GRIDONF4 이벤트 시그니처(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) 테이블이라 운영 시스템에는 없을 수 있으니, 실무 적용 시 운영 테이블로 교체하시기 바랍니다.