Для отображения иерархического дерева состоящего из любого числа уровней иерархии в SALV модели используется класс — cl_salv_tree.
Строки в таком дереве называются узлами. Каждый узел, не важно, на каком он уровне, имеет одинаковую структуру со всеми остальными.
Дерево, как и другие классы SALV модели, создается с помощью фабрично-статического метода factory(). При этом при его вызове необходимо передавать не заполненную таблицу с данными, а пустую. Заполнение данных происходит на этапе определения узлов для созданного дерева. Объект дерева можно создать как в полно экранном режиме, так и в контейнере указав параметр r_container. Кроме того можно спрятать заголовок дерева – передав в параметр hide_header значение abap_true (X).
Пример создания дерева, без иерархии:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
REPORT FIELD-SYMBOLS: CLASS PUBLIC SECTION. CLASS-DATA: go_alv_tree TYPE REF TO cl_salv_tree, gt_empty_tab TYPE STANDARD TABLE OF spfli, gt_full_tab TYPE STANDARD TABLE OF spfli. CLASS-METHODS: create_tree, " Создаем и настраиваем объект ALV get_data, " Получение данных из БД create_nodes, " Заполнение дерева данными (создание иерархии) show_tree. " Отображение (обновление) ALV дерева ENDCLASS. START-OF-SELECTION. lcl_report=>get_data( ). lcl_report=>create_tree( ). lcl_report=>create_nodes( ). lcl_report=>show_tree( ). CLASS lcl_report IMPLEMENTATION. METHOD show_tree. go_alv_tree->display( ). ENDMETHOD. METHOD create_nodes. DATA: lo_nodes TYPE REF TO cl_salv_nodes, lo_node TYPE REF TO cl_salv_node. " Получаем ссылку на экземпляр класса упрвления узлами дерева lo_nodes = go_alv_tree->get_nodes( ). SORT gt_full_tab BY carrid. " Заполняем дерево LOOP AT gt_full_tab ASSIGNING <fs_line>. TRY. lo_node = lo_nodes->add_node( related_node = '' relationship = cl_gui_column_tree=>relat_first_child ). " Присвоение узлу данных lo_node->set_data_row( <fs_line> ). CATCH cx_salv_msg. ENDTRY. ENDLOOP. ENDMETHOD. METHOD get_data. SELECT * FROM spfli INTO CORRESPONDING FIELDS OF TABLE gt_full_tab. ENDMETHOD. METHOD create_tree. TRY. cl_salv_tree=>factory( IMPORTING r_salv_tree = go_alv_tree CHANGING t_table = gt_empty_tab ). CATCH cx_salv_error. MESSAGE 'Ошибка при создании объекта ALV' TYPE 'E'. ENDTRY. ENDMETHOD. ENDCLASS. |
Результат работы программы:
Параметр | Описание |
related_node | Ключ узла, к которому будем добавлять узел в качестве дочернего (или братского – к тому же родителю что и у него). Для получения узла в классе cl_salv_node существует метод key. Если значение пустое узел добавляется на самый верхний уровень. |
relationship | Определяет местоположение, которое займет созданный узел, задается константами из класса cl_gui_column_tree:
|
data_row | Данные узла, с той же структурой что использовалась при создании в фабричном методе. |
collapsen_icon | Иконка в свернутом состоянии |
expanded_icon | Иконка в развернутом состоянии |
text | Определяет текст, который вставляется в колонку иерархии для узла |
visible | Видимость узла |
folder | Если поставить в abap_true, узел будет иметь иконку в свернутом состоянии, в случае если нет дочерних элементов |
expander | Определяет отображать ли флажок разворачивания (сворачивания) уровня иерархии для узла |
row_style | Задает стиль (цвет) для узла. Виды стилей находятся в определении интерфейса IF_SALV_C_TREE_STYLE и могут принимать следующие значения:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
METHOD create_nodes. DATA: lo_nodes TYPE REF TO cl_salv_nodes, lo_node TYPE REF TO cl_salv_node, lv_carrid_key TYPE lvc_nkey, lv_expand_icon TYPE SALV_DE_TREE_IMAGE, lv_collapse_icon TYPE SALV_DE_TREE_IMAGE, lv_hier_icon TYPE SALV_DE_TREE_IMAGE, lo_settings TYPE REF TO cl_salv_tree_settings, lv_carrid TYPE spfli-carrid. lv_expand_icon = icon_expand. lv_collapse_icon = icon_collapse. lv_hier_icon = icon_tree. lo_settings = go_alv_tree->get_tree_settings( ). lo_settings->set_hierarchy_header( 'Иерархия' ). lo_settings->set_hierarchy_size( 30 ). lo_settings->set_hierarchy_icon( lv_hier_icon ). " Получаем ссылку на экземпляр класса упрвления узлами дерева lo_nodes = go_alv_tree->get_nodes( ). SORT gt_full_tab BY carrid. " Заполняем дерево LOOP AT gt_full_tab ASSIGNING <fs_line>. IF lv_carrid <> <fs_line>-carrid. TRY. lo_node = lo_nodes->add_node( related_node = '' relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> collapsed_icon = lv_expand_icon expanded_icon = lv_collapse_icon row_style = IF_SALV_C_TREE_STYLE=>emphasized_a text = 'Родительский узел' ). lv_carrid_key = lo_node->get_key( ). CATCH cx_salv_msg. ENDTRY. ELSE. TRY. lo_node = lo_nodes->add_node( related_node = lv_carrid_key relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> collapsed_icon = lv_expand_icon row_style = IF_SALV_C_TREE_STYLE=>emphasized_b expanded_icon = lv_collapse_icon text = 'Дочерний узел' ). CATCH cx_salv_msg. ENDTRY. ENDIF. lv_carrid = <fs_line>-carrid. ENDLOOP. ENDMETHOD. |
Результат работы программы:
Настройка функций
Как и в случае с cl_salv_table, для полноэкранного режима кнопки настраиваются через GUI статус, стандартный можно взять из программы — SALV_DEMO_TREE_SIMPLE. Если дерево отображается в контейнере, то через класс cl_salv_functions_tree . Однако тут нет явного ограничения на использование GUI статуса в полноэкранном режиме, можно вместо него использовать вышеназванный класс, пример настройки кнопок:
1 2 3 4 5 6 |
METHOD setup_functions. go_alv_tree->set_screen_status( pfstatus = 'SALV_STANDARD' REPORT = sy-repid " Скопировали к себе в программу статус set_functions = go_alv_tree->c_functions_all ). ENDMETHOD. |
Или:
1 2 3 4 5 6 |
METHOD setup_functions. DATA: lo_functions TYPE REF TO cl_salv_functions_tree. lo_functions = go_alv_tree->get_functions( ). lo_functions->set_all( ). ENDMETHOD. |
Результат работы:
Если вдруг кнопка суммы не будет работать замените ее функцией — &CALC_SUM.
Настройка колонок
Настройка колонок работает так же как и с cl_salv_table, за исключением того что для настройки колонок в дереве используются классы – cl_salv_columns_tree и cl_salv_column_tree. Пример настройки колонок – включение оптимизации:
1 2 3 4 5 6 7 8 |
METHOD setup_columns. DATA: lo_columns TYPE REF TO cl_salv_columns_tree, lo_column TYPE REF TO cl_salv_column_tree. lo_columns = go_alv_tree->get_columns( ). lo_columns->set_optimize( abap_true ). ENDMETHOD. |
Обработка событий
За обработку событий дерева отвечает класс cl_salv_events_tree. Для дерева можно обработать следующие события:
- TOP_OF_PAGE – для обработки заголовка
- END_OF_PAGE – для обработки подвала
- BEFORE_SALV_FUNCTION – срабатывает до вызова стандартной функции
- AFTER_SALV_FUNCTION – обработка после вызова стандартной функции
- ADDED_FUNCTION – обработка своей функции
- LINK_CLICK – щелчок по активному элементу (кнопка, ссылка и т.п.)
- DOUBLE_CLICK – двойной щелчок
- KEYPRESS – нажатие клавиш
- CHECKBOX_CHANGE – изменение статуса галочки у записи
- EXPAND_EMPTY_FOLDER – при попытке развернуть пустую строку
Пример обработки этих событий можно посмотреть в стандартной программе — SALV_DEMO_TREE_EVENTS.
Настройка ячеек узла
Для настройки ячеек в узле используется класс cl_salv_item. С помощью него можно определить стиль ячейки, вид (кнопка, ссылка и т.п.), возможность редактирования, если тип – галочка (checkbox). Получить экземпляр класса для конкретной ячейки можно из узла, с помощью метода get_item( ‘ИмяЯчейки’). Ниже пример измененного метода настройки иерархии:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
METHOD create_nodes. DATA: lo_nodes TYPE REF TO cl_salv_nodes, lo_node TYPE REF TO cl_salv_node, lv_carrid_key TYPE lvc_nkey, lv_expand_icon TYPE SALV_DE_TREE_IMAGE, lv_collapse_icon TYPE SALV_DE_TREE_IMAGE, lv_hier_icon TYPE SALV_DE_TREE_IMAGE, lo_item TYPE REF TO cl_salv_item, lo_settings TYPE REF TO cl_salv_tree_settings, lv_carrid TYPE spfli-carrid. lv_expand_icon = icon_expand. lv_collapse_icon = icon_collapse. lv_hier_icon = icon_tree. lo_settings = go_alv_tree->get_tree_settings( ). lo_settings->set_hierarchy_header( 'Иерархия' ). lo_settings->set_hierarchy_size( 30 ). lo_settings->set_hierarchy_icon( lv_hier_icon ). " Получаем ссылку на экземпляр класса упрвления узлами дерева lo_nodes = go_alv_tree->get_nodes( ). SORT gt_full_tab BY carrid. " Заполняем дерево LOOP AT gt_full_tab ASSIGNING <fs_line>. IF lv_carrid <> <fs_line>-carrid. TRY. lo_node = lo_nodes->add_node( related_node = '' relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> collapsed_icon = lv_expand_icon expanded_icon = lv_collapse_icon row_style = IF_SALV_C_TREE_STYLE=>emphasized_a text = 'Родительский узел' ). lv_carrid_key = lo_node->get_key( ). lo_item = lo_node->get_item( 'CARRID' ). lo_item->set_type( if_salv_c_item_type=>button ). lo_item = lo_node->get_item( 'CITYFROM' ). lo_item->set_font( if_salv_c_item_font=>fixed_size ). lo_item->set_enabled( abap_false ). CATCH cx_salv_msg. ENDTRY. ELSE. TRY. lo_node = lo_nodes->add_node( related_node = lv_carrid_key relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> collapsed_icon = lv_expand_icon row_style = IF_SALV_C_TREE_STYLE=>emphasized_negative expanded_icon = lv_collapse_icon text = 'Дочерний узел - Дочерний узел' ). lo_item = lo_node->get_item( 'CARRID' ). lo_item->set_type( if_salv_c_item_type=>checkbox ). lo_item->set_editable( abap_true ). CATCH cx_salv_msg. ENDTRY. ENDIF. lv_carrid = <fs_line>-carrid. ENDLOOP. ENDMETHOD. "create_nodes |
Результат работы программы:
Напоследок исходный код программы целиком, c примером обработки событий и обхода дочерних узлов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
REPORT zsalv_tree_sample. FIELD-SYMBOLS: <fs_line> TYPE spfli. INCLUDE <icon>. CLASS lcl_report DEFINITION. PUBLIC SECTION. CLASS-DATA: go_alv_tree TYPE REF TO cl_salv_tree, gt_empty_tab TYPE STANDARD TABLE OF spfli, gt_full_tab TYPE STANDARD TABLE OF spfli. CLASS-METHODS: create_tree, " Создаем и настраиваем объект ALV get_data, " Получение данных из БД setup_functions," Настройка тулбара create_nodes, " Заполнение дерева данными (создание иерархии) setup_columns, " Настройка колонок on_link_click FOR EVENT link_click OF cl_salv_events_tree IMPORTING NODE_KEY, setup_events, show_tree. " Отображение (обновление) ALV дерева ENDCLASS. "lcl_report DEFINITION START-OF-SELECTION. lcl_report=>get_data( ). lcl_report=>create_tree( ). lcl_report=>create_nodes( ). lcl_report=>setup_functions( ). lcl_report=>setup_columns( ). lcl_report=>setup_events( ). lcl_report=>show_tree( ). CLASS lcl_report IMPLEMENTATION. METHOD show_tree. go_alv_tree->display( ). ENDMETHOD. "show_tree METHOD create_nodes. DATA: lo_nodes TYPE REF TO cl_salv_nodes, lo_node TYPE REF TO cl_salv_node, lv_carrid_key TYPE lvc_nkey, lv_expand_icon TYPE SALV_DE_TREE_IMAGE, lv_collapse_icon TYPE SALV_DE_TREE_IMAGE, lv_hier_icon TYPE SALV_DE_TREE_IMAGE, lo_item TYPE REF TO cl_salv_item, lv_count TYPE I, lo_settings TYPE REF TO cl_salv_tree_settings, lv_carrid TYPE spfli-carrid. lv_expand_icon = ICON_CLOSED_FOLDER. lv_collapse_icon = ICON_OPEN_FOLDER. lv_hier_icon = icon_tree. lo_settings = go_alv_tree->get_tree_settings( ). lo_settings->set_hierarchy_header( 'Иерархия' ). lo_settings->set_hierarchy_size( 30 ). lo_settings->set_hierarchy_icon( lv_hier_icon ). " Получаем ссылку на экземпляр класса упрвления узлами дерева lo_nodes = go_alv_tree->get_nodes( ). SORT gt_full_tab BY carrid. " Заполняем дерево LOOP AT gt_full_tab ASSIGNING <fs_line>. IF lv_carrid <> <fs_line>-carrid. TRY. lv_count = 0. LOOP AT gt_full_tab TRANSPORTING NO FIELDS WHERE carrid = <fs_line>-carrid. lv_count = lv_count + 1. ENDLOOP. IF lv_count > 1. lo_node = lo_nodes->add_node( related_node = '' relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> collapsed_icon = lv_expand_icon expanded_icon = lv_collapse_icon row_style = IF_SALV_C_TREE_STYLE=>emphasized_a text = 'Родительский узел' ). ELSE. lo_node = lo_nodes->add_node( related_node = '' relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> collapsed_icon = lv_collapse_icon row_style = IF_SALV_C_TREE_STYLE=>emphasized_a text = 'Родительский узел' ). ENDIF. lv_carrid_key = lo_node->get_key( ). IF lv_count > 1. lo_item = lo_node->get_item( 'CARRID' ). lo_item->set_type( if_salv_c_item_type=>button ). lo_item->set_value( 'Все' ). ENDIF. lo_item = lo_node->get_item( 'CITYFROM' ). lo_item->set_font( if_salv_c_item_font=>fixed_size ). lo_item->set_enabled( abap_false ). CATCH cx_salv_msg. ENDTRY. ELSE. TRY. lo_node = lo_nodes->add_node( related_node = lv_carrid_key relationship = cl_gui_column_tree=>relat_last_child data_row = <fs_line> row_style = IF_SALV_C_TREE_STYLE=>emphasized_negative text = 'Дочерний узел - Дочерний узел' ). lo_item = lo_node->get_item( 'CARRID' ). lo_item->set_type( if_salv_c_item_type=>checkbox ). lo_item->set_editable( abap_true ). CATCH cx_salv_msg. ENDTRY. ENDIF. lv_carrid = <fs_line>-carrid. ENDLOOP. ENDMETHOD. "create_nodes METHOD get_data. SELECT * FROM spfli INTO CORRESPONDING FIELDS OF TABLE gt_full_tab. ENDMETHOD. "get_data METHOD create_tree. TRY. cl_salv_tree=>factory( IMPORTING r_salv_tree = go_alv_tree CHANGING t_table = gt_empty_tab ). CATCH cx_salv_error. MESSAGE 'Ошибка при создании объекта ALV' TYPE 'E'. ENDTRY. ENDMETHOD. "create_tree METHOD setup_functions. go_alv_tree->set_screen_status( pfstatus = 'SALV_STANDARD' REPORT = sy-repid " Скопировали к себе в программу статус set_functions = go_alv_tree->c_functions_all ). ENDMETHOD. METHOD setup_columns. DATA: lo_columns TYPE REF TO cl_salv_columns_tree, lo_column TYPE REF TO cl_salv_column_tree. TRY. lo_columns = go_alv_tree->get_columns( ). lo_columns->set_optimize( abap_true ). lo_column ?= lo_columns->get_column( 'MANDT' ). lo_column->set_technical( abap_true ). lo_column ?= lo_columns->get_column( 'FLTYPE' ). lo_column->set_technical( abap_true ). lo_column ?= lo_columns->get_column( 'PERIOD' ). lo_column->set_technical( abap_true ). CATCH cx_salv_msg cx_salv_not_found. ENDTRY. ENDMETHOD. METHOD on_link_click. DATA: lo_nodes TYPE REF TO cl_Salv_nodes, lo_main_node TYPE REF TO cl_salv_node, lo_item TYPE REF TO cl_salv_item, lo_child_node TYPE REF TO cl_salv_node. lo_nodes = go_alv_tree->get_nodes( ). TRY. lo_main_node = lo_nodes->get_node( node_key ). lo_child_node = lo_main_node->get_first_child( ). WHILE lo_child_node IS BOUND. lo_item = lo_child_node->get_item( 'CARRID' ). IF lo_item->is_checked( ) = abap_true. lo_item->set_checked( abap_false ). ELSE. lo_item->set_checked( abap_true ). ENDIF. lo_child_node = lo_child_node->get_next_sibling( ). ENDWHILE. CATCH cx_salv_msg. EXIT. ENDTRY. ENDMETHOD. METHOD setup_events. DATA: lo_events TYPE REF TO cl_salv_events_tree. lo_events = go_alv_tree->get_event( ). SET HANDLER on_link_click FOR lo_events. ENDMETHOD. ENDCLASS. "lcl_report IMPLEMENTATION |
Вылетает в дамп
Видимо только у Вас
Добрый день. Подскажите, а можно ли сделать, что бы дочерняя структура отличалась от родительской? и можно ли сделать иерархию для нескольких полей, Допустим родительская структура имеет поля ID, Объекты и Участники, и при нажатии на Объекты появлялась иерархия с объектами, а на участники с участниками, спасибо.
Можно попробовать сделать hotspot элементы, при нажатии на которые заменять данные относительно того на что было нажато, но это потребует дополнительной сложности при разработке (динамически обновлять данные, нечто похожее сделано в теме «ненормальное программирование», если конечно я вас правильно понял)
есть возможность обработки события на нажатие по узлу: родительскому и дочернему?….
надо переход в транзакцию сделать именно при нажатии по узлу….и я так понял…событие LINK_CLICK работает только с ячейками
DOUBLE_CLICK не отрабатывает если в ячейке нет значения. Не сталкивались?
Добрый день! Увы нет.
не подскажите как обойти проблему — если для узла сделать
ls_item_layout-class = cl_gui_column_tree=>item_class_checkbox.
то не получается отловить двойной клик на узле.
может можно как то сделать чтобы поле иерархии было не первым в списке.
вообще задача и отметить строку узела и по двойному клику на ней показать экран
К сожалению не сталкивался.
Добрый день. не подскажете, естит ли параметр, чтобы грид выводился сразу с развернутой структурой?
Посмотрите в сторону: CL_SALV_NODES->EXPAND_ALL
Для кнопки суммирования отлично работает функция — &CALC_SUM. Не работает кнопка установки фильтра , какую функцию надо подставить ?
Отличная статья!