[ABAP] SALV-Table: Anzeige in einem DockingContainer, Einfügen von Buttons und Eventhandling

Variante 1 (cl_gui_docking_container)

CLASS lcl_event DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING e_object
                sender.
    CLASS-METHODS:
      handle_user_command FOR EVENT user_command OF cl_gui_alv_grid
        IMPORTING e_ucomm  " Benutzerkommando
                  sender.  " Sender
ENDCLASS.

CLASS lcl_event IMPLEMENTATION.
  METHOD handle_toolbar.
* Separator hinzufügen
    APPEND VALUE #( butn_type = 3 ) TO e_object->mt_toolbar.
* Print-Button hinzufügen
    APPEND VALUE #( butn_type = 5 text = 'Klick!' icon = icon_change_text function = 'PRINT_DATA' quickinfo = 'Etwas ausgeben' disabled = ' ' ) TO e_object->mt_toolbar.
  ENDMETHOD.

  METHOD handle_user_command.
* TypeCast auf Sender
    DATA: o_grid TYPE REF TO cl_gui_alv_grid.
    o_grid ?= sender.

    CASE e_ucomm.
* Daten speichern
      WHEN 'PRINT_DATA'.
        WRITE: / 'Klick: ', o_grid->m_guid.
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  DATA: it_data TYPE STANDARD TABLE OF t000.
  DATA: o_salv TYPE REF TO cl_salv_table.

* Daten holen
  SELECT *
    INTO TABLE it_data
    FROM t000.

  DATA(o_dock) = NEW cl_gui_docking_container( no_autodef_progid_dynnr = abap_true
                                               side = cl_gui_docking_container=>dock_at_top
*                                               style = cl_gui_container=>ws_visible + cl_gui_container=>ws_thickframe + cl_gui_container=>ws_child
                                               ratio = 90
                                               caption = 'Datenausgabe'
                                               name = 'CNT1' ).

* Datenanzeige
  TRY.
* Bei Angabe des Containers o_dock bleibt die Abarbeitung nach o_salv->display( ) nicht
* stehen, sondern läuft weiter und die Referenz auf das ALV-Grid kann geholt werden.
* Eine Anzeige des SALV-Grids erfolgt so aber nur, wenn eine Listenausgabe erfolgt, daher das WRITE space.
      cl_salv_table=>factory( EXPORTING
                                r_container    = o_dock
                              IMPORTING
                                r_salv_table   = o_salv
                              CHANGING
                                t_table        = it_data ).

      o_salv->get_functions( )->set_all( ).
      o_salv->display( ).

* Trick: Aus dem Container das Grid-Objekt holen und nach cl_gui_alv_grid casten
      READ TABLE o_dock->children INDEX 1 ASSIGNING FIELD-SYMBOL(<child>).
      DATA(o_alv_grid) = CAST cl_gui_alv_grid( <child> ).

* Eventhandler registrieren
      SET HANDLER lcl_event=>handle_toolbar FOR o_alv_grid.
      SET HANDLER lcl_event=>handle_user_command FOR o_alv_grid.

* Anzeige neu aufbauen
      o_alv_grid->refresh_table_display( ).

    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

* leere Toolbar ausblenden
  cl_abap_list_layout=>suppress_toolbar( ).

  WRITE space. " wichtig für Erzwingung der Listenausgabe

Variante 2 (cl_gui_splitter_container)

CLASS lcl_event DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
        IMPORTING e_object
                    sender.
    CLASS-METHODS:
      handle_user_command FOR EVENT user_command OF cl_gui_alv_grid
        IMPORTING e_ucomm  " Benutzerkommando
                    sender.  " Sender
ENDCLASS.

CLASS lcl_event IMPLEMENTATION.
  METHOD handle_toolbar.
* Separator hinzufügen
    APPEND VALUE #( butn_type = 3 ) TO e_object->mt_toolbar.
* Edit-Button hinzufügen
    APPEND VALUE #( butn_type = 5 text = 'Klick!' icon = icon_change_text function = 'PRINT_DATA' quickinfo = 'Etwas ausgeben' disabled = ' ' ) TO e_object->mt_toolbar.
  ENDMETHOD.

  METHOD handle_user_command.
* TypeCast auf Sender
    DATA: o_grid TYPE REF TO cl_gui_alv_grid.
    o_grid ?= sender.

    CASE e_ucomm.
