Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
EnnoWulff
Active Contributor
11,442
If you want to provide a user the possibility to select multiple values from a list then you normally have - in other programming languages - a control containing items an the possibiity to mark or unmark them. It's called a listbox in Visual Basic for example. You eather choose items by holding CTRL key pressed or clicking the check box of the desired list items.

In ABAP you do not have such a simple control; you must build your own.

Using SALV


The most obvious way probably would be to use an SALV as a multi selection box which could look something like this:



The cl_gui_selection_box (no, it does not exist. yet...) can be easily enhanced by adding colors:



By clicking the checkbox the color of the line changes to green.

You could also use Icons instead of the checkbox:





If you would like to invest a little more time you can simulate a modern UI (kind of...):



You can also use the standard row selection of the SALV by marking the lines at the most left side of the SALV table. The user will then have to hold CTRL key to select more than one line. This is a bit problematic because if the user clicks somewehre else in the table the selection will get lost.

Using The Toolbar


A different way to achieve the goal of mutliple selections is using the toolbar-control CL_GUI_TOOLBAR. Here you can define a button as checked which indicates that this button or option is set or active. Using Icons the result might look something like this:


Disadvantages


All the above solutions - which really look quite cool, don't they? - have one major disadvantage: The cost quite a lot amount of space. If selecting some options from a list is not part of a process step or if there is simply not enought place for showing this control than you use a dropdown menu.

The main advantage of these lists is that you always can see all selected and not selected options.

Using CL_CTMENU


The menu is quite a good option for displaying selected or unselected values because every menu item can be checked or not. If checked it will have a small circle in front of the option:



The disadvantage is that you cannot see all the selected options. You will have to click the menu to see which options are marked.

This dropdown menu has another disadvantage: After hitting an option the menu disappears and you will have to click again.

And this actually is the main reason for posting this: I had the idea to raise the dropdown-menu-clicked-event again after having selected an entry and rebuild the menu. The effect is that you can select an option, the menu entry will be changed to checked and right after the click the menu will be displayed again.

The effect can be set by using the DISPATCH method.

Ennotations & Ennohancements


:)

Modularization


This code is a very good example to show how to build a general function that could be used in several different programs. You will have to add some methods so that a programmer can work with it (setting options, getting th results, placing the control in a given container, setting Icons and so) but I think it's easy to imagine that such a tool can be very good re-used.

Customizing


With the given coding you can make the class customizable so that the programmer can set icons to be used, displaying titles etc. You could also use this mutliple selection control as a radio button alternative. just make sure that after selecting an option the oter options are unselected.

Multiple States


I could also imagine multiple states which iteratively will be set after clicking: Not only ON and OFF but GREEN, YELLOW, RED or MUST, SHOULD, CAN'T.

Dynamic programming


Dealing with tables where the structure is unknown could also be a possible option. Just pass the table to the class and tell the class which field is the one to use for marking and which one is the text field to display. Using ASSIGN COMPONENT (fieldname_for_text) OF STRUCTURE ... you can provide an easy way for selecting mutliple lines of any table.

Code now on github


via abapGit

https://github.com/tricktresor/multiple_selections

Code For Dropdown Menu


REPORT.


CLASS lcl_main DEFINITION.
PUBLIC SECTION.
METHODS display.

PROTECTED SECTION.
TYPES: BEGIN OF ty_option,
value TYPE char10,
text TYPE string,
checked TYPE boolean_flg,
END OF ty_option.
DATA: mytoolbar TYPE REF TO cl_gui_toolbar,
menupos_x TYPE i,
menupos_y TYPE i,
options TYPE STANDARD TABLE OF ty_option,
menu_dynamic TYPE REF TO cl_ctmenu.
METHODS build_menu.
METHODS on_function_selected FOR EVENT function_selected OF cl_gui_toolbar
IMPORTING fcode sender.
METHODS on_dropdown_clicked FOR EVENT dropdown_clicked OF cl_gui_toolbar
IMPORTING fcode posx posy sender.
ENDCLASS. "lcl_my_event_handler DEFINITION



CLASS lcl_main IMPLEMENTATION.

METHOD build_menu.

IF menu_dynamic IS INITIAL.
"Create menu
CREATE OBJECT menu_dynamic.
ELSE.
"Clear all entries before rebuild
menu_dynamic->clear( ).
ENDIF.

LOOP AT options ASSIGNING FIELD-SYMBOL(<option>).
"add menu entry with current status
menu_dynamic->add_function( fcode = CONV #( <option>-value )
checked = <option>-checked
text = CONV #( <option>-text ) ).

ENDLOOP.

ENDMETHOD.

METHOD display.

"Create docker on Top of the screen
DATA(docker) = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_top extension = 30 ).

