DATA lo_alv TYPE REF TO cl_salv_table READ-ONLY.
...
DATA(lo_funcs) = lo_alv->get_functions( ).
lo_funcs->add_function(
EXPORTING
name = 'ZREFRESH'
icon = CONV #( ICON_REFRESH )
text = 'Обновить'
tooltip = 'Обновить'
position = if_salv_c_function_position=>left_of_salv_functions
).
...
DATA(lo_event) = lo_alv->get_event( ).
SET HANDLER on_alv_function FOR lo_event ACTIVATION abap_true.
...
METHODS on_alv_function FOR EVENT added_function OF cl_salv_events IMPORTING sender e_salv_function.
...
METHOD on_alv_function.
CASE e_salv_function.
WHEN 'ZREFRESH'.
...
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
Но данный способ не подойдет, если вы хотите добавить не простую кнопку, а
кнопку с выпадающими действиями типа такой:
Нам нужен способ получить GRID как можно раньше после вызова CL_SALV_TABLE=>DISPLAY, и повесить на него обработчик события TOOLBAR ну и добавить кнопочки с подэлементами. Разобъем задачу на 2 более простых: получение GRID и управление toolbar.
Задача первая. Получаем GRID.
Когда мы вызываем CL_SALV_TABLE=>DISPLAY, то в итоге будет вызыван метод SET_METADATA на адаптере. Внутри он создает GRID. Причем он может это делать 2мя способами:- Напрямую
- Через фабрику строителей
-
Если в параметре cl_alv_z_params=>c_param-alv_gui_instance_builder класса
cl_alv_z_params задано не пустое значение, то вызывается метод
cl_alv_gui_ist_builder_factory=>get_alv_gui_instance_builder без
параметров. Внутри метода:
method get_alv_gui_instance_builder. if mo_alv_gui_instance_builder is not bound. "Later Admin Table? if iv_inst_builder_classname is supplied. data(l_instance_builder_name) = iv_inst_builder_classname. else. l_instance_builder_name = cl_alv_z_params=>get_parameter( cl_alv_z_params=>c_param-alv_gui_instance_builder ). endif. if l_instance_builder_name is initial. ro_instance_builder = new lcl_alv_gui_instance_builder( ). else. create object ro_instance_builder type (l_instance_builder_name). endif. mo_alv_gui_instance_builder = ro_instance_builder. else. ro_instance_builder = mo_alv_gui_instance_builder. endif. endmethod.
- Проверяется, что строитель еще не создан
- Если в метод передано имя класса-строителя, берется оно, иначе берется значение параметра cl_alv_z_params=>c_param-alv_gui_instance_builder
- Если в итоге имя класса-строителя пустое, создается строитель из локального для фабрики класса lcl_alv_gui_instance_builder (который наследуется от CL_ALV_GUI_INSTANCE_BUILDER)
- Иначе создается экземпляр указанного класса (очевидно, он тоже должен наследоваться от CL_ALV_GUI_INSTANCE_BUILDER)
- Созданный экземпляр запоминается в статическом атрибуте фабрики и возвращается при следующих вызовах get_alv_gui_instance_builder
- У строителя вызывается метод create_alv_grid_at_pbo, который должен вернуть ALV_GRID.
- Создавать GRID будем не сами, а используя текущего строителя, которого вернет фабрика. Это позволит работать как прокси, если до вызова нашего кода уже будет зарегистрирован какой-то специфический строитель
- При создании GRID будем генерировать соответствующий Event, на который смогут подписаться заинтересованные обработчики
- Создадим метод для регистрации нового строителя в фабрике
- Создадим метод для разовой регистрации строителя в фабрике. Это позволит регистрировать нашего строителя только на 1 конкретный вызов, после чего устанавливать ранее зарегистрированного строителя
Метод REGISTER_BUILDER_ONCE
METHOD register_builder_once.
DATA(lv_prev_builder_class) = cl_alv_z_params=>get_parameter( cl_alv_z_params=>c_param-alv_gui_instance_builder ).
ro_builder = register_builder( ).
ro_builder->mv_prev_builder_class = lv_prev_builder_class.
ro_builder->mv_restore_on_grid_create = abap_true.
ENDMETHOD.
Метод статический, без параметров, возвращает экземпляр нашего строителя. Таким
образом, вызывающий код может подписаться на событие ON_GRID_CREATE строителя.
Внутри метод получает текущее значение параметра
cl_alv_z_params=>c_param-alv_gui_instance_builder. Затем получает строителя
вызовом метода register_builder и запоминает в экземпляре строителя имя
предыдущего класса строителя из параметра и флаг, что его нужно восстановить.
Восстановление происходит не сразу, а после первого создания ALV_GRID.
Метод REGISTER_BUILDER
METHOD register_builder.
DATA(lo_prev_builder) = cl_alv_gui_ist_builder_factory=>get_alv_gui_instance_builder( ).
DATA(lo_type) = cl_abap_datadescr=>describe_by_data( VALUE tv_prev_builder( ) ).
DATA(lv_name) = lo_type->absolute_name.
REPLACE '\CLASS=' IN lv_name WITH ''.
FIND FIRST OCCURRENCE OF '\' IN lv_name MATCH OFFSET DATA(lv_offset).
IF sy-subrc = 0.
DATA(lv_self_name) = CONV cl_alv_z_params=>y_param_value( lv_name(lv_offset) ).
ELSE.
lv_self_name = lv_name. "Hmm
ENDIF.
cl_alv_z_params=>set_parameter(
EXPORTING
param_name = cl_alv_z_params=>c_param-alv_gui_instance_builder " Parameter name
param_value = lv_self_name
).
ro_builder ?= cl_alv_gui_ist_builder_factory=>new_alv_gui_instance_builder( ).
ro_builder->mo_prev_builder = lo_prev_builder.
ENDMETHOD.
Метод статический, без параметров, возвращает экземпляр нашего строителя. Внутри
метод получает экземпляр текущего класса-строителя, вычисляет имя собственного
класса , заносит его в параметр
cl_alv_z_params=>c_param-alv_gui_instance_builder, создает экземпляр
собственного класса через вызов метода фабрики new_alv_gui_instance_builder (он
принудительно обновляет экземпляр класса строителя в атрибуте фабрики), после
чего запоминает в экземпляре собственного строителя ссылку на предыдущий
экземпляр строителя.
Метод CREATE_ALV_GRID_AT_PBO
Метод экземпляра, переопределеный метод класса CL_ALV_GUI_INSTANCE_BUILDER, получает кучу параметров, возвращает новый экземпляр CL_GUI_ALV_GRID. Логика метода:- Если аттрибут mo_prev_builder не ссылается на экземпляр строителя, то получить его из фабрики
- Вызывать метод CREATE_ALV_GRID_AT_PBO на экземпляре mo_prev_builder, тем самым заставив "работать" логику оригинального строителя по созданию ALV_GRID и запомнить полученный экземпляр GRID в атрибуте mo_alv_grid
- Если установлен флаг mv_restore_on_grid_create, вернуть в настройки фабрики прежнего строителя
- "Дернуть" событие ON_GRID_CREATE передав в него экземпляр только что созданного ALV_GRID
Задача вторая. Добавляем и обрабатываем DropDown кнопки на панель инструментов.
Идея в следующем.- Мы создаем экземпляр некоего класса (назовоем его ZCL_SALV_DRODOWN_TLB), который регистрирует и получает наш ALV_BUILDER и подписывается на его событие ON_GRID_CREATE
- Мы храним в классе структуру наших кнопок (таблица с верхнеуровневыми кнопками и их подпунктами)
- В обработчике события ON_GRID_CREATE класс подписывается на событие TOOLBAR (которое вызывается при построении панели инструментов ALV_GRID) и на событие MENU_BUTTON (которое вызывается на нажатие DropDown кнопки). Также производится отписка от данного события, поскольку нас интересует только 1 GRID
- В обработчике события TOOLBAR к стандартным кнопками добавляеются зарегистрированные в классе верхнеуровневые кнопки как кнопки типа DropDown
- В обработчике события MENU_BUTTON к меню добавляются соответствующие подпункты из нажатой верхнеуровневой кнопки
Как это использовать?
Можно примерное такREPORT ztest_salv_dd.
DATA gt_mara TYPE STANDARD TABLE OF mara.
CONSTANTS:
BEGIN OF cv_alv_toolbar,
BEGIN OF action_dd,
func TYPE salv_de_function VALUE 'ZACTION',
text TYPE string VALUE 'Action',
BEGIN OF send,
func TYPE salv_de_function VALUE 'ZACT_SEND',
text TYPE string VALUE 'Send',
END OF send,
BEGIN OF receive,
func TYPE salv_de_function VALUE 'ZACT_RECEIVE',
text TYPE string VALUE 'Receive',
END OF receive,
END OF action_dd,
END OF cv_alv_toolbar.
CLASS lcl_handler DEFINITION.
PUBLIC SECTION.
CLASS-METHODS on_alv_function FOR EVENT added_function OF cl_salv_events IMPORTING sender e_salv_function.
ENDCLASS.
CLASS lcl_handler IMPLEMENTATION.
METHOD on_alv_function.
CASE e_salv_function.
WHEN cv_alv_toolbar-action_dd-send-func.
MESSAGE cv_alv_toolbar-action_dd-send-text TYPE 'I'.
WHEN cv_alv_toolbar-action_dd-receive-func.
MESSAGE cv_alv_toolbar-action_dd-receive-text TYPE 'I'.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
cl_salv_table=>factory(
EXPORTING
r_container = cl_gui_container=>default_screen
IMPORTING
r_salv_table = DATA(lo_alv)
CHANGING
t_table = gt_mara
).
lo_alv->get_functions( )->set_all(
value = if_salv_c_bool_sap=>true
).
DATA(lo_event) = lo_alv->get_event( ).
SET HANDLER lcl_handler=>on_alv_function FOR lo_event ACTIVATION abap_true.
DATA(go_alv_toolbar) = NEW zcl_salv_drodown_tlb( ).
go_alv_toolbar->add_button(
is_button = VALUE #(
function = cv_alv_toolbar-action_dd-func
text = cv_alv_toolbar-action_dd-text
t_subitem = VALUE #(
( function = cv_alv_toolbar-action_dd-send-func
text = cv_alv_toolbar-action_dd-send-text
)
( function = cv_alv_toolbar-action_dd-receive-func
text = cv_alv_toolbar-action_dd-receive-text
)
)
)
).
lo_alv->display( ).
CALL SCREEN 100.
Естественно, кнопки с выпадающими подпунктами можно добавить только для SALV, которые отображаются в контейнере. Полноэкранные SALV используюут GUI Status для панели инструментов, а там такой функциональности не предусмотрено.
Комментариев нет:
Отправить комментарий