* Daten speichern
      WHEN 'PRINT_DATA'.
        WRITE: / 'Klick: ', o_grid->m_guid.
    ENDCASE.
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

  DATA: it_data TYPE STANDARD TABLE OF t000.
  DATA: o_salv TYPE REF TO cl_salv_table.

* Daten holen
  SELECT *
    INTO TABLE it_data
    FROM t000.

  DATA(o_split) = NEW cl_gui_splitter_container( parent = cl_gui_container=>default_screen
                                                 no_autodef_progid_dynnr = abap_true
                                                 rows = 1
                                                 columns = 2 ). " wenn columns = 1, dann FullScreen

* Referenz auf linken Container holen
  DATA(o_spl_left) = o_split->get_container( row = 1 column = 1 ).

* Datenanzeige
  TRY.
* Bei Angabe des Containers o_spl_left bleibt die Abarbeitung nach o_salv->display( ) nicht
* stehen, sondern läuft weiter und die Referenz auf das ALV-Grid kann geholt werden.
* Eine Anzeige des SALV-Grids erfolgt so aber nur, wenn eine Listenausgabe erfolgt, daher das WRITE space.
      cl_salv_table=>factory( EXPORTING
                                r_container    = o_spl_left
                              IMPORTING
                                r_salv_table   = o_salv
                              CHANGING
                                t_table        = it_data ).

      o_salv->get_functions( )->set_all( ).
      o_salv->display( ).

* Trick: Aus dem Container das Grid-Objekt holen und nach cl_gui_alv_grid casten
      READ TABLE o_spl_left->children INDEX 1 ASSIGNING FIELD-SYMBOL(<child>).
      IF <child> IS ASSIGNED.
        DATA(o_alv_grid) = CAST cl_gui_alv_grid( <child> ).

* Eventhandler registrieren
        SET HANDLER lcl_event=>handle_toolbar FOR o_alv_grid.
        SET HANDLER lcl_event=>handle_user_command FOR o_alv_grid.

* Anzeige neu aufbauen
        o_alv_grid->refresh_table_display( ).
      ENDIF.
    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

* leere Toolbar ausblenden
  cl_abap_list_layout=>suppress_toolbar( ).

  WRITE space. " wichtig für Erzwingung der Listenausgabe 

Variante 3 (cl_gui_container=>screen0)

CLASS lcl_event DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: handle_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING e_object
                sender.
    CLASS-METHODS:
      handle_user_command FOR EVENT user_command OF cl_gui_alv_grid
        IMPORTING e_ucomm  " Benutzerkommando
                  sender.  " Sender
ENDCLASS.

CLASS lcl_event IMPLEMENTATION.
  METHOD handle_toolbar.
* Separator hinzufügen
    APPEND VALUE #( butn_type = 3 ) TO e_object->mt_toolbar.
* Print-Button hinzufügen
    APPEND VALUE #( butn_type = 5 text = 'Klick!' icon = icon_change_text function = 'PRINT_DATA' quickinfo = 'Etwas ausgeben' disabled = ' ' ) TO e_object->mt_toolbar.
  ENDMETHOD.

  METHOD handle_user_command.
* TypeCast auf Sender
    DATA: o_grid TYPE REF TO cl_gui_alv_grid.
    o_grid ?= sender.

    CASE e_ucomm.
* Daten speichern
      WHEN 'PRINT_DATA'.
        WRITE: / 'Klick: ', o_grid->m_guid.
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  DATA: it_data TYPE STANDARD TABLE OF t000.
  DATA: o_salv TYPE REF TO cl_salv_table.

* Daten holen
  SELECT *
    INTO TABLE it_data
    FROM t000.

* Datenanzeige
  TRY.
* Bei Angabe des Containers cl_gui_container=>screen0 bleibt die Abarbeitung nach o_salv->display( ) nicht
* stehen, sondern läuft weiter und die Referenz auf das ALV-Grid kann geholt werden.
* Eine Anzeige des SALV-Grids erfolgt so aber nur, wenn eine Listenausgabe erfolgt, daher das WRITE space.
      cl_salv_table=>factory( EXPORTING
                                r_container    = cl_gui_container=>screen0
                              IMPORTING
                                r_salv_table   = o_salv
                              CHANGING
                                t_table        = it_data ).

      o_salv->get_functions( )->set_all( ).
      o_salv->display( ).

