Немногие знают, что в fullscreen ALV можно подключать HTML-заголовки. Еще больше не знают, что можно сделать красивый стандартный выпадающий список, он же select-box, только для такой по сути стандартной фичи, потребуется много вашего Z-кода.
Выглядит примерно так:
![](https://habrastorage.org/files/edf/268/06c/edf26806c1154902b05c6c7152c5874a.png)
Добро пожаловать под кат.
Поехали! Определим глобальные переменные:
— Выходная таблица нашего отчета, пусть она будет на основе всем известной таблицы 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.
Запускаем! Любуемся на итог страданий:
![](https://habrastorage.org/files/03d/407/1a2/03d4071a27ed4624b412766ae70a7aa7.png)
![](https://habrastorage.org/files/55f/b79/1ac/55fb791ac1bb48778d1d124de52c6c95.png)
UPDATE: можно довести до:
![](https://habrastorage.org/files/c41/090/db7/c41090db72524e18b15aac3b48079921.png)
Вроде простая штука, а в SAPе нужно постараться еще. Всем спасибо.
Комментарии (25)
Rupper
22.01.2016 12:01еще при первом знакомстве с абаперами понял, что гвозди бы делать из этих людей.
Такие простыни кода для такого результата вообще никого не удивляют и не расстраивают.
Пользователи, кстати, тоже оказываются в условиях безысходности способны на чудеса запоминания невнятных аббревиатур и кодов.Endrews
22.01.2016 12:07Да уж. меня это тоже порадовало.
Но некоторые вещи в САП действительно удобно и хорошо реализованы. НЕКОТОРЫЕ.
kstep
22.01.2016 18:19+2Вроде у нас 2016 год на дворе. Почему, боже, ну почему подавляющее большинство ERP/CRM систем выглядят как говно из 80-х?
artemlight
22.01.2016 18:38Потому что это никому не нужно. Интуитивность в этих системах может создать иллюзию простоты.
Наша компания вот прям сейчас по этим граблям забег устроила — раньше была «сложная» DMS, а теперь «простая» 1С. Уже полгода расхлёбываем, и края не видно.Zveroloff
22.01.2016 21:32+3Да бог с ней, с интуитивностью. Почему они хотя бы не могут выглядеть аккуратно? Что за страшный курсив в заголовке (он постоянно в сапе попадается)?
occam
25.01.2016 07:49+1Полностью разделяю наблюдению о 80-х и сам регулярно задаюсь тем же вопросом. Есть, конечно, SalesForce и Wave (для управленческого учета), но из них невозможно «вынести» данные с правилами обработки. А все что в формате «сервер-клиент» заставляет задуматься о полной остановке эволюции или конкуренции. SAP, Oracle, 1C, AX и иже с ними — ужасные, громоздкие, разочаровающие тайм-киллеры, не в последнюю очередь из-за своих интерфейсов. Не терпится получить заказ на исследование о том, сколько потерь несет компания, использующая одну из вышеперечисленных erp.
Endrews
25.01.2016 08:38Вообщем конечно ERP-системы не для красоты.
Интерфейс SAP убийственен, но как я слышал, сейчас уже пол Европы работает на SAP UI5, это HTML-версия интерфейса, на JavaScriptivanbolhovitinov
26.01.2016 12:27+1Маркетинговая разводка, имхо. На этом SAP UI5 можно например водить пальцем по айпаду, смотреть красивые дашборды, можно заапрувить заказ на поставку. Увидел, нажал галочку, победил.
А интерфейсов для *создания* заказа на поставку как не было, так и нет. Хотите плодить заказы на поставку в этой красоте неописуемой — пишите сами новый приклад.
occam
26.01.2016 20:46Готов с Вами спорить! Мне кажется, что «не для красоты» могут быть узкоспециализированные (отдельные — от слова «отдел») системы: учетная, финансовая, ТОиР etc. А что касается erp, которая охватывает обычно 70-80% автоматизированных рабочих мест… Извините, но это уже сопоставимо с общим для предприятия регламентом, его тоже можно написать, например, на двух страницах, а можно на 15 с длиной императивных предложений на половину A4. Практика показывает, что предприятия с последним подходом намного чаще «дохнут».
occam
26.01.2016 20:52И насчет пол-европы — это может быть (под вопросом?), а вот в большинстве штатовских бизнесов сап весьма даже гоним и ненужен. Поверьте, как бы смешно это не казалось, через какое-то время erp станет таким же гигееническим фактором оснащенности рабочего места, как кондиционирование или освещенность
ivanbolhovitinov
25.01.2016 15:12Да обычный он, если просто на экране элемент рисоватьEndrews
26.01.2016 11:39Ок, сделайте так:
Фишка, что это hTML, с ним можно еще по извращаться. В статье набросок.
ivanbolhovitinov
26.01.2016 12:08Ага, это понятно, вся красота ШТМЛ в ваших руках.
Кстати, в тему…недавно наткнулся на ABAP-версию игры 2048
Исходники есть в стандартной справке:
help.sap.com/abapdocu_740/en/index.htm?file=abengame_2048_abexa.htm
pavel_pimenov
Можно добавить для сравнения скрин оригинального «не красивого» ComboBox-а
и табличку сравнения в чем минусы-плюсы обоих решений?
Endrews
Оригинальный не возможен в ALV в принципе, Абап-такой-Абап )
ivanbolhovitinov
Как это??? ALV же не обязательно full-screen…
Можно спокойно нарисовать экран с любыми элементами, включая лист-бокс!
Endrews
Вру конечно, может быть оригинальный не full-screen, если отдельно в контейнере нарисовать
impwx
Я тоже, прочитав фразу "красивый стандартный выпадающий список", очень захотел узнать, как в таком случае выглядит некрасивый.