Una interesante herramienta que intenté utilizar en mis primeros años como programador ABAP es el ALV TREE. Desde el comienzo siempre me pareció que podría ser muy agradable para el usuario tener reportes ordenados en Carpetas desplegables, sin embargo, los funcionales de los distintos módulos nunca me solicitaron reportes de este tipo. Es por eso que cada vez que empezaba a estudiar como seria que se hace este tipo de reportes, tenía que suspenderlo debido a que nunca tenía tiempo de investigarlo. Bueno, finalmente aquí está el cómo implementar ALV de forma fácil.

Iniciemos con el objetivo, deseamos crear un ALV TREE similar a los siguientes programas ejemplo estándares BCALV_TREE_DEMO ó BCALV_TREE_02, como vemos a continuación.

1 – Cracion de Dynpro 100 (que contendrá el ALV TREE)

Se deberá crear la dynpro 100 la cual contendrá el ALV TREE

PBO: Definir el status y el titulo

Declarar los Botones SAVE / BACK / CANC

En el PAI: Definimos las acciones que tomarán los botones, BACK y CANC para LEAVE TO CURRENT TRANSACTION. (Por el momento aun no se declaró el RE_ALV_TREE, por lo tanto pueden ignorar eso y esperar hasta que declaremos el objeto)

Declaramos el Objeto sobre la Dynpro, Se debe crear un CUSTOM CONTROLsobre la dynpro 100 del tamaño que ustedes deseen y de nombre TREE_CONTROL

2- Proceso de Datos

En el evento START-OF-SELECTION se debe realizar la búsqueda de datos, el procesamiento y el llamado a la dynpro.

F_BUSQUEDA_DATOS: Realizar las búsquedas de información que se deberán visualizar en el ALV. En nuestro ejemplo se recuperará la información de la tabla de ejemplo ZTREE.
F_ARMA_ALV_TREE: Se encargará de procesar la información para mostrarla en el ALV TREE.

3- Tabla de datos para el ALV

Será la tabla de donde se recuperan los datos para mostrarlos en el ALV

A continuación vemos el contenido de la tabla, donde los estados 1 es Activo y 0 es Anulado

4- Declaraciones de datos del ALV TREE

CONSTANTS: c_tree_container_name TYPE char30 VALUE 'TREE_CONTROL'.
DATA: ok_code  TYPE sy-ucomm.

DATA: re_alv_tree         TYPE REF TO cl_gui_alv_tree,
      re_custom_container TYPE REF TO cl_gui_custom_container,
      re_tree_control     TYPE REF TO cl_item_tree_control.

DATA: wa_hierarchy_header TYPE treev_hhdr,
      wa_variant          type disvariant,
      wa_alv              TYPE zst_alv_tree.

DATA: gt_fieldcat_tree TYPE TABLE OF lvc_s_fcat,
      gt_alv           TYPE TABLE OF zst_alv_tree.

5- Inicializar ALV

Crea el objeto container y el ALV TREE

  "Crea el objeto Container
  CREATE OBJECT re_custom_container
    EXPORTING
      container_name              = c_tree_container_name
    EXCEPTIONS
      cntl_error                  = 1
      cntl_system_error           = 2
      create_error                = 3
      lifetime_error              = 4
      lifetime_dynpro_dynpro_link = 5.
  IF sy-subrc NE 0.
    MESSAGE x208(00) WITH 'ERROR'.
  ENDIF.

  "Crea el ALV TREE
  CREATE OBJECT re_alv_tree
    EXPORTING
      parent                      = re_custom_container
      node_selection_mode         = cl_gui_column_tree=>node_sel_mode_multiple "selección filas
      item_selection              = abap_true    "permite seleccionar columnas
      no_html_header              = 'X'          "Cabecera
      no_toolbar                  = ''
    EXCEPTIONS
      cntl_error                  = 1
      cntl_system_error           = 2
      create_error                = 3
      lifetime_error              = 4
      illegal_node_selection_mode = 5
      failed                      = 6
      illegal_column_name         = 7.
  IF sy-subrc NE 0.
    MESSAGE x208(00) WITH 'ERROR'.
  ENDIF.

