[ABAP] SALV: Eventhandler für Auswahl einer Zeile (Row) bzw. Spalte (Col)

* Eventhandler
CLASS lcl_events DEFINITION.
  PUBLIC SECTION.

* Platzhalter für Referenz auf SALV-Grid
    CLASS-DATA: o_salv TYPE REF TO cl_salv_table.
* Platzhalter für Referenz auf interne Tabelle
    CLASS-DATA: it_t024 TYPE STANDARD TABLE OF t024 WITH DEFAULT KEY.

* Eventhandler-Methode für Change-Select, Verzögerung ~1.5s
    CLASS-METHODS: on_row_select FOR EVENT delayed_changed_sel_callback OF cl_gui_alv_grid
      IMPORTING sender.
ENDCLASS.

CLASS lcl_events IMPLEMENTATION.
* Event behandelt die Auswahl Zeilen/Spalten im Gitter mit 1,5s Verzögerung
  METHOD on_row_select.
    TRY.
* referenz auf ALV-Grid holen
        DATA(o_alv) = CAST cl_gui_alv_grid( sender ).

* selektierte Zeilen, abh. vom if_salv_c_selection_mode
        o_alv->get_selected_rows( IMPORTING et_row_no     = DATA(it_sel_rows)
                                            et_index_rows = DATA(it_sel_rows_idx) ).

* selektierte Spalten, abh. vom if_salv_c_selection_mode
        o_alv->get_selected_columns( IMPORTING et_index_columns = DATA(it_sel_cols_idx) ).

        LOOP AT it_sel_cols_idx ASSIGNING FIELD-SYMBOL(<col>).
        ENDLOOP.

        LOOP AT it_sel_rows_idx ASSIGNING FIELD-SYMBOL(<row>).
        ENDLOOP.

      CATCH cx_root.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_salv_helper DEFINITION INHERITING FROM cl_salv_model_base FINAL.
  PUBLIC SECTION.

    CLASS-METHODS:
      get_alv_from_salv
        IMPORTING
          io_salv_grid   TYPE REF TO cl_salv_table
        RETURNING
          VALUE(ro_grid) TYPE REF TO cl_gui_alv_grid.
ENDCLASS.

CLASS lcl_salv_helper IMPLEMENTATION.
*---------------------------------------------------------------------*
* Wandelt eine Referenz auf cl_salv_table in ein cl_gui_alv_grid um.
*---------------------------------------------------------------------*
* -> io_model - Referenz auf cl_salv_table
* <- ro_grid  - Referenz auf cl_gui_alv_grid, bei Fehler INITIAL
*---------------------------------------------------------------------*
  METHOD get_alv_from_salv.

    IF io_salv_grid IS BOUND.
      TRY.
          DATA(o_model) = CAST cl_salv_model_base( io_salv_grid->extended_grid_api( ) ).

* Funktioniert nur, wenn SALV-Table schon mit display( ) angezeigt und
* somit schon ein Container dafür erzeugt wurde. Andernfalls ist r_adapter INITIAL.
          IF o_model->r_controller IS BOUND AND o_model->r_controller->r_adapter IS BOUND.

            IF o_model->r_controller->r_adapter IS INSTANCE OF if_salv_table_display_adapter.
              ro_grid = CAST if_salv_table_display_adapter( o_model->r_controller->r_adapter )->get_grid( ).
            ENDIF.

          ENDIF.
        CATCH cx_root.
      ENDTRY.
    ENDIF.

  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

  TRY.
* Beispieldaten (Einkäufergruppen) holen
      SELECT FROM t024
        FIELDS *
        INTO TABLE @lcl_events=>it_t024
        UP TO 10 ROWS.

      IF sy-subrc = 0.
        cl_salv_table=>factory( EXPORTING r_container  = cl_gui_container=>default_screen
                                IMPORTING r_salv_table = lcl_events=>o_salv
                                CHANGING  t_table      = lcl_events=>it_t024 ).

* Standardbuttons der SALV-Table
        lcl_events=>o_salv->get_functions( )->set_all( abap_true ).

* if_salv_c_selection_mode=>single    : es kann eine Zeile im SALV/ALV selektiert werden
* if_salv_c_selection_mode=>row_column: es können mehrere Zeile und Spalten im SALV/ALV selektiert werden
* nach 1,5s wird dann der Event on_delayed_change_select ausgelöst
        lcl_events=>o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>single ).

