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

[SAP ABAP] ALV 툴바 드롭다운 메뉴 버튼 — MENU_BUTTON 이벤트 (cl_ctmenu add_function)

by Song.sh 2026. 5. 29.

ALV 툴바에 버튼을 누르면 하위 항목이 드롭다운으로 펼쳐지는 메뉴 버튼을 만들고 싶을 때 쓰는 이벤트가 MENU_BUTTON 입니다. 버튼 하나에 여러 선택지(Choice 1·2·3) 를 묶어 화면을 깔끔하게 정리할 때 유용합니다.

 

핵심은 세 이벤트의 협력입니다. TOOLBAR 로 메뉴 버튼을 툴바에 그리고, MENU_BUTTON 으로 그 버튼을 눌렀을 때 펼쳐질 하위 메뉴를 채우며, 하위 항목을 선택하면 USER_COMMAND 가 그 선택을 처리합니다. TOOLBAR 이벤트와 세트로 움직인다고 생각하면 편합니다.

 

이 글에서는 세 이벤트의 협력 흐름 → 메뉴 버튼 추가 → 하위 메뉴 채우기(cl_ctmenu) → 선택 처리까지 정리합니다. 데이터는 SAP 스탠다드 학습 환경 테이블 SFLIGHT 예시.

핵심 — 세 이벤트의 협력

이벤트 역할 핵심 인자
TOOLBAR 메뉴 버튼을 툴바에 그림 e_object(cl_alv_event_toolbar_set)
MENU_BUTTON 버튼 클릭 시 하위 메뉴를 채움 e_object(cl_ctmenu) · e_ucomm
USER_COMMAND 하위 항목 선택 처리 e_ucomm (선택된 항목 fcode)

흐름을 그림으로 정리하면:

1) TOOLBAR        → 메뉴 버튼 추가 (butn_type=1, function='BTN_LIST')
        ↓ (사용자가 메뉴 버튼 클릭)
2) MENU_BUTTON    → e_ucomm='BTN_LIST' 확인 → cl_ctmenu 에 하위 항목 add_function
                     ('A'=Choice 1, 'B'=Choice 2, 'C'=Choice 3)
        ↓ (사용자가 하위 항목 선택)
3) USER_COMMAND   → e_ucomm='A'/'B'/'C' → 선택 항목 처리

핵심은 버튼을 그리는 것(TOOLBAR), 펼치는 것(MENU_BUTTON), 처리하는 것(USER_COMMAND) 이 각각 다른 이벤트 라는 점입니다. 일반 버튼은 TOOLBAR + USER_COMMAND 둘이면 되지만, 드롭다운은 그 사이에 MENU_BUTTON 이 하나 더 끼어듭니다.


1단계 — 이벤트 핸들러 클래스 정의

세 이벤트를 받을 로컬 클래스를 정의합니다. MENU_BUTTON 의 시그니처가 핵심입니다.

CLASS lcl_event DEFINITION.
  PUBLIC SECTION.
    METHODS handle_toolbar
      FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING e_object e_interactive.

    METHODS handle_menu_button
      FOR EVENT menu_button OF cl_gui_alv_grid
      IMPORTING e_object e_ucomm.

    METHODS handle_user_command
      FOR EVENT user_command OF cl_gui_alv_grid
      IMPORTING e_ucomm.
ENDCLASS.

CLASS lcl_event IMPLEMENTATION.
  METHOD handle_toolbar.
    PERFORM handle_toolbar USING e_object e_interactive.
  ENDMETHOD.
  METHOD handle_menu_button.
    PERFORM handle_menu_button USING e_object e_ucomm.
  ENDMETHOD.
  METHOD handle_user_command.
    PERFORM handle_user_command USING e_ucomm.
  ENDMETHOD.
ENDCLASS.

DATA event_receiver TYPE REF TO lcl_event.

MENU_BUTTONe_objectcl_ctmenu(컨텍스트 메뉴 객체) 타입이고, e_ucomm 은 클릭된 메뉴 버튼의 function 코드입니다. TOOLBARe_object(cl_alv_event_toolbar_set) 와는 타입이 다릅니다.