* Trick: Aus dem Container das Grid-Objekt holen und nach cl_gui_alv_grid casten
      READ TABLE cl_gui_container=>screen0->children INDEX 1 ASSIGNING FIELD-SYMBOL(<child>).
      DATA(o_alv_grid) = CAST cl_gui_alv_grid( <child> ).

* Eventhandler registrieren
      SET HANDLER lcl_event=>handle_toolbar FOR o_alv_grid.
      SET HANDLER lcl_event=>handle_user_command FOR o_alv_grid.

* Anzeige neu aufbauen
      o_alv_grid->refresh_table_display( ).

    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

* leere Toolbar ausblenden
  cl_abap_list_layout=>suppress_toolbar( ).

  WRITE space. " wichtig für Erzwingung der Listenausgabe

[ABAP] ALV-Grid auf dem Selektionsbildschirm anzeigen, Klick-Events abfangen, Selektions-Parameter setzen

DATA: o_dock TYPE REF TO cl_gui_docking_container.
DATA: o_alv TYPE REF TO cl_gui_alv_grid.
DATA: it_t001 TYPE STANDARD TABLE OF t001.
DATA: lv_temp TYPE string.

SELECTION-SCREEN BEGIN OF BLOCK var WITH FRAME TITLE title1.
PARAMETERS: p_param1 TYPE string.
SELECTION-SCREEN END OF BLOCK var.

CLASS lcl_events DEFINITION.
  PUBLIC SECTION.
    METHODS: on_single_click FOR EVENT hotspot_click OF cl_gui_alv_grid
      IMPORTING
        e_row_id  " obsolet, stattdessen es_row_no benutzen
        es_row_no
        e_column_id.
    METHODS: on_double_click FOR EVENT double_click OF cl_gui_alv_grid
      IMPORTING
        e_row e_column.
ENDCLASS.

CLASS lcl_events IMPLEMENTATION.
* Doppel-Klick für Hotspot-Felder
  METHOD on_double_click.
    IF e_row > 0.
      lv_temp = it_t001[ e_row ]-butxt.
    ENDIF.
  ENDMETHOD.

* Single-Klick für Hotspot-Felder
  METHOD on_single_click.
    IF es_row_no-row_id > 0.
      lv_temp = it_t001[ es_row_no-row_id ]-butxt.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

INITIALIZATION.

  title1 = 'Selektion'.

* Daten holen
  SELECT * FROM t001 INTO TABLE it_t001.

* Docking-Container erzeugen
  o_dock = NEW #( side = cl_gui_docking_container=>dock_at_left
                  ratio = 20 ).

* ALV-Grid erzeugen
  o_alv = NEW #( i_parent = o_dock
                 i_appl_events = abap_true ).

* Eventhandler setzen
  DATA(o_events) = NEW lcl_events( ).
  SET HANDLER o_events->on_double_click FOR o_alv.
  SET HANDLER o_events->on_single_click FOR o_alv.

* Layout anpassen
  DATA(lv_layout) = VALUE lvc_s_layo( grid_title = 'Auswahl mit Doppelklick:'
                                      no_toolbar = abap_false
                                      smalltitle = abap_true
                                      zebra      = abap_true ).

* ALV-Grid initialisieren
  o_alv->set_table_for_first_display( EXPORTING
                                        i_structure_name = 'T001'
                                        i_save           = space
                                        is_layout        = lv_layout
                                      CHANGING
                                        it_outtab        = it_t001 ).

* Feldkatalog holen
  DATA: it_fcat TYPE lvc_t_fcat.
    
  o_alv->get_frontend_fieldcatalog( IMPORTING
                                      et_fieldcatalog = it_fcat ).

* Hotspot für die Spalte 'BUTXT' aktivieren, damit Event handle_single_click abgefangen werden kann
  LOOP AT it_fcat ASSIGNING FIELD-SYMBOL(<fcat>).
    CASE <fcat>-fieldname.
      WHEN 'BUTXT'.
        <fcat>-hotspot = abap_true.
    ENDCASE.
  ENDLOOP.

* Feldkatalog speichern
  o_alv->set_frontend_fieldcatalog( it_fieldcatalog = it_fcat ).

* ALV-Grid anzeigen
  o_alv->refresh_table_display( ).

AT SELECTION-SCREEN OUTPUT.
* Selektion an Parameter geben
  p_param1 = lv_temp.

START-OF-SELECTION.
  WRITE: / 'Gewählter Parameter: ', p_param1.

[ABAP] Ein SALV-Table IDA und ein GUI-Picture in einem Dockingcontainer direkt auf dem Selektionsbildschirm anzeigen

