ABAP

[ABAP] ALV TREE , EVENT

셜록누나 2026. 5. 9. 13:58

 

TOP 선언

" ===== 트리 관련 전역 선언 =====

" 노드 키 (filter_detail에서 루트 판단)
DATA: gv_all_node TYPE lvc_nkey,
      gv_sel_node TYPE lvc_nkey.

" 데이터 테이블
DATA : BEGIN OF gs_data,
       END OF gs_data,
       gt_data      LIKE TABLE OF gs_data,  " 트리용 마스터
       gt_make_tree LIKE TABLE OF gs_data.  " 트리 내부 outtab

" CDS 기반 그리드용
DATA: gs_item TYPE zcds_e3_cm_0001_i,
      gt_item LIKE TABLE OF gs_item.

" 컨테이너 / 트리 / 그리드 객체
DATA: gcl_dock_container TYPE REF TO cl_gui_docking_container,
      gcl_splitter       TYPE REF TO cl_gui_splitter_container,
      gcl_top_con        TYPE REF TO cl_gui_container,  " TOP OF PAGE
      gcl_tree_con       TYPE REF TO cl_gui_container,  " 트리
      gcl_right_con      TYPE REF TO cl_gui_container,  " 그리드
      gcl_chart_con      TYPE REF TO cl_gui_container,  " 차트
      gcl_tree           TYPE REF TO cl_gui_alv_tree,
      gcl_grid           TYPE REF TO cl_gui_alv_grid,
      gcl_doc_top        TYPE REF TO cl_dd_document.

" 필드카탈로그 / 레이아웃
DATA: gt_fcat_tree TYPE lvc_t_fcat,   " 트리 숫자 컬럼용
      gt_fcat      TYPE lvc_t_fcat,   " 그리드용
      gs_fcat      TYPE lvc_s_fcat,
      gs_layout    TYPE lvc_s_layo,
      gs_variant   TYPE disvariant,
      gs_stable    TYPE lvc_s_stbl.

" 이벤트
DATA: gt_event TYPE cntl_simple_events,
      gs_event LIKE LINE OF gt_event.

 

PBO

 

 

*&---------------------------------------------------------------------*
*& Form create_dock_con
*&---------------------------------------------------------------------*
FORM create_dock_con.

  CREATE OBJECT gcl_dock_container
    EXPORTING
      side      = cl_gui_docking_container=>dock_at_left
      extension = 5000.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form create_splitter
*& 상하(TOP/하단) → 좌우(트리/그리드) → 우측 상하(그리드/차트)
*&---------------------------------------------------------------------*
FORM create_splitter.

  DATA: lcl_bottom_con     TYPE REF TO cl_gui_container,
        lcl_lr_splitter    TYPE REF TO cl_gui_splitter_container,
        lcl_right_splitter TYPE REF TO cl_gui_splitter_container.

  " [1단계] 상하 분할 (상단 20% TOP / 하단 80% 컨텐츠)
  CREATE OBJECT gcl_splitter
    EXPORTING
      parent  = gcl_dock_container
      rows    = 2
      columns = 1.

  gcl_splitter->get_container( EXPORTING row=1 column=1 RECEIVING container=gcl_top_con ).
  gcl_splitter->get_container( EXPORTING row=2 column=1 RECEIVING container=lcl_bottom_con ).
  gcl_splitter->set_row_height( id=1 height=20 ).
  gcl_splitter->set_row_height( id=2 height=80 ).

  " [2단계] 하단 좌우 분할 (트리 35% / 그리드 65%)
  CREATE OBJECT lcl_lr_splitter
    EXPORTING
      parent  = lcl_bottom_con
      rows    = 1
      columns = 2.

  lcl_lr_splitter->get_container( EXPORTING row=1 column=1 RECEIVING container=gcl_tree_con ).
  lcl_lr_splitter->get_container( EXPORTING row=1 column=2 RECEIVING container=gcl_right_con ).
  lcl_lr_splitter->set_column_width( id=1 width=35 ).
  lcl_lr_splitter->set_column_width( id=2 width=65 ).

  " [3단계] 우측 상하 분할 (그리드 50% / 차트 50%)
  CREATE OBJECT lcl_right_splitter
    EXPORTING
      parent  = gcl_right_con
      rows    = 2
      columns = 1.

  lcl_right_splitter->get_container( EXPORTING row=1 column=1 RECEIVING container=gcl_right_con ).
  lcl_right_splitter->get_container( EXPORTING row=2 column=1 RECEIVING container=gcl_chart_con ).
  lcl_right_splitter->set_row_height( id=1 height=50 ).
  lcl_right_splitter->set_row_height( id=2 height=50 ).