* SALV anzeigen
        lcl_events=>o_salv->display( ).

* ALV-Objektreferenz aus dem SALV-Grid holen, funktioniert erst nach o_salv->display( )
        DATA(o_alv) = lcl_salv_helper=>get_alv_from_salv( lcl_events=>o_salv ).
        IF o_alv IS BOUND.
* Event-Handler des ALV
          SET HANDLER lcl_events=>on_row_select FOR o_alv.
* Event registrieren
          o_alv->register_delayed_event( i_event_id = cl_gui_alv_grid=>mc_evt_delayed_change_select ).
        ENDIF.

* Toolbar der Listausgabe unterdrücken
        cl_abap_list_layout=>suppress_toolbar( ).

* Listausgabe erzwingen für Erzeugung von cl_gui_container=>default_screen
        WRITE: space.

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

[ABAP] SALV-Table: Hilfsklasse zur Ermittlung der Referenz auf ALV-Table (cl_gui_alv_grid) einer SALV-Table (cl_salv_table)

bis SAP-Realease 754: Hilfsklasse lcl_salv_helper abgeleitet von cl_salv_model_base

* bis SAP-Realease 754
* https://zevolving.com/2015/06/salv-table-20-editable-yes-as-per-this-standard-sap-application/

CLASS lcl_salv_helper DEFINITION INHERITING FROM cl_salv_model_base.
  PUBLIC SECTION.

    CLASS-METHODS:
      get_alv_from_salv
        IMPORTING
          io_model       TYPE REF TO cl_salv_model
        RETURNING
          VALUE(ro_grid) TYPE REF TO cl_gui_alv_grid.
ENDCLASS.

CLASS lcl_salv_helper IMPLEMENTATION.
*---------------------------------------------------------------------*
* Wandelt eine Referenz auf cl_salv_table in ein cl_gui_alv_grid um.
* Funktioniert nur, wenn SALV-Table schon mit display( ) angezeigt
* wurde, d.h. schon ein Container dafür erzeugt wurde. Andernfalls ist
* r_adapter INITIAL.
*---------------------------------------------------------------------*
* -> io_model - Referenz auf cl_salv_table (cl_salv_model)
* <- ro_grid  - Referenz auf cl_gui_alv_grid, bei Fehler INITIAL
*---------------------------------------------------------------------*
  METHOD get_alv_from_salv.
  
* wenn Typ 'Table'
    IF io_model->model = if_salv_c_model=>table.
      TRY.
          IF abap_true = cl_wdy_wb_reflection_helper=>is_instance_of( object = io_model->r_controller->r_adapter
                                                                      type_name = 'CL_SALV_GRID_ADAPTER' ).
                                                                      
            DATA(o_grid_adap) = CAST cl_salv_grid_adapter( io_model->r_controller->r_adapter ).

            IF o_grid_adap IS BOUND.
              ro_grid = o_grid_adap->get_grid( ).
            ENDIF.
          ELSEIF abap_true = cl_wdy_wb_reflection_helper=>is_instance_of( object = io_model->r_controller->r_adapter
                                                                          type_name = 'CL_SALV_FULLSCREEN_ADAPTER' ).

            DATA(o_fs_adap) = CAST cl_salv_fullscreen_adapter( io_model->r_controller->r_adapter ).

            IF o_fs_adap IS BOUND.
              ro_grid = o_fs_adap->get_grid( ).
            ENDIF.
          ENDIF.
        CATCH cx_root.
      ENDTRY.
    ENDIF.
  ENDMETHOD.

ENDCLASS.

ab SAP-Release 755: Hilfsklasse lcl_salv_helper mit Nutzung des Interfaces if_salv_table_display_adapter

* ab SAP-Release 755
* SALV-Table: Hilfsklasse zur Ermittlung der Referenz auf ALV-Table (cl_gui_alv_grid) einer SALV-Table (cl_salv_table)
* ab SAP-Release 755 hat die Klasse CL_SALV_FULLSCREEN_ADAPTER keine Funktion get_grid( ) mehr
* somit muss das Coding ab SAP-Release 755 geändert werden
* Quellen:
* https://blogs.sap.com/2022/08/01/editable-cl_salv_table-after-release-756/
* https://tricktresor.de/blog/alv-grid-aus-salv-ermitteln-ab-release-7-55/