"create toolbar object
mytoolbar = NEW #( parent = docker ).

"register events
mytoolbar->set_registered_events( VALUE #( ( eventid = cl_gui_toolbar=>m_id_function_selected )
( eventid = cl_gui_toolbar=>m_id_dropdown_clicked ) ) ).

"Set handler
SET HANDLER on_function_selected FOR mytoolbar.
SET HANDLER on_dropdown_clicked FOR mytoolbar.

"set initial values
options = VALUE #( ( value = 'ONE' text = 'Option One' )
( value = 'TWO' text = 'Option Two' )
( value = 'THREE' text = 'Option Three' )
( value = 'FOUR' text = 'Option Four' ) ).
"Build menu
build_menu( ).

"Add button for selecting options
mytoolbar->add_button( EXPORTING
icon = 'ICON_TOOL'
fcode = 'CHOOSE'
butn_type = '1'
text = 'Select options'
quickinfo = 'Select some options...'
EXCEPTIONS
cntb_error_fcode = 1 ).

ENDMETHOD.

METHOD on_function_selected.

"switch option entry
LOOP AT options ASSIGNING FIELD-SYMBOL(<option>).
IF <option>-value = fcode.
IF <option>-checked = abap_true.
<option>-checked = abap_false.
ELSE.
<option>-checked = abap_true.
ENDIF.
ENDIF.
ENDLOOP.

"rebuild menu
build_menu( ).

"raise event dropdown clicked again
sender->dispatch( cargo = 'mytoolbar' eventid = cl_gui_toolbar=>m_id_dropdown_clicked is_shellevent = abap_false ).

"Set coordinates of menu
sender->track_context_menu(
context_menu = menu_dynamic
posx = menupos_x
posy = menupos_y ).

ENDMETHOD. "lcl_my_event_handler

METHOD on_dropdown_clicked.

IF fcode = 'CHOOSE'.
"call of dropdown: remember current position for displaying menu
menupos_x = posx.
menupos_y = posy.
ENDIF.

"Set coordinates
mytoolbar->track_context_menu(
context_menu = menu_dynamic
posx = posx
posy = posy ).

ENDMETHOD. "lcl_my_event_handler

ENDCLASS. "lcl_my_event_handler IMPLEMENTATION


INITIALIZATION.

new lcl_main( )->display( ).


PARAMETERS p_test.

Code For SALV List


REPORT .

CLASS lcl_main DEFINITION.
PUBLIC SECTION.
TYPES: BEGIN OF ty_option,
mark TYPE boolean_flg,
icon type icon_d,
key TYPE c LENGTH 10,
text TYPE c LENGTH 100,
_col_ TYPE lvc_t_scol,
END OF ty_option,
ty_options TYPE STANDARD TABLE OF ty_option with DEFAULT KEY.
METHODS set IMPORTING options TYPE ty_options.
METHODS get RETURNING VALUE(options) TYPE ty_options.
METHODS display.
PROTECTED SECTION.
DATA mt_options TYPE ty_options.
DATA mo_salv TYPE REF TO cl_salv_table.
METHODS on_click FOR EVENT link_click OF cl_salv_events_table IMPORTING row column sender.
METHODS set_colors.
ENDCLASS.

CLASS lcl_main IMPLEMENTATION.
METHOD set.
mt_options = options.
set_colors( ).
ENDMETHOD.

METHOD get.
options = mt_options.
ENDMETHOD.

METHOD display.

DATA(docker) = NEW cl_gui_docking_container( extension = 200 side = cl_gui_docking_container=>dock_at_left ).

DATA o_column TYPE REF TO cl_salv_column_table.

cl_salv_table=>factory( EXPORTING r_container = docker
IMPORTING r_salv_table = mo_salv
CHANGING t_table = mt_options ).

DATA(layout) = mo_salv->get_display_settings( ).
layout->set_list_header( 'Select option' ).



DATA(columns) = mo_salv->get_columns( ).
columns->set_color_column( '_COL_' ).
columns->set_headers_visible( abap_false ).

o_column ?= columns->get_column( 'MARK' ).
* o_column->set_cell_type( if_salv_c_cell_type=>checkbox_hotspot ).
o_column->set_technical( abap_true ).

o_column ?= columns->get_column( 'ICON' ).
o_column->set_cell_type( if_salv_c_cell_type=>hotspot ).
o_column->set_icon( abap_true ).

o_column ?= columns->get_column( 'KEY' ).
o_column->set_technical( abap_true ).

o_column ?= columns->get_column( 'TEXT' ).

mo_salv->display( ).

DATA(handler) = mo_salv->get_event( ).
SET HANDLER on_click FOR handler.


ENDMETHOD.
METHOD on_click.