ENDFORM.

*&---------------------------------------------------------------------*
*& Form create_top_doc
*& cl_dd_document 객체 생성 (set_top_page에서 사용)
*&---------------------------------------------------------------------*
FORM create_top_doc.

  CREATE OBJECT gcl_doc_top
    EXPORTING
      style            = 'ALV_TO_HTML'
      background_color = 1
      no_margins       = space.

ENDFORM.
*&---------------------------------------------------------------------*
*& Form set_tree_header
*& 트리 좌측 숫자 컬럼 필드카탈로그
*&---------------------------------------------------------------------*
FORM set_tree_header.

  PERFORM set_fcat_tree USING:
    'APRICE' '취득원가' 'ZTE3CM0002' 'APRICE' '8',
    'ACCUM'  '감가누계' 'ZTE3CM0002' 'ACCUM'  '8',
    'BOOK'   '장부가액' 'ZTE3CM0002' 'APRICE' '8',
    'WAERS'  '통화'     'ZTE3CM0002' 'WAERS'  '8'.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form set_fcat_tree
*&---------------------------------------------------------------------*
FORM set_fcat_tree USING pv_field
                         pv_text
                         pv_ref_table
                         pv_ref_field
                         pv_len.

  gs_fcat-fieldname = pv_field.
  gs_fcat-coltext   = pv_text.
  gs_fcat-ref_table = pv_ref_table.
  gs_fcat-ref_field = pv_ref_field.
  gs_fcat-outputlen = pv_len.

  CASE pv_field.
    WHEN 'APRICE' OR 'ACCUM' OR 'BOOK'.
      gs_fcat-cfieldname = 'WAERS'.  " 통화키 연결
      gs_fcat-do_sum     = 'X'.      " 합계 자동계산
  ENDCASE.

  APPEND gs_fcat TO gt_fcat_tree.
  CLEAR  gs_fcat.

ENDFORM.

*&---------------------------------------------------------------------*
*& Form create_tree
*& ALV Tree 객체 생성 + 이벤트 등록
*&---------------------------------------------------------------------*
FORM create_tree.

  DATA: l_hierarchy_header TYPE treev_hhdr.

  l_hierarchy_header-heading   = '자산명'.
  l_hierarchy_header-width     = 25.
  l_hierarchy_header-width_pix = space.

  CREATE OBJECT gcl_tree
    EXPORTING
      parent              = gcl_tree_con
      node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
      item_selection      = space
      no_html_header      = 'X'
      no_toolbar          = space.

  " 더블클릭 이벤트 등록
  gcl_tree->get_registered_events( IMPORTING events = gt_event ).
  gs_event-eventid    = cl_gui_column_tree=>eventid_node_double_click.
  gs_event-appl_event = 'X'.
  APPEND gs_event TO gt_event.
  gcl_tree->set_registered_events( EXPORTING events = gt_event ).

  SET HANDLER lcl_event_handler=>handle_node_click FOR gcl_tree.

  gs_variant-report = sy-repid.

  gcl_tree->set_table_for_first_display(
    EXPORTING
      i_save              = 'A'
      is_variant          = gs_variant
      is_hierarchy_header = l_hierarchy_header
    CHANGING
      it_outtab       = gt_make_tree   " 트리 내부 데이터 (add_node가 여기 채워넣음)
      it_fieldcatalog = gt_fcat_tree ).

ENDFORM.

