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

[SAP ABAP] 한 화면 여러 ALV 를 탭으로 — TABSTRIP + SUBSCREEN 동적 화면 끼우기 (CALL SUBSCREEN INCLUDING)

by Song.sh 2026. 6. 2.

한 화면에서 여러 ALV 를 탭으로 전환 해서 보여줘야 하는 케이스가 자주 있습니다. 항공편 마스터 / 예약 / 자재 같이 성격이 다른 데이터를 한 화면에 묶고, 사용자가 탭을 눌러 화면을 갈아끼우는 구조입니다. ABAP 에서는 TABSTRIP 컨트롤 + SUBSCREEN 두 가지를 조합해서 구현합니다.

 

핵심은 메인 화면에 TABSTRIP 컨트롤 + 그 아래 SUBSCREEN 영역 을 두고, 별도 서브 스크린(110·120·130) 을 각각 만들어 CALL SUBSCREEN ... INCLUDING sy-repid gv_screen 으로 동적으로 끼워 넣는 것입니다. 탭을 누르면 g_tabstrip-activetab 값이 바뀌고, PBO 에서 그 값에 맞춰 gv_screen 변수에 호출할 서브 화면 번호를 세팅해 줍니다.

 

이 글에서는 메인 화면 디자인 → 서브 화면 / 컨테이너 배치 → TABSTRIP 컨트롤 선언 → PBO 분기 → PAI 처리 순서로, 항공편 데이터(SFLIGHT / SBOOK / MARA) 3개 탭을 보여주는 풀 모듈풀을 만들어 봅니다.

핵심 — TABSTRIP + SUBSCREEN 의 구성 요소

탭 ALV 한 화면을 만들려면 화면 디자인 쪽과 코드 쪽에서 각각 갖춰야 할 것들이 다릅니다.

구성 요소 위치 역할
TABSTRIP 컨트롤 G_TABSTRIP 메인 Screen 100 Layout 탭 헤더를 화면에 그리는 컨트롤
PUSH BUTTON TAB1 / TAB2 / TAB3 TABSTRIP 안 탭 한 칸씩 — Function code 가 곧 탭 이름
SUBSCREEN 영역 SUB_SCR TABSTRIP 아래 서브 화면이 끼워 들어가는 자리
서브 화면 110 / 120 / 130 화면 유형 = "서브화면" 탭별 ALV 가 들어갈 화면
Custom Container CON1 / CON2 / CON3 각 서브 화면 안 ALV 가 붙는 Custom Control
CONTROLS g_tabstrip TYPE TABSTRIP TOP INCLUDE 활성 탭(activetab) 을 담는 구조

전체 흐름은 다음과 같습니다.

사용자 TAB2 클릭
      ↓
PAI: g_tabstrip-activetab = ok_code  ('TAB2')
      ↓
PBO: case activetab → gv_screen = '0120'
      ↓
PROCESS BEFORE OUTPUT:
  call subscreen sub_scr INCLUDING sy-repid gv_screen
      ↓
서브 화면 120 PBO 실행 → SBOOK ALV 표시

핵심 트릭은 CALL SUBSCREEN 의 마지막 인자에 변수(gv_screen) 를 넣을 수 있다는 점. 이 변수는 sy-dynnr 타입이고, PBO 시점에 활성 탭에 맞춰 다른 서브 화면 번호로 갈아끼우면 같은 SUBSCREEN 영역에 다른 화면이 들어옵니다.


1단계 — 메인 화면(100) 디자인

메인 화면은 Screen Painter(SE51) 에서 만듭니다. 두 가지 영역만 배치하면 됩니다.

┌──────────────────────────────────────────────┐
│  Screen 100 (Main)                           │
│                                              │
│  ┌──────────────────────────────────────┐   │
│  │ G_TABSTRIP  (TABSTRIP 컨트롤)        │   │
│  │  ┌────┐ ┌─────┐ ┌─────┐              │   │
│  │  │TAB1│ │TAB2 │ │TAB3 │              │   │
│  │  └────┘ └─────┘ └─────┘              │   │
│  └──────────────────────────────────────┘   │
│  ┌──────────────────────────────────────┐   │
│  │ SUB_SCR  (Subscreen area)            │   │
│  │  → 110/120/130 이 여기로 들어옴      │   │
│  └──────────────────────────────────────┘   │
└──────────────────────────────────────────────┘