DATA: o_cnt_bottom TYPE REF TO cl_gui_docking_container.
DATA: o_cnt_right TYPE REF TO cl_gui_docking_container.
DATA: o_alv_bottom TYPE REF TO if_salv_gui_table_ida.
DATA: o_pic TYPE REF TO cl_gui_picture.
DATA: o_collector_bottom TYPE REF TO cl_salv_range_tab_collector.
DATA: lv_mtart TYPE mara-mtart.

SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE title2.
SELECT-OPTIONS: s_mtart FOR lv_mtart.
SELECTION-SCREEN END OF BLOCK b1.

AT SELECTION-SCREEN OUTPUT.

* Verhindern, dass der Container mehrfach erzeugt wird, wenn der Focus aus
* best. Oberflächenelementen zurück kommt.

* Container unten erzeugen
  IF NOT o_cnt_bottom IS BOUND.
    o_cnt_bottom = NEW #( repid = sy-repid
                          dynnr = sy-dynnr
                          side  = cl_gui_docking_container=>dock_at_bottom " unterer Bildschirmrand
                          extension = 300 ).                               " 300 hoch, damit die Selektionskriterien nicht überdeckt werden
* Container rechts erzeugen

    o_cnt_right = NEW #( repid = sy-repid
                         dynnr = sy-dynnr
                         side  = cl_gui_docking_container=>dock_at_right  " rechter Bildschirmrand
                         extension = 800 ).                               " 800 breit, damit die Selektionskriterien nicht überdeckt werden

* IDA-Grid unten erzeugen
    o_alv_bottom = cl_salv_gui_table_ida=>create( iv_table_name    = 'MARA'
                                                  io_gui_container = o_cnt_bottom ).
    o_alv_bottom->display_options( )->set_title( 'MARA' ).

* Picture rechts erzeugen
    o_pic = NEW #( parent = o_cnt_right ).
    o_pic->set_display_mode( display_mode = cl_gui_picture=>display_mode_normal_center ).
    o_pic->load_picture_from_sap_icons( icon  = icon_delete ).

* Suchkriterien unten setzen
    o_collector_bottom = NEW #( ).
    o_collector_bottom->add_ranges_for_name( iv_name = 'MTART' it_ranges = s_mtart[] ).
    o_collector_bottom->get_collected_ranges( IMPORTING et_named_ranges = DATA(it_name_range_pairs_bottom) ).

    o_alv_bottom->set_select_options( it_ranges = it_name_range_pairs_bottom ).
  ENDIF.

[ABAP] Zwei SALV-Table IDA in einem Dockingcontainer direkt auf dem Selektionsbildschirm anzeigen

DATA: o_cnt_bottom TYPE REF TO cl_gui_docking_container.
DATA: o_cnt_right TYPE REF TO cl_gui_docking_container.
DATA: o_alv_bottom TYPE REF TO if_salv_gui_table_ida.
DATA: o_alv_right TYPE REF TO if_salv_gui_table_ida.
DATA: o_collector_bottom TYPE REF TO cl_salv_range_tab_collector.
DATA: o_collector_right TYPE REF TO cl_salv_range_tab_collector.

DATA: lv_arbgb TYPE t100-arbgb.
DATA: lv_msg TYPE t100-msgnr.
DATA: lv_text TYPE t100-text.
DATA: lv_mtart TYPE mara-mtart.

* Selektionskriterien für T100
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE title1.
SELECT-OPTIONS: s_langu FOR sy-langu.
SELECT-OPTIONS: s_arbgb FOR lv_arbgb.
SELECT-OPTIONS: s_msg FOR lv_msg.
SELECT-OPTIONS: s_text FOR lv_text.
SELECTION-SCREEN END OF BLOCK b1.

* Selektionskriterien für MARA
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE title2.
SELECT-OPTIONS: s_mtart FOR lv_mtart.
SELECTION-SCREEN END OF BLOCK b2.

AT SELECTION-SCREEN OUTPUT.

* Verhindern, dass der Container mehrfach erzeugt wird, wenn der Focus aus
* best. Oberflächenelementen zurück kommt.
  IF NOT o_cnt_bottom IS BOUND.
* Container unten erzeugen
    o_cnt_bottom = NEW #( repid = sy-repid
                          dynnr = sy-dynnr
                          side = cl_gui_docking_container=>dock_at_bottom  " unterer Bildschirmrand
                          extension = 300 ).                               " 300 hoch, damit die Selektionskriterien nicht überdeckt werden

