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

[SAP ABAP] CL_GUI_EASY_SPLITTER_CONTAINER 로 ALV 2분할 — orientation·sash_position 마스터/디테일 화면 만드는 법 (ALV)

by Song.sh 2026. 5. 27.

한 화면에 ALV 두 개를 위/아래 또는 좌/우로 나란히 보여주고 싶을 때 가장 빠르게 만들 수 있는 컨테이너가 CL_GUI_EASY_SPLITTER_CONTAINER 입니다. 이름 그대로 "쉬운(Easy) Splitter" — 일반 CL_GUI_SPLITTER_CONTAINER 가 행/열 N개로 자유 분할이라면, EASY 는 항상 2개 영역으로만 나뉘는 경량 버전.

 

장점은 코드가 짧다는 것. orientation(영역 배치 방향) 과 sash_position(분할 비율) 두 파라미터만 정해주면 두 영역이 만들어지고, 각 영역에 ALV Grid 를 하나씩 붙이면 끝. PO Header(EKKO) + PO Item(EKPO) 같은 "마스터 + 디테일" 구조의 화면을 가장 빠르게 짤 때 쓰는 표준 패턴입니다.

 

이 글에서는 Easy Splitter 의 컨테이너 계층 구조 → 5단계 생성 흐름 → orientation/sash_position 파라미터 → top_left vs bottom_right 컨테이너 접근 → 마스터/디테일 동기화 → 전체 코드 통합본까지 정리합니다. 데이터는 SAP 표준 EKKO(구매오더 헤더) + EKPO(구매오더 라인) 예시.

핵심 — Easy Splitter 의 컨테이너 계층

계층 클래스 역할
1. 화면 영역 SE51 Custom Control 'AREA' Screen 100 에 미리 정의된 화면 위치
2. 부모 컨테이너 cl_gui_custom_container 'AREA' 와 ABAP 객체 연결
3. Splitter cl_gui_easy_splitter_container 부모 컨테이너를 2개 영역으로 분할
4. ALV Grid x 2 cl_gui_alv_grid 두 개 각각 splitter 의 top_left / bottom_right 자식 컨테이너에 배치

그림으로 정리하면:

Screen 100
  └ Custom Control 'AREA'
      └ g_container (cl_gui_custom_container)
          └ g_splitter (cl_gui_easy_splitter_container)
              ├ top_left_container     ← g_grid  (위쪽/왼쪽 ALV)
              └ bottom_right_container ← g_grid2 (아래쪽/오른쪽 ALV)

부모 컨테이너 1개를 받아 2개로 나누고, 각 영역에 ALV 를 붙이는 단순 구조. 일반 SPLITTER 처럼 ROWS·COLUMNS 파라미터로 N분할하는 게 아니라 무조건 2분할만 가능 — 그 점이 "Easy" 의 의미.


1단계 — SE51 Screen 100 에 Custom Control 'AREA' 배치

[1] T-Code SE51 (또는 SE38 의 화면 페인터 진입)

[2] Screen 100 의 Layout 편집

[3] 도구 모음의 "Custom Control" 아이콘 클릭 후 화면에 드래그
    └ 사이즈는 분할할 영역 크기 만큼

[4] Custom Control 의 Name 을 'AREA' 로 지정 (또는 회사 표준 이름)

[5] 활성화 + 메인 프로그램 PBO 모듈 연결

여기서 정한 'AREA' 라는 이름이 ABAP 코드에서 container_name = 'AREA' 로 연결됩니다.


2단계 — 데이터 + 객체 참조 변수 선언

* 컨테이너 + Splitter + Grid 두 개
DATA: g_container TYPE REF TO cl_gui_custom_container,
      g_splitter  TYPE REF TO cl_gui_easy_splitter_container,
      g_grid      TYPE REF TO cl_gui_alv_grid,
      g_grid2     TYPE REF TO cl_gui_alv_grid.