TABSTRIP 컨트롤 만들기

요소 목록(Element List) 에서 새 요소를 Tabstrip Control 로 추가하고 이름을 G_TABSTRIP 로 줍니다. 그 안에 PUSH BUTTON 세 개를 배치하고 Function code 를 각각 TAB1·TAB2·TAB3 로 지정합니다.

SUBSCREEN 영역 만들기

같은 화면에 Subscreen area 요소를 추가하고 이름을 SUB_SCR 로 줍니다. 이 영역의 크기가 곧 탭 내용물의 크기를 결정하므로 충분히 넓게.


2단계 — 서브 화면(110·120·130) 만들기

탭 별로 하나씩 서브 화면을 만듭니다. SE51 → 화면 번호 입력 → 속성 → 화면 유형에서 "서브화면" 라디오 체크가 핵심입니다. 일반 화면으로 만들면 CALL SUBSCREEN 시점에 덤프가 납니다.

화면 담당 탭 Custom Container 표시 데이터
110 TAB1 CON1 SFLIGHT (항공편)
120 TAB2 CON2 SBOOK (예약)
130 TAB3 CON3 MARA (자재)

각 서브 화면 안에 Custom Control 요소(사용자제어) 를 하나씩 배치하고 이름을 CON1·CON2·CON3 으로 지정. 이 컨테이너에 코드에서 ALV 를 붙입니다.

서브 화면 Flow Logic

서브 화면도 PBO / PAI 가 있어야 합니다. 각 화면에 다음을 추가합니다.

PROCESS BEFORE OUTPUT.
  MODULE create_alv110.   " 화면 110 의 경우
PROCESS AFTER INPUT.
  MODULE user_command_0110.

3단계 — TABSTRIP 컨트롤 선언 (TOP INCLUDE)

ABAP 코드에서 탭 상태를 받으려면 CONTROLS 구문으로 TABSTRIP 컨트롤을 선언해 줍니다. 화면 디자인의 컨트롤 이름과 정확히 동일한 이름 이어야 합니다.

CONTROLS : g_tabstrip TYPE TABSTRIP.
DATA     : gv_screen  TYPE sy-dynnr,
           ok_code    TYPE sy-ucomm.

CONTROLS 로 선언된 g_tabstripactivetab 컴포넌트를 가집니다. 현재 활성 탭의 Function code (= 'TAB1' / 'TAB2' / 'TAB3') 가 여기에 들어 있습니다.

gv_screen 은 PBO 에서 활성 탭에 따라 호출할 서브 화면 번호('0110'·'0120'·'0130') 를 담아두는 변수.


4단계 — PBO 분기: set_tabscreen + CALL SUBSCREEN

PBO 에서 두 가지 모듈을 실행합니다. 하나는 활성 탭에 따라 gv_screen 을 세팅하는 모듈, 다른 하나는 그 변수를 가지고 SUBSCREEN 을 호출하는 Flow Logic 명령입니다.

메인 Screen 100 의 Flow Logic

PROCESS BEFORE OUTPUT.
  MODULE status_0100.
  MODULE set_tabscreen.
  CALL SUBSCREEN sub_scr INCLUDING sy-repid gv_screen.

PROCESS AFTER INPUT.
  CALL SUBSCREEN sub_scr.
  MODULE user_command_0100.

set_tabscreen 모듈 (PBO INCLUDE)

MODULE set_tabscreen OUTPUT.
  IF g_tabstrip-activetab IS INITIAL.
    g_tabstrip-activetab = 'TAB1'.
  ENDIF.

  CASE g_tabstrip-activetab.
    WHEN 'TAB1'.   gv_screen = '0110'.
    WHEN 'TAB2'.   gv_screen = '0120'.
    WHEN 'TAB3'.   gv_screen = '0130'.
    WHEN OTHERS.   gv_screen = '0110'.
  ENDCASE.
ENDMODULE.

처음 화면이 떴을 때 activetab 이 비어 있는 케이스를 처리하기 위해 초기값 'TAB1' 을 박아 줍니다. 그렇지 않으면 첫 진입 시 gv_screen 이 공백이라 SUBSCREEN 호출이 실패합니다.

create_alv110 같은 ALV 생성 모듈 (PBO INCLUDE)

각 서브 화면 PBO 에서 자기 ALV 를 만들어 컨테이너에 붙입니다. 한 번만 만들면 되므로 인스턴스가 비어 있을 때만 생성합니다.

