계층 데이터를 트리로 보여주되 데이터 컬럼 없이 순수 텍스트 노드만 필요할 때 쓰는 가벼운 클래스가 CL_GUI_SIMPLE_TREE 입니다. ALV Tree(CL_GUI_ALV_TREE) 와 달리 오른쪽에 데이터 컬럼이 붙지 않고, 노드 클릭 시 다른 ALV 그리드에 상세 데이터를 띄우는 마스터-디테일 화면 의 왼쪽 트리로 자주 씁니다.
핵심은 두 가지입니다. (1) MTREESNODE 구조체로 노드 한 행씩 인터널 테이블에 쌓아두고, (2) add_nodes 메소드 한 번 호출로 전체 노드를 화면에 그립니다. ALV Tree 가 노드 하나씩 ADD_NODE 호출하는 방식이라면, SIMPLE TREE 는 테이블 일괄 등록 방식.
이 글에서는 컨테이너 2개(왼쪽 트리 / 오른쪽 ALV) 구성 → MTREESNODE 노드 테이블 채우기 → add_nodes 호출 → 이벤트(node_double_click) 등록 → 클릭 시 ALV 갱신까지 정리합니다. 데이터는 SAP 스탠다드 학습 환경 SCARR(항공사 마스터) + SFLIGHT(항공편) 마스터-디테일 예시.
핵심 — SIMPLE TREE 의 노드 구조
SIMPLE TREE 의 각 노드는 MTREESNODE(SEU_TREE_CONTROL 패키지의 스탠다드 구조체) 한 행으로 표현됩니다. 키와 부모 키로 계층을 형성하고, 텍스트·아이콘·스타일 등 표시 속성을 함께 담습니다.
| 필드 | 의미 |
|---|---|
node_key |
노드 고유 키 (이벤트 발생 시 어느 노드인지 식별) |
relatkey |
부모 노드 키. 루트는 공백 |
isfolder |
'X' 면 폴더(자식 가질 수 있음) / 공백이면 leaf |
text |
화면에 표시할 텍스트 |
expander |
'X' 면 처음에 펼친 상태로 시작 |
n_image |
노드 아이콘 (예: '@10@') — leaf 노드의 아이콘만 적용 |
style |
텍스트 강조 — cl_gui_simple_tree=>style_emphasized 등 |
disabled |
'X' 면 선택 불가 (회색) |
흐름을 그림으로 정리하면:
[ 화면 100 ]
┌────────────────────┬───────────────────────────────┐
│ TREE_CONTAINER │ CON1 (ALV 그리드) │
│ ▼ AIRPLANE │ │
│ ▼ CARRID │ CARRID/CONNID/FLDATE/... │
│ • LH │ LH / 0400 / 19950228 / ... │
│ • AA │ │
│ • AZ │ │
└────────────────────┴───────────────────────────────┘
더블클릭 LH
↓
SELECT * FROM sflight WHERE carrid = 'LH' INTO TABLE gt_sflight.
↓
go_grid->refresh_table_display( )
↓
오른쪽 ALV 가 LH 항공편만 표시

