Эта публикация предназначена ABAP-разработчикам в SAP ERP и всем им сочувствующим.
Немногие знают, что в ALV можно подключать HTML-заголовки. Еще больше не знают, что можно сделать красивый стандартный выпадающий список, он же select-box, только для такой по сути стандартной фичи, потребуется много вашего Z-кода.
Выглядит примерно так:
Добро пожаловать под кат.
Поехали! Определим глобальные переменные:
— Выходная таблица нашего отчета, пусть она будет на основе всем известной таблицы MARA;
— Переменная, в которой мы будем хранить текущее значение выбранной в селект-боксе;
— константу с подпрограммой для HTML-header;
— класс-handler, который будет срабатывать при выборе данных, и объект handler.
*----------------------------------------------------------------------*
* Определение глобальных переменных
*----------------------------------------------------------------------*
TYPE-POOLS: slis.
TABLES: mara.
DATA:
gt_data TYPE TABLE OF mara WITH HEADER LINE,
gv_matnr TYPE mara-matnr.
CONSTANTS:
gc_form_top TYPE slis_formname VALUE 'DO_HTML_TOP_OF_PAGE'.
*----------------------------------------------------------------------*
* CLASS cl_my_event_handler DEFINITION
*----------------------------------------------------------------------*
CLASS cl_my_event_handler DEFINITION.
PUBLIC SECTION.
METHODS:
handle_selections FOR EVENT selected OF cl_dd_select_element
IMPORTING sender.
ENDCLASS.
DATA:
go_hand1 TYPE REF TO cl_my_event_handler.
Напишем главную программу отчета и подпрограммы по инициализации, получении данных и выводе отчета. Здесь особо отмечу, что нужно создать объект handler и подключить HTML-заголовок: i_callback_html_top_of_page = gc_form_top.
*----------------------------------------------------------------------*
* Отчет
*----------------------------------------------------------------------*
SELECT-OPTIONS:
so_matnr FOR mara-matnr.
INITIALIZATION.
PERFORM init.
START-OF-SELECTION.
PERFORM get_data.
END-OF-SELECTION.
PERFORM reuse_alv.
*&---------------------------------------------------------------------*
*& Form init
*&---------------------------------------------------------------------*
FORM init.
" -------------------------------------------------- "
" Создадим объект хендлера
" -------------------------------------------------- "
CREATE OBJECT go_hand1.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form get_data
*&---------------------------------------------------------------------*
FORM get_data.
" -------------------------------------------------- "
" Получим данные
" -------------------------------------------------- "
SELECT *
FROM mara
INTO TABLE gt_data
WHERE matnr IN so_matnr.
CHECK: sy-subrc IS INITIAL.
SORT: gt_data BY matnr.
ENDFORM. "get_data
*&---------------------------------------------------------------------*
*& Form reuse_alv
*&---------------------------------------------------------------------*
FORM reuse_alv.
DATA: lt_fieldcat TYPE TABLE OF lvc_s_fcat.
CHECK gt_data[] IS NOT INITIAL.
" -------------------------------------------------- "
" Вывод ALV
" -------------------------------------------------- "
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = 'MARA'
CHANGING
ct_fieldcat = lt_fieldcat[]
EXCEPTIONS
inconsistent_interface = 1
program_error = 2
OTHERS = 3.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_callback_program = sy-repid
i_callback_html_top_of_page = gc_form_top
it_fieldcat_lvc = lt_fieldcat[]
i_save = 'A'
TABLES
t_outtab = gt_data[].
ENDFORM. "reuse_alv
Для HTML-хедера создаем подпрограмму с именем, указанным в глобальном константе. Вызовем из нее подпрограмму, которая создаст нашу красоту:
*&---------------------------------------------------------------------*
*& Form do_html_top_of_page
*&---------------------------------------------------------------------*
FORM do_html_top_of_page USING p_doc TYPE REF TO cl_dd_document.
DATA: lo_form TYPE REF TO cl_dd_form_area,
lo_sele TYPE REF TO cl_dd_select_element.
" -------------------------------------------------- "
" Создадим область
" -------------------------------------------------- "
CALL METHOD p_doc->add_form
IMPORTING
formarea = lo_form.
" -------------------------------------------------- "
" Создадим селект-бокс
" -------------------------------------------------- "
PERFORM add_casebox
TABLES
gt_data
CHANGING
gv_matnr
lo_form
lo_sele.
ENDFORM. "do_html_top_of_page
Посмотрим подпрограмму по созданию селект-бокса. Здесь отмечу, что если в отчете была команда, снять фильтры, зачищаем нашу глобальную переменную (gv_matnr) со значением. Потом создаем линию, в которую добавляем заголовок фильтра, вызываем подпрограмму, которая заполнит нам значения в нем, и сам фильтр на форму, закрываем линию:
*&---------------------------------------------------------------------*
*& Form add_casebox
*&---------------------------------------------------------------------*
FORM add_casebox
*&---------------------------------------------------------------------*
TABLES
it_data STRUCTURE mara
CHANGING
iv_matnr TYPE mara-matnr
lo_form TYPE REF TO cl_dd_form_area
lo_selec TYPE REF TO cl_dd_select_element.
*&---------------------------------------------------------------------*
DATA: lt_opt_tab TYPE sdydo_option_tab,
lv_text TYPE sdydo_text_element.
*----------------------------------------------------------------------*
DO.
CASE sy-index.
WHEN 1.
" -------------------------------------------------- "
" Отмена фильтров
" -------------------------------------------------- "
CHECK sy-ucomm EQ '&ILD'.
CLEAR: iv_matnr.
WHEN 2.
" -------------------------------------------------- "
" Начало линии
" -------------------------------------------------- "
CALL METHOD lo_form->line_with_layout
EXPORTING
start = 'X'.
WHEN 3.
" -------------------------------------------------- "
" Заголовок селект-бокса
" -------------------------------------------------- "
lv_text = 'Материал:'.
CALL METHOD lo_form->add_text
EXPORTING
text = lv_text.
WHEN 4.
" -------------------------------------------------- "
" Разделитель
" -------------------------------------------------- "
CALL METHOD lo_form->add_gap
EXPORTING
width = 2.
WHEN 5.
" -------------------------------------------------- "
" Заполним таблицу значений
" -------------------------------------------------- "
PERFORM fill_mat_tab
TABLES it_data
CHANGING iv_matnr
lt_opt_tab.
WHEN 6.
" -------------------------------------------------- "
" Добавим сам селект-бокс
" -------------------------------------------------- "
CALL METHOD lo_form->add_select_element
EXPORTING
OPTIONS = lt_opt_tab
value = 'P'
IMPORTING
select_element = lo_selec.
WHEN 7.
" -------------------------------------------------- "
" Подключим хендлер
" -------------------------------------------------- "
SET HANDLER go_hand1->handle_selections
FOR lo_selec.
WHEN 8.
" -------------------------------------------------- "
" Окончание линии
" -------------------------------------------------- "
CALL METHOD lo_form->line_with_layout
EXPORTING
end = 'X'.
WHEN OTHERS.
EXIT.
ENDCASE.
ENDDO.
ENDFORM.
В программе по заполнению фильтра добавим сначала то значение, которое сейчас выбрано, чтобы оно было первым в списке. Потом добавим значение Все, если у нас в таблице больше одного значения. И потом все записи из таблицы:
*&---------------------------------------------------------------------*
*& Form fill_mat_tab
*&---------------------------------------------------------------------*
FORM fill_mat_tab
*&---------------------------------------------------------------------*
TABLES
it_data STRUCTURE mara
CHANGING
iv_matnr TYPE matnr
it_optab TYPE sdydo_option_tab.
*&---------------------------------------------------------------------*
DATA: ls_opt TYPE sdydo_option.
REFRESH: it_optab.
*----------------------------------------------------------------------*
DO.
CASE sy-index.
WHEN 1.
" -------------------------------------------------- "
" Сохраним значение если оно выбрано
" -------------------------------------------------- "
CHECK iv_matnr IS NOT INITIAL.
ls_opt-value = iv_matnr.
ls_opt-text = iv_matnr.
APPEND ls_opt TO it_optab.
WHEN 2.
" -------------------------------------------------- "
" Если значение не одно, добавим строчку - Все
" -------------------------------------------------- "
READ TABLE it_data INDEX 1.
LOOP AT it_data TRANSPORTING NO FIELDS WHERE matnr NE it_data-matnr.
ls_opt-value = '*'.
ls_opt-text = 'Все'.
APPEND ls_opt TO it_optab.
EXIT.
ENDLOOP.
WHEN 3.
" -------------------------------------------------- "
" Добавим все значения
" -------------------------------------------------- "
LOOP AT it_data WHERE matnr IS NOT INITIAL.
ls_opt-value = it_data-matnr.
ls_opt-text = it_data-matnr.
COLLECT ls_opt INTO it_optab.
ENDLOOP.
WHEN OTHERS.
EXIT.
ENDCASE.
ENDDO.
ENDFORM.
Внедрим наш handler. Здесь в sender->value значение, выбранное пользователем. Запишем его сразу в нашу глобальную переменную gv_matnr. В подпрограмме set_filter по обработке стандартной фильтрации:
1) Получим глобальный grid в локальный объект;
2) Получим уже установленные параметры фильтрации, и снимем уже установленный ранее фильтр, по полю, которое мы фильтруем, через селект-бокс;
3) Добавим новые параметры фильтрации;
4) Сохраним фильтр;
5) Обновим отчет.
*----------------------------------------------------------------------*
* CLASS cl_my_event_handler IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS cl_my_event_handler IMPLEMENTATION.
METHOD handle_selections.
DATA text_buff TYPE sdydo_text_element.
text_buff = sender->value.
gv_matnr = text_buff.
" -------------------------------------------------- "
" Установим фильтр в отчете
" -------------------------------------------------- "
PERFORM set_filter
TABLES
gt_data
USING
gv_matnr
.
ENDMETHOD. "handle_selections
ENDCLASS. "cl_my_event_handler IMPLEMENTATION
*&---------------------------------------------------------------------*
*& Form set_filter
*&---------------------------------------------------------------------*
FORM set_filter
*&---------------------------------------------------------------------*
TABLES
it_data STRUCTURE mara
USING
iv_value TYPE mara-matnr.
*&---------------------------------------------------------------------*
DATA: lo_ref1 TYPE REF TO cl_gui_alv_grid,
lt_filtered TYPE lvc_t_filt,
lv_field TYPE char10 VALUE 'MATNR',
ls_filter LIKE LINE OF lt_filtered.
*----------------------------------------------------------------------*
DO.
CASE sy-index.
WHEN 1.
" -------------------------------------------------- "
" Получим объект ALV
" -------------------------------------------------- "
CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
IMPORTING
e_grid = lo_ref1.
WHEN 2.
" -------------------------------------------------- "
" Получим итоги и уберем фильтр уст. в прошлый раз
" -------------------------------------------------- "
CALL METHOD lo_ref1->get_filter_criteria
IMPORTING
et_filter = lt_filtered.
DELETE lt_filtered WHERE fieldname = lv_field.
WHEN 3.
" -------------------------------------------------- "
" Добавим новый фильтр
" -------------------------------------------------- "
CHECK iv_value NE ''
AND iv_value NE '*'.
ls_filter-fieldname = lv_field.
ls_filter-sign = 'I'.
ls_filter-option = 'EQ'.
ls_filter-low = iv_value.
APPEND ls_filter TO lt_filtered.
WHEN 4.
" -------------------------------------------------- "
" Сохраним фильтр
" -------------------------------------------------- "
CALL METHOD lo_ref1->set_filter_criteria
EXPORTING
it_filter = lt_filtered
EXCEPTIONS
no_fieldcatalog_available = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
WHEN 5.
" -------------------------------------------------- "
" Обновим ALV
" -------------------------------------------------- "
lo_ref1->refresh_table_display( ).
WHEN OTHERS.
EXIT.
ENDCASE.
ENDDO.
ENDFORM.
Запускаем! Любуемся на итог страданий:
Вроде простая штука, а в SAPе нужно постараться еще. Всем спасибо.
Автор: Endrews