MODULE create_alv110 OUTPUT.
  SELECT * FROM sflight INTO TABLE @DATA(lt_sflight) UP TO 50 ROWS.

  IF go_con IS INITIAL.
    go_con  = NEW #( container_name = 'CON1' ).
    go_grid = NEW #( i_parent = go_con ).

    go_grid->set_table_for_first_display(
      EXPORTING
        i_structure_name = 'SFLIGHT'
      CHANGING
        it_outtab        = lt_sflight ).
  ENDIF.
ENDMODULE.

120 / 130 도 동일한 구조로 각각 SBOOK / MARA 데이터를 붙이면 됩니다.


5단계 — PAI 처리: activetab 갱신

PAI 에서는 단 한 줄이 핵심입니다. 사용자가 클릭한 탭의 Function code 를 g_tabstrip-activetab 에 다시 넣어 줘야 다음 PBO 때 set_tabscreen 이 올바른 화면 번호를 세팅합니다.

MODULE user_command_0100 INPUT.
  g_tabstrip-activetab = ok_code.

  CASE ok_code.
    WHEN 'BACK' OR 'EXIT' OR 'CANC'.
      SET SCREEN 0.
  ENDCASE.

  CLEAR ok_code.
ENDMODULE.

이 한 줄 — g_tabstrip-activetab = ok_code — 을 빠뜨리면 탭을 눌러도 화면이 안 바뀌고 첫 탭 그대로 머무릅니다. 가장 흔한 실수.


자주 빠뜨리는 함정

푸시버튼 "참조필드" 미설정

TAB 푸시버튼의 속성(참조필드) 에 G_TABSTRIP 컨트롤 이름을 안 적으면 일반 버튼처럼 동작합니다. 더블클릭 후 Dict 탭에서 참조필드를 컨트롤 이름과 동일하게 지정해야 탭으로 인식됩니다.

서브 화면 라디오 미체크

서브로 쓸 화면의 속성에서 화면 유형 = 서브화면 라디오를 안 체크하면 CALL SUBSCREEN 호출 시 덤프(DYNP_TOO_FEW_LINES_IN_AREA 류) 가 발생합니다.

CALL SUBSCREEN 위치 — Flow Logic 안

CALL SUBSCREEN sub_scr INCLUDING ... gv_screen 은 ABAP 소스의 MODULE 안이 아니라 메인 화면 100 의 Flow Logic 안에 직접 적습니다. MODULE 안에 적으면 컴파일 오류.

activetab 갱신 누락

PAI 에서 g_tabstrip-activetab = ok_code 빠뜨리면 탭 클릭이 무시됩니다. PBO 의 set_tabscreen 만 봐서는 이유를 못 찾으므로 가장 자주 막히는 지점.

gv_screen 초기값 미설정

첫 진입 시 activetab 이 공백이라 case 문이 다른 분기로 떨어지면 gv_screen 이 공백 그대로 CALL SUBSCREEN 에 전달되어 덤프. set_tabscreen 첫 줄에 IF activetab IS INITIAL ... 'TAB1' ... ENDIF 안전 장치 필수.

Custom Container 이름 대소문자

CL_GUI_CUSTOM_CONTAINER 컨스트럭터의 container_name 은 Screen Painter 의 컨테이너 이름과 정확히 일치(대문자) 해야 합니다. 'con1' 처럼 소문자로 박으면 컨트롤이 안 잡혀서 ALV 가 안 보이거나 다른 화면에 떠 버립니다.

같은 컨테이너에 ALV 중복 생성

PBO 가 매번 실행되므로 IF go_con IS INITIAL. 같은 가드 없이 컨테이너 / 그리드를 만들면 호출마다 새 인스턴스가 생성되어 메모리 누수 + 화면이 깜빡입니다. 항상 가드 + refresh_table_display 패턴으로.


전체 코드 — 복사용 통합본

화면 100 + 서브 화면 110·120·130 은 SE51 에서 미리 만든다는 전제로, ABAP 부분은 메인 + 6개 INCLUDE(T / C / SCR / O / I / F) 로 구성합니다. INCLUDE 는 T → C → SCR → O → I → F 순서로 메인 프로그램이 로드합니다.

*&---------------------------------------------------------------------*
*& Report ZRXX_ALV_TABSTRIP  (메인)
*&---------------------------------------------------------------------*
REPORT zrxx_alv_tabstrip.