*&---------------------------------------------------------------------*
*& Form make_hierarchy
*& [Lv.0] 전체 루트
*& [Lv.1] 자산분류 폴더 (anlkl 기준 합계)
*& [Lv.2] 개별 자산 리프
*&---------------------------------------------------------------------*
FORM make_hierarchy.

  DATA: lt_data_tmp LIKE TABLE OF gs_data,
        lt_sum      LIKE TABLE OF gs_data,
        ls_sum      LIKE gs_data,
        ls_root     LIKE gs_data,
        lv_all_key  TYPE lvc_nkey,
        lv_cls_key  TYPE lvc_nkey,
        lv_node_key TYPE lvc_nkey.

  lt_data_tmp = gt_data.
  REFRESH: gt_make_tree, lt_sum.

  "----------------------------------------------------------------
  " STEP 1. anlkl별 합계 집계 (COLLECT → O(n) 루프 1번)
  "         COLLECT은 anlkl 같은 행끼리 aprice/accum 자동 합산
  "----------------------------------------------------------------
  LOOP AT lt_data_tmp INTO gs_data.
    CLEAR ls_sum.
    ls_sum-anlkl  = gs_data-anlkl.
    ls_sum-aprice = gs_data-aprice.
    ls_sum-accum  = gs_data-accum.
    ls_sum-book   = gs_data-aprice - gs_data-accum.
    ls_sum-waers  = 'KRW'.
    COLLECT ls_sum INTO lt_sum.
  ENDLOOP.

  SORT lt_sum      BY anlkl.
  SORT lt_data_tmp BY anlkl anln1.

  "----------------------------------------------------------------
  " STEP 2. [Lv.0] 루트 노드 — 전체
  "         ls_root는 반드시 CLEAR 후 넘겨야 COLLECT 잔여값 방지
  "----------------------------------------------------------------
  CLEAR ls_root.
  PERFORM add_node USING ls_root '전체' space lv_all_key.
  gv_all_node = lv_all_key.  " 전역 저장 → filter_detail에서 루트 판단에 사용

  "----------------------------------------------------------------
  " STEP 3. [Lv.1] 분류 폴더 + [Lv.2] 개별 자산 리프
  "----------------------------------------------------------------
  LOOP AT lt_sum INTO ls_sum.

    " [Lv.1] 자산분류 폴더 노드 (부모: lv_all_key)
    PERFORM add_node USING ls_sum ls_sum-anlkl lv_all_key lv_cls_key.

    " [Lv.2] 개별 자산 리프 노드 (부모: lv_cls_key)
    LOOP AT lt_data_tmp INTO gs_data WHERE anlkl = ls_sum-anlkl.
      PERFORM add_node USING gs_data gs_data-anlnt lv_cls_key lv_node_key.
    ENDLOOP.

  ENDLOOP.

  "----------------------------------------------------------------
  " STEP 4. 트리 렌더링
  "----------------------------------------------------------------
  gcl_tree->expand_node( i_node_key = gv_all_node ).
  gcl_tree->update_calculations( ).
  gcl_tree->frontend_update( ).

ENDFORM.

*&---------------------------------------------------------------------*
*& Form add_node
*& ps_data      : 노드에 담길 실제 데이터 (오른쪽 숫자 컬럼)
*& pv_text      : 왼쪽 계층 컬럼에 표시될 텍스트
*& pv_relat_key : 부모 노드 키 (space면 최상위 루트)
*& pv_node_key  : 생성된 노드의 고유 키 반환 (자식 연결 시 부모로 사용)
*&---------------------------------------------------------------------*
FORM add_node USING ps_data      LIKE gs_data
                    pv_text
                    pv_relat_key TYPE lvc_nkey
                    pv_node_key  TYPE lvc_nkey.

  DATA lv_node_text TYPE lvc_value.
  lv_node_text = pv_text.

  gcl_tree->add_node(
    EXPORTING
      i_relat_node_key = pv_relat_key
      i_relationship   = cl_gui_column_tree=>relat_last_child
      i_node_text      = lv_node_text
      is_outtab_line   = ps_data
    IMPORTING
      e_new_node_key   = pv_node_key ).

ENDFORM.

 

 

EVENT

*&---------------------------------------------------------------------*
*& Include          ZRE3FI0008_C01
*&---------------------------------------------------------------------*
CLASS lcl_event_handler DEFINITION FINAL.
  PUBLIC SECTION.

    CLASS-METHODS:
      handle_node_click
        FOR EVENT node_double_click OF cl_gui_alv_tree
        IMPORTING node_key.

ENDCLASS.
*&---------------------------------------------------------------------*
*& Class (Implementation) lcl_event_handler
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
CLASS lcl_event_handler IMPLEMENTATION.

  METHOD handle_node_click.

    PERFORM filter_detail USING node_key.

  ENDMETHOD.