Creación de catalogo de campos

  FIELD-SYMBOLS <fs_fieldcat_tree> TYPE lvc_s_fcat.

  "Determina el catalogo del ALV tree
  CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
    EXPORTING
      i_structure_name       = 'ZST_ALV_TREE'  "estructura del ALV TREE
    CHANGING
      ct_fieldcat            = pgt_fieldcat_tree
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.


  "Ajuste de parámetros del catalogo
  LOOP AT pgt_fieldcat_tree ASSIGNING <fs_fieldcat_tree>.

    CASE <fs_fieldcat_tree>-fieldname.
      WHEN 'CLIENTE'.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-no_zero   = 'X'.

      WHEN 'OPERACION'.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-no_zero   = 'X'.
        <fs_fieldcat_tree>-scrtext_l = text-002.  "Operación
        <fs_fieldcat_tree>-scrtext_m = text-003.  "Nro Operación
        <fs_fieldcat_tree>-scrtext_s = text-003.  "Nro Operación

      WHEN 'ESTADO'.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-no_zero   = 'X'.

      WHEN 'TIPO'.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-no_zero   = 'X'.

      WHEN 'DESCRIP'.
        <fs_fieldcat_tree>-outputlen = '000040'.
        <fs_fieldcat_tree>-no_zero   = 'X'.

      WHEN 'CLASE'.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-no_zero   = 'X'.

      WHEN 'CANTIDAD'.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-no_zero   = 'X'.

      WHEN OTHERS.
        <fs_fieldcat_tree>-outputlen = '000020'.
        <fs_fieldcat_tree>-scrtext_l = text-004.  "Cantidad
        <fs_fieldcat_tree>-scrtext_m = text-004.  "Cantidad
        <fs_fieldcat_tree>-scrtext_s = text-004.  "Cantidad
        <fs_fieldcat_tree>-do_sum    = 'X'.
        <fs_fieldcat_tree>-no_sum    = ''.
    ENDCASE.

  ENDLOOP.

Definición de la primer columna del ALV, donde se arma el árbol de carpetas.

  CLEAR pwa_hierarchy_header.
  pwa_hierarchy_header-heading   = text-001. "Operaciones
  pwa_hierarchy_header-width     = 40.       "Ancho de columna
  pwa_hierarchy_header-width_pix = ''.

Definición de eventos

  DATA: lo_events TYPE  cntl_simple_events,
        l_event   TYPE cntl_simple_event.

  " Se appendean eventos a ser registrados en la columna del ALV tree
  l_event-eventid = cl_gui_column_tree=>eventid_node_double_click. "ID doble clicks en nodo
  APPEND l_event TO lo_events.
  l_event-eventid = cl_gui_column_tree=>eventid_header_context_men_req. "ID solicitud de contexto del menú del encabezado
  APPEND l_event TO lo_events.
  l_event-eventid = cl_gui_column_tree=>eventid_expand_no_children. "ID expansión de nodos
  APPEND l_event TO lo_events.
  l_event-eventid = cl_gui_column_tree=>eventid_header_click. "Permite selección de columnas
  APPEND l_event TO lo_events.
  l_event-eventid = cl_gui_column_tree=>eventid_node_context_menu_req.
  APPEND l_event TO lo_events.
  l_event-eventid = cl_gui_column_tree=>eventid_item_context_menu_req.
  APPEND l_event TO lo_events.

  " Se llama al método encargado de registrar eventos en el  ALV tree
  CALL METHOD re_alv_tree->set_registered_events
    EXPORTING
      events                    = lo_events " tabla que contiene ID de eventos
    EXCEPTIONS
      cntl_error                = 1
      cntl_system_error         = 2
      illegal_event_combination = 3.
  IF sy-subrc NE 0.
    MESSAGE x208(00) WITH 'ERROR'.
  ENDIF.

  "Se instancia el objeto que manejara los eventos
  CREATE OBJECT lo_click.

  "Se setea dentro del objeto (lo_click)
  "el método ( handle_node_double_click )
  "dentro de la clase (lcl_tree_event_receiver)
  "que va a manejar el doble click en nodos para ALV (re_alv_tree)
  SET HANDLER lo_click->handle_node_double_click FOR re_alv_tree. "maneja clicks en nodos

Muestra ALV por primera vez (la tabla GT_ALV tiene que estar vacía)

  wa_variant-report = sy-repid.

  "Setea para mostrar por primera vez
  CALL METHOD re_alv_tree->set_table_for_first_display
    EXPORTING
      is_hierarchy_header = wa_hierarchy_header
      "i_save              = 'A'
      "is_variant          = wa_variant
    CHANGING
      it_outtab           = gt_alv[]      "Tabla ALV tiene que estar vacía!!
      it_fieldcatalog     = gt_fieldcat_tree.

6- Definición de nodos