* Screen ok_code
DATA: ok_code TYPE sy-ucomm.

* Field Catalog 두 개 (ALV 두 개니까)
DATA: gt_fcat  TYPE lvc_t_fcat,
      gt_fcat2 TYPE lvc_t_fcat.

* PO 헤더 데이터 (위쪽 ALV)
DATA: BEGIN OF gs_data,
        ebeln TYPE ekko-ebeln,
        bstyp TYPE ekko-bstyp,
        bsart TYPE ekko-bsart,
      END OF gs_data,
      gt_data LIKE TABLE OF gs_data.

* PO 라인 데이터 (아래쪽 ALV)
DATA: gt_ekpo TYPE TABLE OF ekpo,
      gs_ekpo LIKE LINE OF gt_ekpo.

Grid 두 개, Field Catalog 두 개, 데이터 테이블 두 개. 분할이 2개라 모든 게 "쌍" 으로 묶입니다.


3단계 — START-OF-SELECTION → 데이터 조회 → CALL SCREEN

START-OF-SELECTION.

* 위쪽 ALV 데이터 — EKKO
  SELECT * INTO CORRESPONDING FIELDS OF TABLE gt_data
    FROM ekko.

* 아래쪽 ALV 데이터 — EKPO
  SELECT * INTO CORRESPONDING FIELDS OF TABLE gt_ekpo
    FROM ekpo.

  CALL SCREEN 100.

데이터를 먼저 채운 뒤 화면 100 호출. 화면 PBO 가 돌면서 컨테이너와 그리드가 그려집니다.


4단계 — PBO 모듈에서 컨테이너 + Splitter + 두 그리드 생성

PBO 의 핵심 모듈은 "컨테이너 한 번만 만들기" 패턴.

MODULE status_0100 OUTPUT.
  SET PF-STATUS 'S100'.
ENDMODULE.

MODULE create_container OUTPUT.

  IF g_container IS INITIAL.        " 첫 PBO 에서만 1회 생성
    PERFORM create_container.       " 컨테이너 + Splitter + Grid 생성
    PERFORM create_fcat.            " 두 Grid 의 Field Catalog 작성
    PERFORM register_event.         " 더블클릭 이벤트 등록
    PERFORM display.                " set_table_for_first_display
  ENDIF.

ENDMODULE.

PBO 가 여러 번 도는 화면에서 매번 컨테이너를 새로 만들면 메모리 누수 + 화면 깜빡임이 발생하므로 "g_container IS INITIAL 일 때만" 가드.

컨테이너 생성 FORM — Easy Splitter 의 핵심

FORM create_container.

* 1) 부모 Custom Container 생성 — SE51 의 'AREA' 와 연결
  g_container = NEW #( container_name = 'AREA' ).

* 2) Easy Splitter 생성 — 'AREA' 를 2분할
  g_splitter  = NEW #(
    parent        = g_container         " 부모 컨테이너
    orientation   = 0                   " 0=VERTICAL(위/아래), 1=HORIZONTAL(좌/우)
    sash_position = 30 ).               " 위쪽 30%, 아래쪽 70%

* 3) Grid 두 개를 splitter 의 자식 컨테이너에 배치
*    orientation=0 (VERTICAL) 기준:
*      top_left_container     = 위쪽 영역 (PO Header)
*      bottom_right_container = 아래쪽 영역 (PO Item)
  g_grid  = NEW #( i_parent = g_splitter->top_left_container ).      " 위쪽
  g_grid2 = NEW #( i_parent = g_splitter->bottom_right_container ).  " 아래쪽

ENDFORM.

핵심 3가지:

  • parent — Splitter 가 분할할 부모 컨테이너
  • orientation — 0=ORIENTATION_VERTICAL(위/아래), 1=ORIENTATION_HORIZONTAL(좌/우)
  • sash_position — 분할 비율(%). 예: 30 = 첫 영역이 30%, 나머지가 70%