2단계 — TOOLBAR 이벤트: 메뉴 버튼 추가

툴바에 버튼을 추가하되, butn_type = 1(메뉴 버튼) 로 지정합니다. 일반 버튼은 butn_type = 0, 드롭다운 메뉴 버튼은 1 입니다.

FORM handle_toolbar USING p_object      TYPE REF TO cl_alv_event_toolbar_set
                          p_interactive TYPE char01.

* 구분선
  APPEND VALUE stb_button( butn_type = 3 ) TO p_object->mt_toolbar.

* 메뉴 버튼 (드롭다운) — butn_type = 1
  APPEND VALUE stb_button(
    function  = 'BTN_LIST'
    butn_type = 1
    icon      = icon_dropdown
    text      = '선택 메뉴' ) TO p_object->mt_toolbar.

ENDFORM.

여기서 정한 function = 'BTN_LIST'MENU_BUTTON 이벤트의 e_ucomm 으로 넘어옵니다.

butn_type 버튼 종류
0 일반 버튼 (단순 클릭)
1 메뉴 버튼 (드롭다운) — MENU_BUTTON 이벤트 발생
3 구분선 (separator)

3단계 — MENU_BUTTON 이벤트: 하위 메뉴 채우기

메뉴 버튼을 클릭하면 MENU_BUTTON 이벤트가 발생합니다. e_object(cl_ctmenu) 의 add_function 으로 펼쳐질 항목을 추가합니다.

FORM handle_menu_button USING p_object TYPE REF TO cl_ctmenu
                              p_ucomm  TYPE sy-ucomm.