READ TABLE mt_options ASSIGNING FIELD-SYMBOL(<option>) INDEX row.
IF sy-subrc = 0.
IF <option>-mark = abap_true.
<option>-mark = abap_false.
<option>-icon = icon_led_red.
CLEAR <option>-_col_.
APPEND INITIAL LINE TO <option>-_col_ ASSIGNING FIELD-SYMBOL(<col>).
* <col>-color-col = col_background.
ELSE.
<option>-mark = abap_true.
<option>-icon = icon_led_green.
CLEAR <option>-_col_.
APPEND INITIAL LINE TO <option>-_col_ ASSIGNING <col>.
* <col>-color-col = col_positive.
ENDIF.
ENDIF.

mo_salv->refresh( ).
DATA(selections) = mo_salv->get_selections( ).
selections->set_selected_cells( VALUE #( ) ).


ENDMETHOD.

METHOD set_colors.

LOOP AT mt_options ASSIGNING FIELD-SYMBOL(<option>).
CLEAR <option>-_col_.
APPEND INITIAL LINE TO <option>-_col_ ASSIGNING FIELD-SYMBOL(<col>).
IF <option>-mark = abap_false.
* <col>-color-col = col_background.
<option>-icon = icon_led_red.
ELSE.
* <col>-color-col = col_positive.
<option>-icon = icon_led_green.
ENDIF.
ENDLOOP.

ENDMETHOD.
ENDCLASS.
PARAMETERS p_dummy.

INITIALIZATION.

DATA(main) = NEW lcl_main( ).
main->set( VALUE #( ( text = `One` key = '1' )
( text = `Two` key = '2' )
( text = `Three` key = '3' )
( text = `Four` key = '4' )
) ).
main->display( ).

AT SELECTION-SCREEN.
cl_demo_output=>display_data( main->get( ) ).

Code For Menu Buttons


REPORT.

CLASS lcl_main DEFINITION.
PUBLIC SECTION.
METHODS display.

PROTECTED SECTION.
TYPES: BEGIN OF ty_option,
value TYPE char10,
text TYPE string,
checked TYPE boolean_flg,
END OF ty_option.
DATA: mytoolbar TYPE REF TO cl_gui_toolbar,
options TYPE STANDARD TABLE OF ty_option.
METHODS build_menu.
METHODS on_function_selected FOR EVENT function_selected OF cl_gui_toolbar
IMPORTING fcode sender.

ENDCLASS. "lcl_my_event_handler DEFINITION


CLASS lcl_main IMPLEMENTATION.

METHOD build_menu.

DATA lv_icon TYPE icon_text.

IF mytoolbar IS INITIAL.
"Create docker on Top of the screen
DATA(docker) = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_left extension = 130 ).


"create toolbar object
mytoolbar = NEW #( parent = docker
display_mode = cl_gui_toolbar=>m_mode_vertical ).

"register events
mytoolbar->set_registered_events( VALUE #( ( eventid = cl_gui_toolbar=>m_id_function_selected ) ) ).

"Set handler
SET HANDLER on_function_selected FOR mytoolbar.
ELSE.
mytoolbar->delete_all_buttons( ).
ENDIF.

LOOP AT options ASSIGNING FIELD-SYMBOL(<option>).
IF <option>-checked = abap_false.
* lv_icon = icon_led_red.
* lv_icon = icon_space.
lv_icon = icon_unlocked.
ELSE.
* lv_icon = icon_led_green.
* lv_icon = icon_alarm.
lv_icon = icon_locked.
ENDIF.
"add menu entry with current status
mytoolbar->add_button( fcode = CONV #( <option>-value )
icon = lv_icon
is_checked = <option>-checked
butn_type = cntb_btype_button
text = CONV #( <option>-text ) ).

ENDLOOP.

ENDMETHOD.

METHOD display.


"set initial values
options = VALUE #( ( value = 'ONE' text = 'Option One' )
( value = 'TWO' text = 'Option Two' )
( value = 'THREE' text = 'Option Three' )
( value = 'FOUR' text = 'Option Four' ) ).
"Build menu
build_menu( ).


ENDMETHOD.

METHOD on_function_selected.

ASSIGN options[ value = fcode ] TO FIELD-SYMBOL(<option>).
IF sy-subrc = 0.
IF <option>-checked = abap_true.
<option>-checked = abap_false.
ELSE.
<option>-checked = abap_true.
ENDIF.
ENDIF.

build_menu( ).

ENDMETHOD. "lcl_my_event_handler



ENDCLASS. "lcl_my_event_handler IMPLEMENTATION


INITIALIZATION.

NEW lcl_main( )->display( ).


PARAMETERS p_test.
14 Comments
Labels in this area