orientation 과 자식 컨테이너 매핑

Splitter 의 자식 컨테이너 속성 이름이 top_left_container · bottom_right_container 인데, 한 속성 이름이 orientation 값에 따라 두 가지 의미를 가집니다.

orientation SAP 상수 영역 배치 top_left_container bottom_right_container
0 ORIENTATION_VERTICAL 위/아래로 쌓임 (분할선 가로) 위쪽 영역 아래쪽 영역
1 ORIENTATION_HORIZONTAL 좌/우로 배치 (분할선 세로) 왼쪽 영역 오른쪽 영역

SAP 상수 이름이 "두 영역이 배치되는 방향" 기준이라 직관적으로 헷갈리기 쉽습니다. ORIENTATION_VERTICAL 은 두 영역이 세로(위→아래) 로 쌓인다는 의미고, 분할선은 가로 방향. PO 헤더(EKKO) + PO 라인(EKPO) 마스터-디테일에서는 위쪽 헤더 + 아래쪽 라인 배치가 자연스러우니 orientation=0 을 씁니다. 컬럼이 많아 가로 스크롤이 부담되면 orientation=1 로 좌/우 배치.


5단계 — Field Catalog 생성 + 이벤트 등록 + ALV 표시

두 Grid 의 Field Catalog 를 각각 자동 생성하고, 위쪽 ALV 의 더블클릭 이벤트를 등록한 뒤 화면 표시.

FORM create_fcat.

* 위쪽 ALV (gt_data) 의 Field Catalog
  IF gt_data IS NOT INITIAL.
    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.
  ENDIF.

* 아래쪽 ALV (gt_ekpo) 의 Field Catalog
  IF gt_ekpo IS NOT INITIAL.
    DATA lr_str2 TYPE REF TO cl_abap_structdescr.
    lr_str2 ?= cl_abap_structdescr=>describe_by_data( gs_ekpo ).

    DATA(lt_fcat2) = cl_salv_data_descr=>read_structdescr( lr_str2 ).
    gt_fcat2 = CORRESPONDING #( lt_fcat2 MAPPING ref_table = reftable
                                                  ref_field = reffield ).

    CALL FUNCTION 'LVC_FIELDCAT_COMPLETE'
      CHANGING
        ct_fieldcat = gt_fcat2.
  ENDIF.

ENDFORM.

FORM register_event.
  CREATE OBJECT g_event_receiver.
  SET HANDLER g_event_receiver->handle_double_click FOR g_grid.
ENDFORM.

FORM display.

  g_grid->set_table_for_first_display(
    CHANGING
      it_fieldcatalog = gt_fcat
      it_outtab       = gt_data ).      " 위쪽 ALV — PO 헤더

  g_grid2->set_table_for_first_display(
    CHANGING
      it_fieldcatalog = gt_fcat2
      it_outtab       = gt_ekpo ).      " 아래쪽 ALV — PO 라인

ENDFORM.

두 그리드 모두 표시되면 사용자가 한 화면에서 PO 헤더 + 라인을 동시에 보는 마스터-디테일 뷰가 완성됩니다.


마스터-디테일 동기화 패턴

Easy Splitter 로 두 ALV 를 만들고 끝이 아니라, 보통 "위쪽 ALV 의 라인을 더블클릭하면 아래쪽 ALV 가 그 PO 의 라인만 보여주도록" 동기화하는 패턴이 같이 따라옵니다.

* 이벤트 핸들러 클래스
CLASS lcl_event_receiver DEFINITION.
  PUBLIC SECTION.
    METHODS handle_double_click
      FOR EVENT double_click OF cl_gui_alv_grid
      IMPORTING e_row sender.
ENDCLASS.

CLASS lcl_event_receiver IMPLEMENTATION.
  METHOD handle_double_click.
    DATA: lt_filtered LIKE gt_ekpo.

    IF sender = g_grid.                  " 위쪽 헤더 ALV 더블클릭
      DATA(ls_data) = gt_data[ e_row-index ].