Subrutina F_ADD_FOLDER se encargará de crear una Carpeta dependiendo de los parámetros que se le informen.
Subrutina F_ADD_LEAF se encargará de crear una Hoja (linea del alv) dependiendo de los parámetros que se le informen.

Se recorre la tabla GT_ZTREE y por cada cliente se crean 3 carpetas, una Cliente (con el Nro de cliente de la tabla) y otras dos ACTIVO y CANCELADO.
En cada Carpeta se deberá indicar el Nro de relación de dependencia «Padre» y el «Hijo».
Donde dice SPACE es por que no tiene una carpeta Padre, en el CHANGING se obtendrá la clave para relacionar con dicha carpeta.
Es posible pasar un icono que deseamos que tenga cada carpeta, pueden ver mi otro post de ICONOS.

*&---------------------------------------------------------------------*
*& Form F_ADD_FOLDER
*&---------------------------------------------------------------------*
*  Adiciona una carpeta
*     Esta rubrutina recibe 3 parámetros
*          -P_RELAT_KEY:  Clave relación
*          -P_NODE_TEXT:  Texto del Nodo
*          -P_NODE_IMAGE: Icono
*     Devuelve
*          -P_NEW_KEY: Será la nueva clave para relacionarlo
*&---------------------------------------------------------------------*
FORM f_add_folder USING p_relat_key  TYPE lvc_nkey
                        p_node_text  TYPE lvc_value
                        p_node_icon  TYPE tv_image
                  CHANGING p_new_key TYPE lvc_nkey.

  DATA: gt_item_layout TYPE lvc_t_layi,
        wa_item_layout TYPE lvc_s_layi.

  DATA: wa_node TYPE lvc_s_layn.

  "Layout (imagen / tipo de campo / estilo)
  wa_item_layout-t_image   = p_node_icon.
  wa_item_layout-fieldname = re_alv_tree->c_hierarchy_column_name.
  wa_item_layout-style     = cl_gui_column_tree=>style_intensifd_critical.
  APPEND wa_item_layout TO gt_item_layout.

  "layout de los nodos que colgaran de esta carpeta, es posible cambiar la imagen al desplegar los nodos
  "si se deja vacío coloca icono de hoja
  wa_node-n_image   = '@FN@'. "Contraído: Icono de carpeta cerrada
  wa_node-exp_image = '@FO@'. "Expandido: Icono de carpeta abierta

  "Adiciona NODO
  CALL METHOD re_alv_tree->add_node
    EXPORTING
      i_relat_node_key = p_relat_key
      i_relationship   = cl_gui_column_tree=>relat_last_child
      i_node_text      = p_node_text
      is_node_layout   = wa_node
      it_item_layout   = gt_item_layout
    IMPORTING
      e_new_node_key   = p_new_key.

ENDFORM.

Por cada Cliente determinado en la tabla, se vuelve a recorrer la tabla por los Activos para asociar a la carpeta activo y por los Cancelados para asociar a carpeta cancelados. En la estructura WA_ALV se cargarán los datos de la tabla ALV.

*&---------------------------------------------------------------------*
*& Form F_ADD_LEAF
*&---------------------------------------------------------------------*
*&  Adiciona una hoja
*   En este punto es donde se insertan los datos para el ALV
*&---------------------------------------------------------------------*
FORM f_add_leaf USING pwa_tree     TYPE zst_alv_tree   "Datos para la carga del ALV
                      p_relat_key  TYPE lvc_nkey       "Clave para relacionarlo con una carpeta
                      p_node_text  TYPE lvc_value      "Nombre de la hora (en la 1er columna desplegable)
                CHANGING p_new_key TYPE lvc_nkey.      "Nueva clave para relacionar (en este ejemplo no se usará)

  "Creación de una Hoja, Linea del ALV relacionado con alguna carpeta
  CALL METHOD re_alv_tree->add_node
    EXPORTING
      i_relat_node_key = p_relat_key
      i_relationship   = cl_gui_column_tree=>relat_last_child
      is_outtab_line   = pwa_tree
      i_node_text      = p_node_text
    IMPORTING
      e_new_node_key   = p_new_key.

  CLEAR: pwa_tree.

ENDFORM.

7- Una vez cargada la tabla GT_ALV se debe refrescar el ALV de la siguiente manera

  "Modificar salida del ALV con los datos cargados
  CALL METHOD re_alv_tree->frontend_update.

  "Refresca el ALV en pantalla
  CALL METHOD cl_gui_cfw=>flush
    EXCEPTIONS
      cntl_system_error = 1
      cntl_error        = 2.