ENDCLASS.
*&---------------------------------------------------------------------*
*& Form filter_detail
*& 트리 노드 클릭 시 우측 Grid 필터링
*& - 전체 노드: 전체 조회
*& - Lv.1 폴더: anlkl 조건
*& - Lv.2 리프: anln1 조건
*&---------------------------------------------------------------------*
FORM filter_detail USING pv_node_key TYPE lvc_nkey.

  DATA: ls_node  LIKE gs_data,
        lr_anln1 TYPE RANGE OF zte3cm0002-anln1,
        lr_anlkl TYPE RANGE OF zte3cm0002-anlkl.

  " 클릭한 노드의 outtab 데이터 읽기
  gcl_tree->get_outtab_line(
    EXPORTING i_node_key    = pv_node_key
    IMPORTING e_outtab_line = ls_node ).

  " 노드 종류 판단 → RANGE 조건 세팅
  IF pv_node_key NE gv_all_node.                     " 전체가 아니면

    IF ls_node-anln1 IS NOT INITIAL.                 " Lv.2 리프 클릭
      lr_anln1 = VALUE #( ( sign='I' option='EQ' low=ls_node-anln1 ) ).

    ELSEIF ls_node-anlkl IS NOT INITIAL.             " Lv.1 폴더 클릭
      lr_anlkl = VALUE #( ( sign='I' option='EQ' low=ls_node-anlkl ) ).

    ENDIF.
  ENDIF.

  " CDS에서 조건에 맞는 월별 감가상각 조회
  REFRESH gt_item.
  SELECT bukrs, anln1, anlnt, waers,
         m01, m02, m03, m04, m05, m06,
         m07, m08, m09, m10, m11, m12
    FROM zcds_e3_cm_0001_i
   WHERE bukrs = @pa_bukrs
     AND ( gjahr = @pa_gjahr OR gjahr IS NULL )
     AND anln1 IN @lr_anln1
     AND anlkl IN @lr_anlkl
    INTO CORRESPONDING FIELDS OF TABLE @gt_item.

  gcl_grid->refresh_table_display(
    EXPORTING is_stable = gs_stable i_soft_refresh = space ).

ENDFORM.

PBO 에 EVENT 등록

FORM create_tree .

  DATA: l_hierarchy_header TYPE treev_hhdr.

  l_hierarchy_header-heading   = '자산명'.
  l_hierarchy_header-width     = 25.
  l_hierarchy_header-width_pix = space.

  CREATE OBJECT gcl_tree
    EXPORTING
      parent              = gcl_tree_con
      node_selection_mode = cl_gui_column_tree=>node_sel_mode_single
      item_selection      = space
      no_html_header      = 'X'
      no_toolbar          = space
    EXCEPTIONS
      OTHERS              = 1.

  " 이벤트 등록
  CALL METHOD gcl_tree->get_registered_events
    IMPORTING
      events = gt_event.

  gs_event-eventid    = cl_gui_column_tree=>eventid_node_double_click.
  gs_event-appl_event = 'X'.
  APPEND gs_event TO gt_event.

  CALL METHOD gcl_tree->set_registered_events
    EXPORTING
      events = gt_event.

  SET HANDLER lcl_event_handler=>handle_node_click FOR gcl_tree.

  gs_variant-report = sy-repid.

  CALL METHOD gcl_tree->set_table_for_first_display
    EXPORTING
      i_save              = 'A'
      is_variant          = gs_variant
      is_hierarchy_header = l_hierarchy_header
    CHANGING
      it_outtab           = gt_make_tree
      it_fieldcatalog     = gt_fcat_tree.

ENDFORM.

 

LAYOUT

FORM set_tree_header .

  PERFORM set_fcat_tree USING:
      'APRICE' '취득원가' 'ZTE3CM0002' 'APRICE' '8',
      'ACCUM'  '감가누계' 'ZTE3CM0002' 'ACCUM'  '8',
      'BOOK'   '장부가액' 'ZTE3CM0002' 'APRICE' '8',
      'WAERS'   '통화' 'ZTE3CM0002' 'WAERS' '8'.

ENDFORM.
*&---------------------------------------------------------------------*
*& Form set_fcat_tree
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
*&      --> P_
*&      --> P_
*&      --> P_
*&      --> P_
*&      --> P_
*&---------------------------------------------------------------------*
FORM set_fcat_tree   USING   pv_field
                             pv_text
                             pv_ref_table
                             pv_ref_field
                             pv_len.

  gs_fcat-fieldname = pv_field.
  gs_fcat-coltext   = pv_text.
  gs_fcat-ref_table = pv_ref_table.
  gs_fcat-ref_field = pv_ref_field.
  gs_fcat-outputlen = pv_len.

  CASE pv_field.
    WHEN 'APRICE' OR 'ACCUM' OR 'BOOK'.
      gs_fcat-cfieldname = 'WAERS'.
      gs_fcat-do_sum     = 'X'.

  ENDCASE.

  APPEND gs_fcat TO gt_fcat_tree.
  CLEAR  gs_fcat.

ENDFORM.