*     해당 PO 의 라인만 필터링
      LOOP AT gt_ekpo INTO DATA(ls_ekpo) WHERE ebeln = ls_data-ebeln.
        APPEND ls_ekpo TO lt_filtered.
      ENDLOOP.

*     아래쪽 라인 ALV 갱신
      g_grid2->set_table_for_first_display(
        CHANGING
          it_fieldcatalog = gt_fcat2
          it_outtab       = lt_filtered ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

DATA g_event_receiver TYPE REF TO lcl_event_receiver.

핸들러 안에서는 위쪽 그리드(g_grid) 의 더블클릭만 처리하고, 선택된 PO 의 EBELN 으로 EKPO 라인을 필터링한 결과를 아래쪽 그리드(g_grid2) 에 다시 표시. 이벤트 핸들러 등록 방식은 "[SAP ABAP] ALV 체크박스 전체 선택" 글에서 다룬 lcl_event_receiver 패턴과 동일합니다.


비교 — Easy Splitter vs 일반 Splitter

구분 CL_GUI_EASY_SPLITTER_CONTAINER CL_GUI_SPLITTER_CONTAINER
분할 수 항상 2개 ROWS x COLUMNS 자유 (예: 2x2, 3x1)
자식 접근 속성 top_left_container / bottom_right_container 메서드 get_container( row, column )
코드 길이 짧음 (한 줄 NEW + 자식 속성 2개) 중간 (rows · columns 설정 + 각 셀 get_container)
분할 비율 변경 set_sash_position 한 값 set_row_height / set_column_width 메서드
적합한 시나리오 마스터-디테일 (헤더+라인) · 좌/우 비교 2x2 격자 대시보드 · 다중 ALV + 트리

대부분 시나리오는 EASY 로 충분. 3분할 이상이 필요하거나 좌/우 + 위/아래 동시 배치(2x2) 가 필요할 때만 일반 SPLITTER 로 갑니다.


자주 빠뜨리는 함정

g_container IS INITIAL 가드 누락

PBO 가 여러 번 도는데 매번 NEW 하면 메모리 누수 + 화면 깜빡임 발생. 첫 PBO 한 번만 생성하도록 가드 필수.

orientation 의미 혼동

SAP 상수 이름은 "영역이 배치되는 방향" 기준. ORIENTATION_VERTICAL(0) = 두 영역이 세로로 쌓임(위/아래), ORIENTATION_HORIZONTAL(1) = 가로로 배치(좌/우). 분할선 방향 기준으로 외우면 정반대로 헷갈리므로, 코드 옆 주석 권장.

sash_position 단위 오해

픽셀이 아닌 퍼센트(%). 30 이면 첫 영역(top_left) 이 30%, 두 번째(bottom_right) 가 70%. 0~100 범위 밖 값은 무시됨.

자식 컨테이너 속성 이름 헷갈림

한 속성 이름(top_left_container / bottom_right_container) 이 orientation 값에 따라 두 가지 의미를 가짐. 위 매핑 표를 코드 옆에 두고 작성.

두 Grid 의 Field Catalog 공용

각 Grid 마다 별도 Field Catalog 가 필요. gt_fcat + gt_fcat2 처럼 따로 둬야 컬럼 구성이 섞이지 않음.

EKPO 전체 표시

마스터-디테일 패턴에서 위쪽 PO 선택 시 아래쪽 EKPO 를 필터링 안 하면 전체 EKPO 가 보임. handle_double_click 에서 필터링 갱신 패턴 필수.

Background 실행 시 덤프

이 글의 패턴은 Dialog 전용. 배치 잡으로 돌리려면 "[SAP ABAP] ALV 백그라운드 DUMP 방지" 글의 OFFLINE( ) 분기 패턴을 같이 적용.


전체 코드 — 복사용 통합본

아래 통합본은 SE38 에 그대로 붙여 활성화 가능. Screen 100 의 PBO 모듈에 status_0100·create_container, PAI 모듈에 user_command_0100 연결하고, SE51 에서 Screen 100 에 Custom Control 'AREA' 만 추가하면 됩니다.

*&---------------------------------------------------------------------*
*& Report ZRXX_ALV_EASY_SPLITTER (예시)
*&---------------------------------------------------------------------*
REPORT zrxx_alv_easy_splitter.

* ★ 1) DATA 선언 — 컨테이너 + Splitter + Grid 두 개 + 데이터 + Field Catalog
DATA: g_container TYPE REF TO cl_gui_custom_container,
      g_splitter  TYPE REF TO cl_gui_easy_splitter_container,
      g_grid      TYPE REF TO cl_gui_alv_grid,
      g_grid2     TYPE REF TO cl_gui_alv_grid.