ALV Tree 와 가장 큰 차이를 정리하면:
| 항목 | SIMPLE TREE | ALV TREE |
|---|---|---|
| 클래스 | CL_GUI_SIMPLE_TREE |
CL_GUI_ALV_TREE |
| 데이터 컬럼 | 없음 (텍스트만) | 있음 (DDIC 구조 기반) |
| 노드 추가 | MTREESNODE 테이블 + add_nodes 일괄 |
ADD_NODE 한 번씩 |
| 이벤트 | node_double_click 등 (node_key 전달) |
ALV 이벤트 풀세트 + 트리 이벤트 |
| 적합 시나리오 | 마스터-디테일의 왼쪽 카테고리 트리 | 계층 + 컬럼 데이터를 한 곳에 보여줘야 할 때 |
1단계 — 화면 + 컨테이너 2개
SE51 의 Screen 100 에 Custom Control 두 개를 배치합니다. 왼쪽은 트리용 TREE_CONTAINER, 오른쪽은 ALV 그리드용 CON1. 코드에서는 각각 CL_GUI_CUSTOM_CONTAINER 인스턴스를 만들어 자식 컨트롤(트리 / 그리드) 의 부모로 사용합니다.
* TOP INCLUDE
TYPES : node_table_type LIKE TABLE OF mtreesnode.
DATA : tree_con_ref TYPE REF TO cl_gui_custom_container,
g_tree TYPE REF TO cl_gui_simple_tree.
DATA : con1_ref TYPE REF TO cl_gui_custom_container,
go_grid TYPE REF TO cl_gui_alv_grid.
DATA : gt_sflight LIKE TABLE OF sflight,
ok_code LIKE sy-ucomm.
node_table_type 은 MTREESNODE 의 STANDARD TABLE 타입. add_nodes 에 그대로 넘기는 인자이므로 한 번 선언해 두면 편합니다.
2단계 — ALV 그리드 생성 (오른쪽 패널)
먼저 오른쪽 ALV 부터 만들어 둡니다. 처음엔 빈 테이블이지만 트리 클릭 이벤트가 발생하면 SELECT 후 refresh_table_display 로 채웁니다.
MODULE create_container OUTPUT.
CHECK con1_ref IS INITIAL.
CREATE OBJECT con1_ref
EXPORTING container_name = 'CON1'.
CREATE OBJECT go_grid
EXPORTING i_parent = con1_ref.
CALL METHOD go_grid->set_table_for_first_display
EXPORTING
i_structure_name = 'SFLIGHT'
CHANGING
it_outtab = gt_sflight.
ENDMODULE.
i_structure_name = 'SFLIGHT' 만 박으면 컬럼 카탈로그 자동 생성. 빈 gt_sflight 도 OK — 이후 데이터만 채우면 됩니다.
3단계 — 트리 생성 + 노드 테이블 + add_nodes
핵심 단계. 컨테이너 / 트리 객체를 만들고 build_node_table 폼에서 노드를 인터널 테이블에 쌓은 뒤 add_nodes 한 번으로 화면에 표시.
MODULE create_tree OUTPUT.
CHECK g_tree IS INITIAL.
DATA : node_table TYPE node_table_type.
CREATE OBJECT tree_con_ref
EXPORTING container_name = 'TREE_CONTAINER'.
CREATE OBJECT g_tree
EXPORTING
parent = tree_con_ref
node_selection_mode = cl_gui_simple_tree=>node_sel_mode_single.
PERFORM build_node_table USING node_table.
CALL METHOD g_tree->add_nodes
EXPORTING
table_structure_name = 'MTREESNODE'
node_table = node_table.
ENDMODULE.
table_structure_name = 'MTREESNODE' 인자는 노드 테이블의 행 타입을 ALV 에게 알려주는 용도. 항상 'MTREESNODE' 고정 (대문자 문자열 리터럴).
노드 테이블 채우기 — 두 가지 방식
(a) 수동 — 노드 한 줄씩 직접 박기. 데이터가 정해진 카테고리 트리(예: PO 유형, 모듈 분류) 에 유용.
FORM build_node_table USING p_node_table TYPE node_table_type.
DATA : node LIKE mtreesnode.
* 루트
CLEAR node.
node-node_key = 'Root'.
node-isfolder = 'X'.
node-text = 'AIRPLANE'.
APPEND node TO p_node_table.
* 그룹 (CARRID)
CLEAR node.
node-node_key = 'Child1'.
node-relatkey = 'Root'.
node-isfolder = 'X'.
node-text = 'CARRID'.
node-expander = 'X'. " 처음부터 펼친 상태
APPEND node TO p_node_table.
ENDFORM.
(b) 자동 — SELECT 후 LOOP 으로 동적 추가. 항공사 마스터(SCARR) 처럼 DB 에서 카테고리 목록을 가져올 때.
* 위 두 노드 추가 후 이어서
DATA : gs_carr TYPE scarr,
gt_carr LIKE TABLE OF gs_carr.
SELECT * FROM scarr INTO TABLE @gt_carr.
LOOP AT gt_carr INTO gs_carr.
CLEAR node.
node-node_key = gs_carr-carrid. " CARRID 자체를 키로
node-relatkey = 'Child1'. " CARRID 그룹의 자식
node-text = gs_carr-carrid.
APPEND node TO p_node_table.
ENDLOOP.
이 두 방식은 섞어 쓸 수 있습니다. 위처럼 루트 / 그룹은 수동으로 박고, 그 아래 데이터 노드는 LOOP 으로 자동 추가하는 게 가장 일반적.
4단계 — 이벤트 등록 + 핸들러 클래스
SIMPLE TREE 의 이벤트는 두 단계로 등록합니다. (1) 어떤 이벤트를 받을지 set_registered_events 로 등록, (2) 그 이벤트의 핸들러 메소드를 SET HANDLER 로 연결.
핸들러 클래스 정의
CLASS lcl_application DEFINITION.
PUBLIC SECTION.
METHODS handle_node_double_click
FOR EVENT node_double_click OF cl_gui_simple_tree
IMPORTING node_key.
ENDCLASS.
CLASS lcl_application IMPLEMENTATION.
METHOD handle_node_double_click.
PERFORM handle_node_double_click USING node_key.
ENDMETHOD.
ENDCLASS.
DATA : lcl_application TYPE REF TO lcl_application.
FOR EVENT node_double_click OF cl_gui_simple_tree 시그니처는 고정. IMPORTING node_key 로 사용자가 더블클릭한 노드의 키가 자동으로 들어옵니다.
이벤트 등록 모듈
MODULE event_tree OUTPUT.
DATA : event TYPE cntl_simple_event,
events TYPE cntl_simple_events.
* 1) 받을 이벤트 목록
event-eventid = cl_gui_simple_tree=>eventid_node_double_click.
event-appl_event = 'X'. " 애플리케이션 이벤트
APPEND event TO events.
CALL METHOD g_tree->set_registered_events
EXPORTING
events = events
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
illegal_event_combination = 3.
* 2) 핸들러 인스턴스 생성 + 연결
CREATE OBJECT lcl_application.
SET HANDLER lcl_application->handle_node_double_click FOR g_tree.
ENDMODULE.
appl_event = 'X' 는 "이 이벤트는 ABAP 백엔드에서 받겠다" 는 표시. 안 박으면 시스템 이벤트로 처리되어 핸들러가 안 불립니다.
클릭 시 ALV 갱신
FORM handle_node_double_click USING p_node_key.
SELECT *
INTO CORRESPONDING FIELDS OF TABLE gt_sflight
FROM sflight
WHERE carrid = p_node_key.
PERFORM refresh_grid.
ENDFORM.
FORM refresh_grid.
IF go_grid IS BOUND.
go_grid->refresh_table_display( ).
ENDIF.
ENDFORM.
CARRID 노드의 node_key 를 CARRID 자체로 박아뒀으니 WHERE carrid = p_node_key 로 바로 필터링. 키 설계가 이벤트 처리를 결정합니다.
자주 빠뜨리는 함정
node_key 중복
같은 키를 두 번 APPEND 하면 첫 번째만 등록되고 두 번째는 무시되거나 덤프. node_key 는 전체 트리 안에서 unique. CARRID 자체로 키를 박을 때는 SELECT 결과가 중복되지 않게 SELECT DISTINCT 또는 SORT + DELETE ADJACENT DUPLICATES 후 LOOP.
relatkey 오타
부모 키와 자식의 relatkey 가 한 글자라도 다르면 그 자식 노드는 어디에도 안 붙고 사라진 것처럼 보입니다. 대소문자 포함 정확히 일치해야.
appl_event = 'X' 누락
set_registered_events 호출 시 event-appl_event = 'X' 가 없으면 시스템 이벤트로 처리되어 ABAP 핸들러가 불리지 않습니다. SIMPLE TREE 이벤트는 거의 항상 애플리케이션 이벤트.
CHECK ... IS INITIAL 누락
PBO 모듈은 매 화면 진입 시 실행되므로 CHECK g_tree IS INITIAL 같은 가드 없이 add_nodes 를 반복하면 같은 노드가 누적됩니다. 처음 한 번만 트리를 만들고 이후엔 갱신 함수로.
Custom Container 이름 — 대문자
container_name = 'tree_container' 처럼 소문자로 박으면 SE51 의 이름과 안 맞아 컨트롤이 안 잡힙니다. 대문자 문자열로 일치시키기.
isfolder vs leaf
isfolder = 'X' 를 박은 노드는 자식을 가질 수 있는 폴더로 표시. leaf 노드(자식 없음) 인데 isfolder 를 박으면 펼치기 화살표가 보이는데 안 펼쳐지는 어색한 화면이 됩니다.
node_image 는 leaf 전용
n_image(노드 아이콘) 은 isfolder='X' 인 폴더 노드에는 적용되지 않습니다. 폴더는 표준 폴더 아이콘 고정. leaf 노드의 아이콘만 커스텀할 수 있습니다.
전체 코드 — 복사용 통합본
화면(CALL SCREEN) 이 있는 모듈풀 구조라 SAP 스탠다드 INCLUDE 6분할(T / C / SCR / O / I / F) 로 구성합니다. SE51 에서 Screen 100 의 Custom Container 2개(TREE_CONTAINER·CON1) + Flow Logic 에 status_0100 · create_container · create_tree · event_tree (PBO) · user_command_0100 (PAI).
*&---------------------------------------------------------------------*
*& Report ZRXX_ALV_SIMPLE_TREE
*&---------------------------------------------------------------------*
REPORT zrxx_alv_simple_tree.
INCLUDE zrxx_alv_simple_tree_t. " TOP - 전역 선언
INCLUDE zrxx_alv_simple_tree_c. " CLASS - 이벤트 핸들러 클래스
INCLUDE zrxx_alv_simple_tree_scr. " SCR - 셀렉션 스크린 (사용 안 함)
INCLUDE zrxx_alv_simple_tree_o. " PBO - OUTPUT 모듈
INCLUDE zrxx_alv_simple_tree_i. " PAI - INPUT 모듈
INCLUDE zrxx_alv_simple_tree_f. " FORM - 서브루틴
START-OF-SELECTION.
CALL SCREEN 100.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_SIMPLE_TREE_T (TOP)
*&---------------------------------------------------------------------*
TYPES : node_table_type LIKE TABLE OF mtreesnode.
DATA : tree_con_ref TYPE REF TO cl_gui_custom_container,
g_tree TYPE REF TO cl_gui_simple_tree.
DATA : con1_ref TYPE REF TO cl_gui_custom_container,
go_grid TYPE REF TO cl_gui_alv_grid.
DATA : gt_sflight LIKE TABLE OF sflight,
ok_code LIKE sy-ucomm.
DATA : lcl_application TYPE REF TO lcl_application.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_SIMPLE_TREE_C (CLASS)
*&---------------------------------------------------------------------*
CLASS lcl_application DEFINITION.
PUBLIC SECTION.
METHODS handle_node_double_click
FOR EVENT node_double_click OF cl_gui_simple_tree
IMPORTING node_key.
ENDCLASS.
CLASS lcl_application IMPLEMENTATION.
METHOD handle_node_double_click.
PERFORM handle_node_double_click USING node_key.
ENDMETHOD.
ENDCLASS.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_SIMPLE_TREE_SCR (SCR)
*&---------------------------------------------------------------------*
* (이 글에서는 셀렉션 스크린 사용 안 함)
* Screen 100 은 SE51 에서 정의 — Custom Container 두 개:
* - 'TREE_CONTAINER' (왼쪽, SIMPLE TREE)
* - 'CON1' (오른쪽, ALV GRID)
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_SIMPLE_TREE_O (PBO)
*&---------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
SET PF-STATUS 'S100'.
ENDMODULE.
MODULE create_container OUTPUT.
CHECK con1_ref IS INITIAL.
CREATE OBJECT con1_ref
EXPORTING container_name = 'CON1'.
CREATE OBJECT go_grid
EXPORTING i_parent = con1_ref.
CALL METHOD go_grid->set_table_for_first_display
EXPORTING
i_structure_name = 'SFLIGHT'
CHANGING
it_outtab = gt_sflight.
ENDMODULE.
MODULE create_tree OUTPUT.
CHECK g_tree IS INITIAL.
DATA : node_table TYPE node_table_type.
CREATE OBJECT tree_con_ref
EXPORTING container_name = 'TREE_CONTAINER'.
CREATE OBJECT g_tree
EXPORTING
parent = tree_con_ref
node_selection_mode = cl_gui_simple_tree=>node_sel_mode_single.
PERFORM build_node_table USING node_table.
CALL METHOD g_tree->add_nodes
EXPORTING
table_structure_name = 'MTREESNODE'
node_table = node_table.
ENDMODULE.
MODULE event_tree OUTPUT.
* PBO 마다 새로 등록되지 않도록 한 번만
CHECK lcl_application IS INITIAL.
DATA : event TYPE cntl_simple_event,
events TYPE cntl_simple_events.
event-eventid = cl_gui_simple_tree=>eventid_node_double_click.
event-appl_event = 'X'.
APPEND event TO events.
CALL METHOD g_tree->set_registered_events
EXPORTING
events = events
EXCEPTIONS
cntl_error = 1
cntl_system_error = 2
illegal_event_combination = 3.
CREATE OBJECT lcl_application.
SET HANDLER lcl_application->handle_node_double_click FOR g_tree.
ENDMODULE.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_SIMPLE_TREE_I (PAI)
*&---------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
CASE ok_code.
WHEN 'BACK' OR 'EXIT' OR 'CANC'.
LEAVE TO SCREEN 0.
ENDCASE.
ENDMODULE.
*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_SIMPLE_TREE_F (FORM)
*&---------------------------------------------------------------------*
FORM build_node_table USING p_node_table TYPE node_table_type.
DATA : node LIKE mtreesnode.
* 루트 — AIRPLANE
CLEAR node.
node-node_key = 'Root'.
node-isfolder = 'X'.
node-text = 'AIRPLANE'.
APPEND node TO p_node_table.
* 그룹 — CARRID 폴더
CLEAR node.
node-node_key = 'Child1'.
node-relatkey = 'Root'.
node-isfolder = 'X'.
node-text = 'CARRID'.
node-expander = 'X'.
APPEND node TO p_node_table.
* 자동 추가 — SCARR 의 CARRID 목록을 leaf 노드로
DATA : gs_carr TYPE scarr,
gt_carr LIKE TABLE OF gs_carr.
SELECT * FROM scarr INTO TABLE @gt_carr.
LOOP AT gt_carr INTO gs_carr.
CLEAR node.
node-node_key = gs_carr-carrid.
node-relatkey = 'Child1'.
node-text = gs_carr-carrid.
APPEND node TO p_node_table.
ENDLOOP.
ENDFORM.
* 더블클릭 처리 — 클릭한 CARRID 의 SFLIGHT 만 ALV 에 표시
FORM handle_node_double_click USING p_node_key.
SELECT *
INTO CORRESPONDING FIELDS OF TABLE gt_sflight
FROM sflight
WHERE carrid = p_node_key.
PERFORM refresh_grid.
ENDFORM.
FORM refresh_grid.
IF go_grid IS BOUND.
go_grid->refresh_table_display( ).
ENDIF.
ENDFORM.
요약
| 단계 | 위치 | 핵심 |
|---|---|---|
| 1 | TOP + Screen | 컨테이너 2개(TREE_CONTAINER·CON1) + TYPES node_table_type LIKE TABLE OF mtreesnode |
| 2 | ALV 그리드 | CL_GUI_ALV_GRID + SET_TABLE_FOR_FIRST_DISPLAY(빈 테이블 OK) |
| 3 | 트리 + 노드 | CL_GUI_SIMPLE_TREE + MTREESNODE 노드 테이블 + add_nodes( table_structure_name = 'MTREESNODE' ) |
| 4 | 이벤트 | eventid_node_double_click + appl_event='X' + set_registered_events + SET HANDLER |
| 5 | 디테일 갱신 | 핸들러 → SELECT WHERE carrid = node_key → go_grid->refresh_table_display( ) |
SIMPLE TREE 의 본질은 "MTREESNODE 한 테이블에 노드를 다 쌓아 add_nodes 로 일괄 등록 + node_double_click 이벤트로 클릭한 키를 받아 처리". node_key + relatkey 로 계층을 만들고, appl_event = 'X' 와 핸들러 클래스만 잘 짝지으면 마스터-디테일 화면이 만들어집니다. ALV Tree 와 달리 데이터 컬럼이 없어 가볍고, 카테고리 선택용 사이드 패널로 활용도가 높습니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다. CL_GUI_SIMPLE_TREE(SEU_TREE_CONTROL 패키지) · MTREESNODE(구조) · CNTL_SIMPLE_EVENT/CNTL_SIMPLE_EVENTS(이벤트 구조) · 메소드 ADD_NODES·SET_REGISTERED_EVENTS 와 이벤트 ID eventid_node_double_click 및 모드 상수 node_sel_mode_single·style_emphasized·relat_last_child 는 NetWeaver 스탠다드 정의(ECC 6.0 / S/4HANA on-premise 기준) 입니다. SCARR·SFLIGHT 는 SAP 스탠다드 학습 환경(IDES) 테이블이며 실무 적용 시 운영 테이블로 교체하시기 바랍니다.