INCLUDE zrxx_alv_tabstrip_t.     " TOP   - 전역 선언 + CONTROLS
INCLUDE zrxx_alv_tabstrip_c.     " CLASS - 로컬 클래스 (이 글에서는 사용 안 함)
INCLUDE zrxx_alv_tabstrip_scr.   " SCR   - 셀렉션 스크린 (이 글에서는 사용 안 함)
INCLUDE zrxx_alv_tabstrip_o.     " PBO   - OUTPUT 모듈
INCLUDE zrxx_alv_tabstrip_i.     " PAI   - INPUT 모듈
INCLUDE zrxx_alv_tabstrip_f.     " FORM  - 서브루틴 (이 글에서는 사용 안 함)

START-OF-SELECTION.
  CALL SCREEN 100.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_TABSTRIP_T  (TOP - 전역 선언)
*&---------------------------------------------------------------------*
* ★ TABSTRIP 컨트롤 + 화면 변수
CONTROLS : g_tabstrip TYPE TABSTRIP.
DATA     : gv_screen  TYPE sy-dynnr,
           ok_code    TYPE sy-ucomm.

* 탭별 컨테이너 + ALV 인스턴스
DATA : go_con  TYPE REF TO cl_gui_custom_container,
       go_grid TYPE REF TO cl_gui_alv_grid.

DATA : go_con2  TYPE REF TO cl_gui_custom_container,
       go_grid2 TYPE REF TO cl_gui_alv_grid.

DATA : go_con3  TYPE REF TO cl_gui_custom_container,
       go_grid3 TYPE REF TO cl_gui_alv_grid.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_TABSTRIP_C  (CLASS - 로컬 클래스)
*&---------------------------------------------------------------------*
* (이 글에서는 사용 안 함 — 이벤트 핸들러가 필요해지면 여기에 lcl_event 정의)

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_TABSTRIP_SCR  (SCR - 셀렉션 스크린)
*&---------------------------------------------------------------------*
* (이 글에서는 사용 안 함 — 셀렉션 조건이 필요하면 SELECT-OPTIONS 추가)
*
* Screen 100 / 110 / 120 / 130 은 SE51 에서 정의:
*   100 : 메인 (TABSTRIP G_TABSTRIP + 푸시버튼 TAB1/TAB2/TAB3 + Subscreen SUB_SCR)
*   110 : 서브화면 (Custom Container CON1) — TAB1 / SFLIGHT
*   120 : 서브화면 (Custom Container CON2) — TAB2 / SBOOK
*   130 : 서브화면 (Custom Container CON3) — TAB3 / MARA
*
* Screen 100 Flow Logic:
*   PROCESS BEFORE OUTPUT.
*     MODULE status_0100.
*     MODULE set_tabscreen.
*     CALL SUBSCREEN sub_scr INCLUDING sy-repid gv_screen.
*   PROCESS AFTER INPUT.
*     CALL SUBSCREEN sub_scr.
*     MODULE user_command_0100.
*
* Screen 110 Flow Logic:
*   PROCESS BEFORE OUTPUT.
*     MODULE create_alv110.
*   PROCESS AFTER INPUT.
*     MODULE user_command_0110.
* (120, 130 도 동일하게 create_alv120 / 130 + user_command_0120 / 0130)

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_TABSTRIP_O  (PBO - OUTPUT)
*&---------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
  SET PF-STATUS 'S100'.
ENDMODULE.

* ★ 활성 탭에 따라 서브 화면 번호 세팅
MODULE set_tabscreen OUTPUT.
  IF g_tabstrip-activetab IS INITIAL.
    g_tabstrip-activetab = 'TAB1'.
  ENDIF.

  CASE g_tabstrip-activetab.
    WHEN 'TAB1'.   gv_screen = '0110'.
    WHEN 'TAB2'.   gv_screen = '0120'.
    WHEN 'TAB3'.   gv_screen = '0130'.
    WHEN OTHERS.   gv_screen = '0110'.
  ENDCASE.
ENDMODULE.

* TAB1 — SFLIGHT
MODULE create_alv110 OUTPUT.
  SELECT * FROM sflight
    INTO TABLE @DATA(lt_sflight)
    UP TO 50 ROWS.

  IF go_con IS INITIAL.
    go_con  = NEW #( container_name = 'CON1' ).
    go_grid = NEW #( i_parent = go_con ).

    go_grid->set_table_for_first_display(
      EXPORTING
        i_structure_name = 'SFLIGHT'
      CHANGING
        it_outtab        = lt_sflight ).
  ENDIF.