DATA: ok_code TYPE sy-ucomm.

DATA: gt_fcat  TYPE lvc_t_fcat,
      gt_fcat2 TYPE lvc_t_fcat.

DATA: BEGIN OF gs_data,
        ebeln TYPE ekko-ebeln,
        bstyp TYPE ekko-bstyp,
        bsart TYPE ekko-bsart,
      END OF gs_data,
      gt_data LIKE TABLE OF gs_data.

DATA: gt_ekpo TYPE TABLE OF ekpo,
      gs_ekpo LIKE LINE OF gt_ekpo.

* ★ 2) 이벤트 핸들러 클래스 — 마스터 ALV 더블클릭 → 디테일 ALV 필터링
CLASS lcl_event_receiver DEFINITION.
  PUBLIC SECTION.
    METHODS handle_double_click
      FOR EVENT double_click OF cl_gui_alv_grid
      IMPORTING e_row sender.
ENDCLASS.

CLASS lcl_event_receiver IMPLEMENTATION.
  METHOD handle_double_click.
    DATA: lt_filtered LIKE gt_ekpo.

    IF sender = g_grid.                  " 위쪽 헤더 ALV 더블클릭
      DATA(ls_data) = gt_data[ e_row-index ].

*     해당 PO 의 라인만 필터링
      LOOP AT gt_ekpo INTO DATA(ls_ekpo) WHERE ebeln = ls_data-ebeln.
        APPEND ls_ekpo TO lt_filtered.
      ENDLOOP.

*     아래쪽 라인 ALV 갱신
      g_grid2->set_table_for_first_display(
        CHANGING
          it_fieldcatalog = gt_fcat2
          it_outtab       = lt_filtered ).
    ENDIF.
  ENDMETHOD.
ENDCLASS.

DATA g_event_receiver TYPE REF TO lcl_event_receiver.

* ★ 3) 데이터 조회 → CALL SCREEN
START-OF-SELECTION.
  SELECT * INTO CORRESPONDING FIELDS OF TABLE gt_data
    FROM ekko.
  SELECT * INTO CORRESPONDING FIELDS OF TABLE gt_ekpo
    FROM ekpo.
  CALL SCREEN 100.

* ★ 4) PBO 모듈 — 첫 호출 시에만 컨테이너 + Splitter + Grid 생성
MODULE status_0100 OUTPUT.
  SET PF-STATUS 'S100'.
ENDMODULE.

MODULE create_container OUTPUT.
  IF g_container IS INITIAL.
    PERFORM create_container.
    PERFORM create_fcat.
    PERFORM register_event.
    PERFORM display.
  ENDIF.
ENDMODULE.

* ★ 5) PAI 모듈 — ok_code 처리
MODULE user_command_0100 INPUT.
  CASE ok_code.
    WHEN 'BACK' OR 'EXIT' OR 'CANC'.
      LEAVE PROGRAM.
  ENDCASE.
ENDMODULE.