CLASS lcl_salv_helper DEFINITION INHERITING FROM cl_salv_model_base FINAL.
  PUBLIC SECTION.

    CLASS-METHODS:
      get_alv_from_salv
        IMPORTING
          io_salv_grid   TYPE REF TO cl_salv_table
        RETURNING
          VALUE(ro_grid) TYPE REF TO cl_gui_alv_grid.
ENDCLASS.

CLASS lcl_salv_helper IMPLEMENTATION.
*---------------------------------------------------------------------*
* Wandelt eine Referenz auf cl_salv_table in ein cl_gui_alv_grid um.
*---------------------------------------------------------------------*
* -> io_model - Referenz auf cl_salv_table (cl_salv_table)
* <- ro_grid  - Referenz auf cl_gui_alv_grid, bei Fehler INITIAL
*---------------------------------------------------------------------*
  METHOD get_alv_from_salv.

    IF io_salv_grid IS BOUND.

      TRY.
          DATA(o_model) = CAST cl_salv_model_base( io_salv_grid->extended_grid_api( ) ).

* Funktioniert nur, wenn SALV-Table schon mit display( ) angezeigt und
* somit schon ein Container dafür erzeugt wurde. Andernfalls ist r_adapter INITIAL.
          IF o_model->r_controller IS BOUND AND o_model->r_controller->r_adapter IS BOUND.

            IF o_model->r_controller->r_adapter IS INSTANCE OF if_salv_table_display_adapter.
              ro_grid = CAST if_salv_table_display_adapter( o_model->r_controller->r_adapter )->get_grid( ).
            ENDIF.

          ENDIF.

        CATCH cx_root.
      ENDTRY.

    ENDIF.

  ENDMETHOD.

ENDCLASS.

Anwendungsbeispiel

* Anwendungs-Beispiel
CLASS lcl_event DEFINITION.
  PUBLIC SECTION.
    CONSTANTS: co_btn_click TYPE string VALUE 'BTN_KLICK'.

    CLASS-METHODS: on_toolbar FOR EVENT toolbar OF cl_gui_alv_grid
      IMPORTING
        e_object
        sender.
    CLASS-METHODS: on_user_command FOR EVENT user_command OF cl_gui_alv_grid
      IMPORTING
        e_ucomm
        sender.
ENDCLASS.

CLASS lcl_event IMPLEMENTATION.
* Toolbar-Buttons hinzufügen
  METHOD on_toolbar.
* Separator hinzufügen
    APPEND VALUE #( butn_type = cntb_btype_sep ) TO e_object->mt_toolbar.
* Edit-Button hinzufügen
    APPEND VALUE #( butn_type = cntb_btype_button
                    text = 'Klick!'
                    icon = icon_change_text
                    function = co_btn_click
                    quickinfo = 'Etwas ausgeben'
                    disabled = abap_false ) TO e_object->mt_toolbar.
  ENDMETHOD.

* User-Command
  METHOD on_user_command.
    CASE e_ucomm.
      WHEN co_btn_click.
        MESSAGE |Klick: { sender->m_guid }| TYPE 'I'.
    ENDCASE.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  TRY.
      DATA: o_salv TYPE REF TO cl_salv_table.

* Daten holen
      SELECT FROM t000
        FIELDS *
        INTO TABLE @DATA(it_t000).

      cl_salv_table=>factory( EXPORTING r_container  = cl_gui_container=>default_screen
                              IMPORTING r_salv_table = o_salv
                              CHANGING  t_table      = it_t000 ).

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

      o_salv->display( ).

* Referenz auf ALV-Grid holen
      DATA(o_alv_grid) = lcl_salv_helper=>get_alv_from_salv( o_salv ).

      IF o_alv_grid IS BOUND.
* Eventhandler des ALV-Grids registrieren
        SET HANDLER lcl_event=>on_toolbar FOR o_alv_grid.
        SET HANDLER lcl_event=>on_user_command FOR o_alv_grid.

* Toolbar-Buttons refreshen
        o_alv_grid->refresh_table_display( ).
      ENDIF.
    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

* leere Standard-Toolbar ausblenden
  cl_abap_list_layout=>suppress_toolbar( ).

* Ausgabe von cl_gui_container=>default_screen erzwingen
  WRITE space.

Links