ENDMODULE.

* TAB2 — SBOOK
MODULE create_alv120 OUTPUT.
  SELECT * FROM sbook
    INTO TABLE @DATA(lt_sbook)
    UP TO 50 ROWS.

  IF go_con2 IS INITIAL.
    go_con2  = NEW #( container_name = 'CON2' ).
    go_grid2 = NEW #( i_parent = go_con2 ).

    go_grid2->set_table_for_first_display(
      EXPORTING
        i_structure_name = 'SBOOK'
      CHANGING
        it_outtab        = lt_sbook ).
  ENDIF.
ENDMODULE.

* TAB3 — MARA
MODULE create_alv130 OUTPUT.
  SELECT * FROM mara
    INTO TABLE @DATA(lt_mara)
    UP TO 50 ROWS.

  IF go_con3 IS INITIAL.
    go_con3  = NEW #( container_name = 'CON3' ).
    go_grid3 = NEW #( i_parent = go_con3 ).

    go_grid3->set_table_for_first_display(
      EXPORTING
        i_structure_name = 'MARA'
      CHANGING
        it_outtab        = lt_mara ).
  ENDIF.
ENDMODULE.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_TABSTRIP_I  (PAI - INPUT)
*&---------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
* ★ 클릭한 탭의 Function code 를 activetab 으로 다시 박기 (핵심)
  g_tabstrip-activetab = ok_code.

  CASE ok_code.
    WHEN 'BACK' OR 'EXIT' OR 'CANC'.
      SET SCREEN 0.
  ENDCASE.

  CLEAR ok_code.
ENDMODULE.

* 서브 화면 PAI — 필요 시 각각 따로
MODULE user_command_0110 INPUT.
ENDMODULE.

MODULE user_command_0120 INPUT.
ENDMODULE.

MODULE user_command_0130 INPUT.
ENDMODULE.

*&---------------------------------------------------------------------*
*& INCLUDE ZRXX_ALV_TABSTRIP_F  (FORM - 서브루틴)
*&---------------------------------------------------------------------*
* (이 글에서는 사용 안 함 — 데이터 가공 FORM 이 필요해지면 여기에 추가)

요약

단계 위치 핵심
1 메인 Screen 100 TABSTRIP G_TABSTRIP + 푸시버튼 TAB1/2/3 + Subscreen SUB_SCR
2 서브 화면 110/120/130 화면 유형 = 서브화면 + Custom Container CON1/2/3
3 TOP INCLUDE CONTROLS g_tabstrip TYPE TABSTRIP + gv_screen TYPE sy-dynnr
4 PBO + Flow Logic set_tabscreen(activetab→gv_screen) + CALL SUBSCREEN sub_scr INCLUDING sy-repid gv_screen
5 PAI g_tabstrip-activetab = ok_code (1줄, 빠뜨리면 탭 안 바뀜)

탭 ALV 의 본질은 "같은 SUBSCREEN 영역에 다른 화면을 동적으로 끼워 넣기" 입니다.

CONTROLS 로 선언한 TABSTRIP 의 activetab 값과 CALL SUBSCREEN ... INCLUDING sy-repid gv_screen 의 변수 인자, 그리고 PAI 의 g_tabstrip-activetab = ok_code 세 가지가 맞물려 동작합니다. 푸시버튼 참조필드와 서브 화면 라디오만 정확히 설정하면 ALV 가 아니라 일반 입력 화면도 같은 패턴으로 탭에 묶을 수 있습니다.


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

TABSTRIP 컨트롤 · CONTROLS 구문 · CALL SUBSCREEN ... INCLUDING · CL_GUI_CUSTOM_CONTAINER · CL_GUI_ALV_GRID 는 NetWeaver 스탠다드 정의(ECC 6.0 / S/4HANA on-premise 기준) 입니다. SFLIGHT · SBOOK · MARA 는 SAP 스탠다드 학습 환경(IDES) 테이블이며, 실무 적용 시 운영 테이블로 교체하시기 바랍니다. 화면 100 / 110 / 120 / 130 의 레이아웃은 SE51 Screen Painter 에서 직접 그려야 하며 코드만으로는 재현되지 않습니다.