* ★ 6) ★ 핵심: Easy Splitter 생성 — orientation + sash_position
FORM create_container.
  g_container = NEW #( container_name = 'AREA' ).

  g_splitter  = NEW #(
    parent        = g_container
    orientation   = 0                  " 0=VERTICAL(위/아래), 1=HORIZONTAL(좌/우)
    sash_position = 30 ).              " 위쪽 30%, 아래쪽 70%

* orientation=0 기준:
*   top_left_container     = 위쪽 영역 (PO Header)
*   bottom_right_container = 아래쪽 영역 (PO Item)
  g_grid  = NEW #( i_parent = g_splitter->top_left_container ).
  g_grid2 = NEW #( i_parent = g_splitter->bottom_right_container ).
ENDFORM.

* ★ 7) Field Catalog 두 개 — 각 그리드 별도 작성
FORM create_fcat.
  IF gt_data IS NOT INITIAL.
    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.
  ENDIF.

  IF gt_ekpo IS NOT INITIAL.
    DATA lr_str2 TYPE REF TO cl_abap_structdescr.
    lr_str2 ?= cl_abap_structdescr=>describe_by_data( gs_ekpo ).

    DATA(lt_fcat2) = cl_salv_data_descr=>read_structdescr( lr_str2 ).
    gt_fcat2 = CORRESPONDING #( lt_fcat2 MAPPING ref_table = reftable
                                                  ref_field = reffield ).

    CALL FUNCTION 'LVC_FIELDCAT_COMPLETE'
      CHANGING ct_fieldcat = gt_fcat2.
  ENDIF.
ENDFORM.

* ★ 8) 이벤트 핸들러 등록 — 위쪽 ALV 더블클릭
FORM register_event.
  CREATE OBJECT g_event_receiver.
  SET HANDLER g_event_receiver->handle_double_click FOR g_grid.
ENDFORM.

* ★ 9) 두 그리드 표시
FORM display.
  g_grid->set_table_for_first_display(
    CHANGING
      it_fieldcatalog = gt_fcat
      it_outtab       = gt_data ).

  g_grid2->set_table_for_first_display(
    CHANGING
      it_fieldcatalog = gt_fcat2
      it_outtab       = gt_ekpo ).
ENDFORM.

요약

단계 위치 핵심 행동
1 SE51 Screen 100 Custom Control 'AREA' 배치
2 데이터 / 객체 선언 g_container + g_splitter + g_grid x 2 + 데이터 테이블 x 2
3 START-OF-SELECTION SELECT * + CALL SCREEN 100
4 PBO create_container 모듈 (IS INITIAL 가드) custom_containereasy_splitter(orientation/sash_position) → grid x 2
5 Field Catalog + 이벤트 + Display 두 Grid 각각 gt_fcat 채워 set_table_for_first_display + 더블클릭 핸들러

Easy Splitter 의 본질은 "한 Custom Container 를 2개로 나누고, 각 영역에 ALV 한 개씩 붙이기" 한 줄. orientation 으로 영역 배치 방향(ORIENTATION_VERTICAL=0 위/아래, ORIENTATION_HORIZONTAL=1 좌/우), sash_position 으로 비율, top_left_container / bottom_right_container 속성으로 자식 접근. 마스터-디테일 화면이나 좌/우 비교 ALV 가 필요한 시나리오에 가장 빠르게 만들 수 있는 표준 패턴이고, 3분할 이상이 정말 필요한 경우만 일반 SPLITTER 로 옮기면 됩니다.


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

CL_GUI_EASY_SPLITTER_CONTAINER 의 생성자 파라미터(orientation·sash_position) 와 자식 컨테이너 속성(top_left_container·bottom_right_container) 은 NetWeaver 표준 정의(ECC 6.0 / S/4HANA on-premise 기준) 입니다. 적용 환경 버전에 따라 일부 차이가 있을 수 있으니 실제 적용 시 SE24 의 클래스 정의를 확인하시기 바랍니다.