* 드롭다운에 넣을 항목 목록
  DATA(lt_drop) = VALUE lvc_t_dral(
    ( value = 'Choice 1' int_value = 'A' )
    ( value = 'Choice 2' int_value = 'B' )
    ( value = 'Choice 3' int_value = 'C' ) ).

  CASE p_ucomm.
    WHEN 'BTN_LIST'.                      " 2단계에서 정한 메뉴 버튼
      LOOP AT lt_drop INTO DATA(ls_drop).
        p_object->add_function(
          fcode = CONV #( ls_drop-int_value )   " 선택 시 e_ucomm 이 될 값
          text  = CONV #( ls_drop-value ) ).    " 화면에 보이는 텍스트
      ENDLOOP.
  ENDCASE.

ENDFORM.

add_functionfcode 가 항목 선택 시 USER_COMMANDe_ucomm 으로 전달되고, text 는 메뉴에 표시되는 글자입니다. lvc_t_dral 은 드롭다운 항목을 담기 좋은 스탠다드 테이블 타입입니다.


4단계 — USER_COMMAND 이벤트: 선택 항목 처리

하위 항목을 선택하면 그 fcodeUSER_COMMANDe_ucomm 으로 넘어옵니다. 일반 버튼 처리와 똑같이 CASE 로 분기합니다.

FORM handle_user_command USING p_ucomm TYPE sy-ucomm.
  CASE p_ucomm.
    WHEN 'A'.
      MESSAGE 'Choice 1 선택' TYPE 'I'.
    WHEN 'B'.
      MESSAGE 'Choice 2 선택' TYPE 'I'.
    WHEN 'C'.
      MESSAGE 'Choice 3 선택' TYPE 'I'.
  ENDCASE.
ENDFORM.

즉 드롭다운 항목 선택은 결국 USER_COMMAND 로 귀결됩니다. MENU_BUTTON 은 "어떤 항목을 보여줄지" 를 정하는 단계이고, 실제 동작은 USER_COMMAND 가 맡습니다.

등록은 세 이벤트를 모두 SET HANDLER 합니다.

FORM set_event.
  event_receiver = NEW #( ).
  SET HANDLER event_receiver->handle_toolbar      FOR go_grid.
  SET HANDLER event_receiver->handle_menu_button  FOR go_grid.
  SET HANDLER event_receiver->handle_user_command FOR go_grid.
ENDFORM.

자주 빠뜨리는 함정

butn_type 미지정 — 드롭다운이 안 됨

버튼을 butn_type = 0(일반) 으로 만들면 MENU_BUTTON 이벤트가 발생하지 않습니다. 드롭다운이 필요하면 반드시 butn_type = 1 로 지정해야 합니다.

menu_button 핸들러 미등록

handle_menu_buttonSET HANDLER 안 하면 메뉴 버튼을 눌러도 하위 항목이 비어 있습니다. TOOLBAR·MENU_BUTTON·USER_COMMAND 세 개를 모두 등록해야 완성됩니다.

e_object 타입 혼동

TOOLBARe_objectcl_alv_event_toolbar_set, MENU_BUTTONe_objectcl_ctmenu 입니다. FORM 파라미터 타입을 헷갈리면 메소드(add_function) 호출에서 오류가 납니다.

add_function 의 fcode 와 USER_COMMAND 분기 불일치

add_function( fcode = 'A' ) 로 만들고 USER_COMMAND 에서 WHEN 'CHOICE_A' 로 받으면 안 잡힙니다. fcode 와 분기 값이 정확히 같아야 합니다.

매번 add_function 누적

MENU_BUTTON 이벤트는 메뉴 버튼을 누를 때마다 발생합니다. e_object(cl_ctmenu) 는 클릭 시점마다 새로 전달되므로 누적 걱정은 없지만, 조건에 따라 항목을 다르게 보여주려면 e_ucomm 으로 분기해서 그때그때 채웁니다.


전체 코드 — 복사용 통합본

아래는 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_MENU_BUTTON  (메인 프로그램)
*&---------------------------------------------------------------------*
REPORT zrxx_alv_menu_button.

INCLUDE zrxx_alv_menu_button_t.     " TOP   - 전역 선언
INCLUDE zrxx_alv_menu_button_c.     " CLASS - 로컬 클래스
INCLUDE zrxx_alv_menu_button_scr.   " SCR   - 셀렉션 스크린
INCLUDE zrxx_alv_menu_button_o.     " PBO   - OUTPUT 모듈
INCLUDE zrxx_alv_menu_button_i.     " PAI   - INPUT 모듈
INCLUDE zrxx_alv_menu_button_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_MENU_BUTTON_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.

DATA: gs_data TYPE sflight,
      gt_data TYPE TABLE OF sflight.

DATA event_receiver TYPE REF TO lcl_event.   " C INCLUDE 의 클래스 참조

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_MENU_BUTTON_C  (CLASS - 로컬 클래스)
*&---------------------------------------------------------------------*
CLASS lcl_event DEFINITION.
  PUBLIC SECTION.
    METHODS handle_toolbar
      FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING e_object e_interactive.
    METHODS handle_menu_button
      FOR EVENT menu_button OF cl_gui_alv_grid
      IMPORTING e_object e_ucomm.
    METHODS handle_user_command
      FOR EVENT user_command OF cl_gui_alv_grid
      IMPORTING e_ucomm.
ENDCLASS.

CLASS lcl_event IMPLEMENTATION.
  METHOD handle_toolbar.
    PERFORM handle_toolbar USING e_object e_interactive.
  ENDMETHOD.
  METHOD handle_menu_button.
    PERFORM handle_menu_button USING e_object e_ucomm.
  ENDMETHOD.
  METHOD handle_user_command.
    PERFORM handle_user_command USING e_ucomm.
  ENDMETHOD.
ENDCLASS.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_MENU_BUTTON_SCR  (SCR - 셀렉션 스크린)
*&---------------------------------------------------------------------*
* 이 글은 셀렉션 스크린(SELECT-OPTIONS/PARAMETERS) 을 쓰지 않습니다.
* Screen 100 은 SE51 에서 정의 (Docking 사용, Custom Control 없음).
* 셀렉션 조건이 필요하면 여기에 SELECT-OPTIONS 를 선언.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_MENU_BUTTON_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_event.

    gs_layo-zebra      = abap_true.
    gs_layo-cwidth_opt = abap_true.

    go_grid->set_table_for_first_display(
      EXPORTING
        i_structure_name = 'SFLIGHT'
        is_layout        = gs_layo
      CHANGING
        it_outtab        = gt_data
        it_fieldcatalog  = gt_fcat ).
  ENDIF.
ENDMODULE.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_MENU_BUTTON_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_MENU_BUTTON_F  (FORM - 서브루틴)
*&---------------------------------------------------------------------*
* 이벤트 등록
FORM set_event.
  event_receiver = NEW #( ).
  SET HANDLER event_receiver->handle_toolbar      FOR go_grid.
  SET HANDLER event_receiver->handle_menu_button  FOR go_grid.
  SET HANDLER event_receiver->handle_user_command FOR go_grid.
ENDFORM.

* ★ TOOLBAR 이벤트: 메뉴 버튼 추가 (butn_type=1)
FORM handle_toolbar USING p_object      TYPE REF TO cl_alv_event_toolbar_set
                          p_interactive TYPE char01.
  APPEND VALUE stb_button( butn_type = 3 ) TO p_object->mt_toolbar.
  APPEND VALUE stb_button( function  = 'BTN_LIST'
                           butn_type = 1
                           icon      = icon_dropdown
                           text      = '선택 메뉴' ) TO p_object->mt_toolbar.
ENDFORM.

* ★ MENU_BUTTON 이벤트: 하위 메뉴 채우기
FORM handle_menu_button USING p_object TYPE REF TO cl_ctmenu
                              p_ucomm  TYPE sy-ucomm.
  DATA(lt_drop) = VALUE lvc_t_dral(
    ( value = 'Choice 1' int_value = 'A' )
    ( value = 'Choice 2' int_value = 'B' )
    ( value = 'Choice 3' int_value = 'C' ) ).

  CASE p_ucomm.
    WHEN 'BTN_LIST'.
      LOOP AT lt_drop INTO DATA(ls_drop).
        p_object->add_function(
          fcode = CONV #( ls_drop-int_value )
          text  = CONV #( ls_drop-value ) ).
      ENDLOOP.
  ENDCASE.
ENDFORM.

* ★ USER_COMMAND 이벤트: 선택 항목 처리
FORM handle_user_command USING p_ucomm TYPE sy-ucomm.
  CASE p_ucomm.
    WHEN 'A'.
      MESSAGE 'Choice 1 선택' TYPE 'I'.
    WHEN 'B'.
      MESSAGE 'Choice 2 선택' TYPE 'I'.
    WHEN 'C'.
      MESSAGE 'Choice 3 선택' TYPE 'I'.
  ENDCASE.
ENDFORM.


요약

단계 이벤트 핵심
1 TOOLBAR stb_button( butn_type = 1 ) 메뉴 버튼 추가
2 MENU_BUTTON cl_ctmenu->add_function 하위 항목 채움
3 USER_COMMAND CASE e_ucomm 선택 항목 처리

MENU_BUTTON 의 본질은 "드롭다운 메뉴 버튼의 하위 항목을 cl_ctmenu->add_function 으로 채우는 것". 버튼 그리기는 TOOLBAR(butn_type=1), 항목 채우기는 MENU_BUTTON, 선택 처리는 USER_COMMAND 가 나눠 맡는 3단 구조만 이해하면 됩니다. 선택지가 많은 기능을 버튼 하나로 묶어 툴바를 깔끔하게 정리할 때 유용합니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.

CL_GUI_ALV_GRIDMENU_BUTTON(e_object·e_ucomm) · TOOLBAR · USER_COMMAND 이벤트와 cl_ctmenuadd_function 메소드, stb_button 구조는 NetWeaver 스탠다드 정의(ECC 6.0 / S/4HANA on-premise 기준) 입니다. 적용 환경 버전에 따라 일부 차이가 있을 수 있으니 실제 적용 시 SE24 의 클래스 정의를 확인하시기 바랍니다. SFLIGHT 는 SAP 스탠다드 학습 환경(IDES) 테이블이라 운영 시스템에는 없을 수 있으니, 실무 적용 시 운영 테이블로 교체하시기 바랍니다.