* Container rechts erzeugen
    o_cnt_right = NEW #( repid = sy-repid
                         dynnr = sy-dynnr
                         side = cl_gui_docking_container=>dock_at_right  " rechter Bildschirmrand
                         extension = 800 ).                              " 800 breit, damit die Selektionskriterien nicht überdeckt werden


* IDA-Grid unten erzeugen
    o_alv_bottom = cl_salv_gui_table_ida=>create( iv_table_name    = 'MARA'
                                                  io_gui_container = o_cnt_bottom ).
    o_alv_bottom->display_options( )->set_title( 'MARA' ).

* IDA-Grid rechts erzeugen
    o_alv_right = cl_salv_gui_table_ida=>create( iv_table_name    = 'T100'
                                                 io_gui_container = o_cnt_right ).
    o_alv_right->display_options( )->set_title( 'T100' ).

* Suchkriterien unten setzen
    o_collector_bottom = NEW #( ).
    o_collector_bottom->add_ranges_for_name( iv_name = 'MTART' it_ranges = s_mtart[] ).
    o_collector_bottom->get_collected_ranges( IMPORTING et_named_ranges = DATA(it_name_range_pairs_bottom) ).

    o_alv_bottom->set_select_options( it_ranges = it_name_range_pairs_bottom ).

* Suchkriterien rechts setzen
    o_collector_right = NEW #( ).
    o_collector_right->add_ranges_for_name( iv_name = 'SPRSL' it_ranges = s_langu[] ).
    o_collector_right->add_ranges_for_name( iv_name = 'ARBGB' it_ranges = s_arbgb[] ).
    o_collector_right->add_ranges_for_name( iv_name = 'MSGNR' it_ranges = s_msg[] ).
    o_collector_right->add_ranges_for_name( iv_name = 'TEXT' it_ranges = s_text[] ).
    o_collector_right->get_collected_ranges( IMPORTING et_named_ranges = DATA(it_name_range_pairs_right) ).

    o_alv_right->set_select_options( it_ranges = it_name_range_pairs_right ).
  ENDIF.

[ABAP] SALV-Table IDA in einem Dockingcontainer direkt auf dem Selektionsbildschirm anzeigen

DATA: o_cnt TYPE REF TO cl_gui_docking_container.
DATA: o_alv TYPE REF TO if_salv_gui_table_ida.
DATA: o_collector TYPE REF TO cl_salv_range_tab_collector.
DATA: it_t100 TYPE t100.

SELECT-OPTIONS: s_langu FOR sy-langu.
SELECT-OPTIONS: s_arbgb FOR it_t100-arbgb.
SELECT-OPTIONS: s_msg FOR it_t100-msgnr.
SELECT-OPTIONS: s_text FOR it_t100-text.

AT SELECTION-SCREEN OUTPUT.

* Verhindern, dass der Container mehrfach erzeugt wird, wenn der Focus aus
* best. Oberflächenelementen zurück kommt.
  IF NOT o_cnt IS BOUND.
* Container erzeugen
    o_cnt = NEW #( repid = sy-repid
                   dynnr = sy-dynnr
                   side  = cl_gui_docking_container=>dock_at_bottom " unterer Bildschirmrand
                   extension = 400 ).                               " max. 400 hoch, damit die Selektionskriterien nicht überdeckt werden

* IDA-Grid erzeugen
    o_alv = cl_salv_gui_table_ida=>create( iv_table_name    = 'T100'
                                           io_gui_container = o_cnt ).

    o_collector = NEW #( ).

* Suchkriterien setzen
    o_collector->add_ranges_for_name( iv_name = 'SPRSL' it_ranges = s_langu[] ).
    o_collector->add_ranges_for_name( iv_name = 'ARBGB' it_ranges = s_arbgb[] ).
    o_collector->add_ranges_for_name( iv_name = 'MSGNR' it_ranges = s_msg[] ).
    o_collector->add_ranges_for_name( iv_name = 'TEXT' it_ranges = s_text[] ).
    o_collector->get_collected_ranges( IMPORTING et_named_ranges = DATA(it_name_range_pairs) ).

* IDA-Grid Optionen setzen
    o_alv->set_select_options( it_ranges = it_name_range_pairs ).
    o_alv->display_options( )->enable_alternating_row_pattern( ).
  ENDIF.