[ABAP] ALV-Grid als Property-Grid (Parametertabelle) mit Edit-Feldern und Typprüfung

Quelle / Inspiration gefunden auf: www.tricktresor.de

* ALV-Konstanten
INCLUDE <cl_alv_control>.

CLASS lcl_main DEFINITION.
  PUBLIC SECTION.

    TYPES: ty_enum TYPE i.

    TYPES: BEGIN OF ty_param,
             name  TYPE string,
             type  TYPE ty_enum,
             text  TYPE string,
             value TYPE string,
           END OF ty_param.

    TYPES: ty_it_params TYPE STANDARD TABLE OF ty_param WITH NON-UNIQUE DEFAULT KEY.

* Enum
    CLASS-DATA: string TYPE ty_enum VALUE 1 READ-ONLY.
    CLASS-DATA: int TYPE ty_enum VALUE 2 READ-ONLY.
    CLASS-DATA: float TYPE ty_enum VALUE 3 READ-ONLY.
    CLASS-DATA: date TYPE ty_enum VALUE 4 READ-ONLY.

* Bezeichner
    CONSTANTS: co_name TYPE string VALUE 'NAME'.
    CONSTANTS: co_type TYPE string VALUE 'TYPE'.
    CONSTANTS: co_text TYPE string VALUE 'TEXT'.
    CONSTANTS: co_value TYPE string VALUE 'VALUE'.

    METHODS: constructor
      IMPORTING
        o_parent TYPE REF TO cl_gui_container.

    METHODS: init_grid.

    METHODS: add_parameter
      IMPORTING
        parameter TYPE ty_param.

    METHODS: get_params
      RETURNING VALUE(rv_it_parameters) TYPE ty_it_params.

  PROTECTED SECTION.

    DATA: o_grid TYPE REF TO cl_gui_alv_grid.
    DATA: it_params TYPE ty_it_params.

    METHODS: on_data_changed FOR EVENT data_changed OF cl_gui_alv_grid
      IMPORTING
          er_data_changed
          sender.

ENDCLASS.

CLASS lcl_main IMPLEMENTATION.

  METHOD constructor.
    o_grid = NEW #( i_parent = o_parent ).
  ENDMETHOD.

* ALV-Gitter initialisieren
  METHOD init_grid.

    DATA(it_fieldcat) = VALUE lvc_t_fcat( ( fieldname  = co_name
                                            outputlen  = 15
                                            coltext    = 'Parameter'
                                            style      = alv_style_font_bold + alv_style_color_int_group )
                                          ( fieldname  = co_type
                                            outputlen  = 5
                                            coltext    = 'Type'
                                            no_out     = abap_true )
                                          ( fieldname  = co_text
                                            outputlen  = 15
                                            coltext    = 'Text' )
                                          ( fieldname  = co_value
                                            outputlen  = 20
                                            coltext    = 'Value'
                                            edit       = abap_true
                                            fix_column = abap_true ) ).

    DATA(s_layout) = VALUE lvc_s_layo( no_toolbar = abap_true
                                       no_headers = abap_false ).

    SET HANDLER on_data_changed FOR o_grid.

* Tastenevents registrieren
    o_grid->register_edit_event( i_event_id = cl_gui_alv_grid=>mc_evt_enter ).    " Enter
    o_grid->register_edit_event( i_event_id = cl_gui_alv_grid=>mc_evt_modified ). " Eingabe, Cursortasten

* ALV-Grid selektionsbereit setzen
    o_grid->set_ready_for_input( i_ready_for_input = 1 ).

    o_grid->set_table_for_first_display( EXPORTING
                                           is_layout       = s_layout
                                         CHANGING
                                           it_outtab       = it_params
                                           it_fieldcatalog = it_fieldcat ).

  ENDMETHOD.

* Parameterliste zurückholen
  METHOD get_params.
    rv_it_parameters = it_params.
  ENDMETHOD.

* Parameter hinzufügen
  METHOD add_parameter.
    APPEND VALUE #( name  = parameter-name
                    type  = parameter-type
                    text  = parameter-text
                    value = parameter-value ) TO it_params.
  ENDMETHOD.

  METHOD on_data_changed.
* geänderte Zellen durchgehen
    LOOP AT er_data_changed->mt_good_cells ASSIGNING FIELD-SYMBOL(<fs_changed>).
      IF <fs_changed> IS ASSIGNED.
* Zeile x aus der iTab it_params rausholen und daraus die Zelle anhand des Spaltennamens (Feldnamens) holen
        TRY.
            ASSIGN COMPONENT <fs_changed>-fieldname OF STRUCTURE it_params[ <fs_changed>-row_id ] TO FIELD-SYMBOL(<fs_param>).

            IF <fs_param> IS ASSIGNED.
* Änderungswert in die Zelle der iTab (it_params) rückschreiben
              CASE it_params[ <fs_changed>-row_id ]-type.
                WHEN lcl_main=>string.
                  <fs_param> = <fs_changed>-value.
                WHEN lcl_main=>int.
* Typprüfung für Int
                  IF cl_abap_matcher=>create( pattern = '^[-+]?[0-9]*$'
                                              text = <fs_changed>-value
                                              ignore_case = abap_true )->match( ) = abap_true.

                    <fs_param> = <fs_changed>-value.
                  ELSE.
* Eingabefehler im Protokoll anzeigen
                    er_data_changed->add_protocol_entry( i_msgid     = '0K'
                                                         i_msgno     = '000'
                                                         i_msgty     = 'E'
                                                         i_msgv1     = 'Ungültiger Wert:'
                                                         i_msgv2     = <fs_changed>-value
                                                         i_msgv3     = 'Bitte einen Wert vom Typ int eingeben!'
                                                         i_msgv4     = ''
                                                         i_fieldname = <fs_changed>-fieldname
                                                         i_row_id    = <fs_changed>-row_id ).
                  ENDIF.
                WHEN lcl_main=>float.
* Typprüfung für Float
                  IF cl_abap_matcher=>create( pattern = '^[-+]?[0-9]*[,]?[0-9]+([eE][-+]?[0-9]+)?$'
                                              text = <fs_changed>-value
                                              ignore_case = abap_true )->match( ) = abap_true.

                    <fs_param> = <fs_changed>-value.
                  ELSE.
* Eingabefehler im Protokoll anzeigen
                    er_data_changed->add_protocol_entry( i_msgid     = '0K'
                                                         i_msgno     = '000'
                                                         i_msgty     = 'E'
                                                         i_msgv1     = 'Ungültiger Wert:'
                                                         i_msgv2     = <fs_changed>-value
                                                         i_msgv3     = 'Bitte einen Wert vom Typ float eingeben!'
                                                         i_msgv4     = ''
                                                         i_fieldname = <fs_changed>-fieldname
                                                         i_row_id    = <fs_changed>-row_id ).
                  ENDIF.
                WHEN lcl_main=>date.
* Typprüfung für Date
                  IF cl_abap_matcher=>create( pattern = '^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$'
                                              text = <fs_changed>-value
                                              ignore_case = abap_true )->match( ) = abap_true.

                    <fs_param> = <fs_changed>-value.
                  ELSE.
* Eingabefehler im Protokoll anzeigen
                    er_data_changed->add_protocol_entry( i_msgid     = '0K'
                                                         i_msgno     = '000'
                                                         i_msgty     = 'E'
                                                         i_msgv1     = 'Ungültiger Wert:'
                                                         i_msgv2     = <fs_changed>-value
                                                         i_msgv3     = 'Bitte einen Datumswert im Format dd.mm.yyyy eingeben!'
                                                         i_msgv4     = ''
                                                         i_fieldname = <fs_changed>-fieldname
                                                         i_row_id    = <fs_changed>-row_id ).
                  ENDIF.
              ENDCASE.
            ENDIF.
          CATCH cx_root.
        ENDTRY.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

ENDCLASS.

**********************************************************************
*
* Datentypen, Variablen, Konstanten
*
**********************************************************************
DATA: o_main TYPE REF TO lcl_main.

**********************************************************************
*
* SELECTION-SCREEN
*
**********************************************************************
SELECTION-SCREEN BEGIN OF SCREEN 2000.
SELECTION-SCREEN END OF SCREEN 2000.

**********************************************************************
*
* INITIALIZATION
*
**********************************************************************
INITIALIZATION.

  o_main = NEW #( o_parent = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_left
                                                           extension = 500
                                                           no_autodef_progid_dynnr = abap_true ) ).

* Beispiel-Parameter einfügen
* String-Parameter
  o_main->add_parameter( VALUE #( name = 'PERSON_VOR'
                                  type = lcl_main=>string
                                  text = 'Vorname'
                                  value = 'Udo' ) ).
* String-Parameter
  o_main->add_parameter( VALUE #( name = 'PERSON_NACH'
                                  type = lcl_main=>string
                                  text = 'Nachname'
                                  value = 'Lehmann' ) ).
* Int-Parameter
  o_main->add_parameter( VALUE #( name = 'PERSON_ALTER'
                                  type = lcl_main=>int
                                  text = 'Alter'
                                  value = '34' ) ).
* Float-Parameter
  o_main->add_parameter( VALUE #( name = 'PERSON_GROESSE'
                                  type = lcl_main=>float
                                  text = 'Größe'
                                  value = '1,80' ) ).
* Date-Parameter
  o_main->add_parameter( VALUE #( name = 'PERSON_DATE'
                                  type = lcl_main=>date
                                  text = 'Geburtsdatum'
                                  value = '01.01.1980' ) ).

**********************************************************************
*
* AT SELECTION-SCREEN OUTPUT
*
**********************************************************************
AT SELECTION-SCREEN OUTPUT.

  IF o_main IS BOUND.
    o_main->init_grid( ).
  ENDIF.

**********************************************************************
*
* AT SELECTION-SCREEN
*
**********************************************************************
AT SELECTION-SCREEN.
* wenn "Ausführen" (F8) geklickt wurde
  IF sy-ucomm = 'CRET'.
    cl_demo_output=>display_data( o_main->get_params( ) ).
  ENDIF.

**********************************************************************
*
* START-OF-SELECTION
*
**********************************************************************
START-OF-SELECTION.
* leeres Selektionbild 2000 anzeigen
  CALL SELECTION-SCREEN 2000.

[ABAP] ALV-Grid als Property-Grid mit Tri-State Klickfeldern/Buttons (ON / OFF / UNDEF)

Quelle / Inspiration gefunden auf: www.tricktresor.de

Die Codeteile mit UNDEF / abap_undefined können auch auskommentiert werden, so dass sich eine Möglichkeit der Dual-State Umschaltung (ON / OFF) per Mausklick ergibt.

* ALV-Konstanten
INCLUDE <cl_alv_control>.

CLASS lcl_main DEFINITION.
  PUBLIC SECTION.

    TYPES: BEGIN OF ty_param,
             name   TYPE string,
             text   TYPE string,
             status TYPE boolean,
           END OF ty_param.

    TYPES: ty_it_params TYPE STANDARD TABLE OF ty_param WITH NON-UNIQUE DEFAULT KEY.

    TYPES: BEGIN OF ty_ui_param,
             name    TYPE string,
             text    TYPE string,
             status  TYPE icon_text,
             t_color TYPE lvc_t_scol,
             t_style TYPE lvc_t_styl,
           END OF ty_ui_param.

    TYPES: ty_it_ui_params TYPE STANDARD TABLE OF ty_ui_param.

    TYPES: ty_cell_type TYPE i.

    CONSTANTS: co_celltype_hotspot TYPE ty_cell_type VALUE 1.
    CONSTANTS: co_celltype_button TYPE ty_cell_type VALUE 2.

* Farben
    CONSTANTS: co_color_on TYPE i VALUE col_positive.
    CONSTANTS: co_color_off TYPE i VALUE col_negative.
    CONSTANTS: co_color_undef TYPE i VALUE col_total.

* Bezeichner
    CONSTANTS: co_status TYPE string VALUE 'STATUS'.
    CONSTANTS: co_on TYPE string VALUE 'ON'.
    CONSTANTS: co_off TYPE string VALUE 'OFF'.
    CONSTANTS: co_undef TYPE string VALUE 'N/A'.

* Icons
    CONSTANTS status_icon_on TYPE icon_text VALUE icon_oo_object.
    CONSTANTS status_icon_off TYPE icon_text VALUE icon_system_start_recording.
    CONSTANTS status_icon_undef TYPE icon_text VALUE icon_oo_class.
*    CONSTANTS status_icon_undef TYPE icon_text VALUE icon_led_yellow.

    METHODS: constructor
      IMPORTING
        o_parent TYPE REF TO cl_gui_container.

    METHODS: init_grid
      IMPORTING
        cell_type TYPE ty_cell_type.

    METHODS: add_parameter
      IMPORTING
        parameter TYPE ty_param.

    METHODS: get_params
      RETURNING VALUE(rv_it_parameters) TYPE ty_it_params.

  PROTECTED SECTION.

    DATA: o_grid TYPE REF TO cl_gui_alv_grid.
    DATA: it_params TYPE ty_it_params.
    DATA: it_ui_params TYPE ty_it_ui_params.

    METHODS: set_color
      IMPORTING
                status       TYPE boolean
      RETURNING VALUE(color) TYPE lvc_t_scol.

    METHODS: on_hotspot_click FOR EVENT hotspot_click OF cl_gui_alv_grid
      IMPORTING
          e_row_id.

    METHODS: on_button_click FOR EVENT button_click OF cl_gui_alv_grid
      IMPORTING
          es_col_id
          es_row_no.

ENDCLASS.

CLASS lcl_main IMPLEMENTATION.

  METHOD constructor.
    o_grid = NEW #( i_parent = o_parent ).
  ENDMETHOD.

  METHOD init_grid.

    CLEAR: it_ui_params.

* Parameter in ALV-Zeilen umwandeln
    LOOP AT it_params ASSIGNING FIELD-SYMBOL(<fs_param>).

      CASE <fs_param>-status.
        WHEN abap_true.
* ON
          APPEND VALUE #( name = <fs_param>-name
                          text = <fs_param>-text
                          status = |{ status_icon_on } { co_on }|
                          t_color = me->set_color( abap_true ) ) TO it_ui_params.
        WHEN abap_false.
* OFF
          APPEND VALUE #( name = <fs_param>-name
                          text = <fs_param>-text
                          status = |{ status_icon_off } { co_off }|
                          t_color = me->set_color( abap_false ) ) TO it_ui_params.
        WHEN abap_undefined.
* UNDEF
          APPEND VALUE #( name = <fs_param>-name
                          text = <fs_param>-text
                          status = |{ status_icon_undef } { co_undef }|
                          t_color = me->set_color( abap_undefined ) ) TO it_ui_params.

      ENDCASE.

    ENDLOOP.

    DATA: it_fieldcat TYPE lvc_t_fcat.

    IF cell_type = co_celltype_button.
      it_fieldcat = VALUE lvc_t_fcat( ( fieldname = 'NAME'
                                        outputlen = 15
                                        coltext = 'Parameter'
                                        style = alv_style_font_bold + alv_style_color_int_group )
                                      ( fieldname = 'TEXT'
                                        outputlen = 20
                                        coltext = 'Description' )
                                      ( fieldname = co_status
                                        outputlen = 10
                                        coltext = 'Switch'
                                        style = alv_style_button
                                        icon = abap_true
                                        fix_column = abap_true ) ).
    ELSE.
      it_fieldcat = VALUE lvc_t_fcat( ( fieldname = 'NAME'
                                        outputlen = 15
                                        coltext = 'Parameter'
                                        style = alv_style_font_bold + alv_style_color_int_group )
                                      ( fieldname = 'TEXT'
                                        outputlen = 20
                                        coltext = 'Description' )
                                      ( fieldname = co_status
                                        outputlen = 10
                                        coltext = 'Switch'
                                        hotspot = abap_true
                                        icon = abap_true
                                        fix_column = abap_true ) ).
    ENDIF.

    DATA(s_layout) = VALUE lvc_s_layo( stylefname = 'T_STYLE'
                                       ctab_fname = 'T_COLOR'
                                       no_toolbar = abap_true
                                       no_headers = abap_false ).

    SET HANDLER on_hotspot_click FOR o_grid.
    SET HANDLER on_button_click FOR o_grid.

    o_grid->set_table_for_first_display( EXPORTING
                                           is_layout = s_layout
                                         CHANGING
                                           it_outtab = it_ui_params
                                           it_fieldcatalog = it_fieldcat ).

  ENDMETHOD.

* Parameterliste zurückholen
  METHOD get_params.
    rv_it_parameters = it_params.
  ENDMETHOD.

* Parameter hinzufügen
  METHOD add_parameter.
    APPEND VALUE #( name   = parameter-name
                    text   = parameter-text
                    status = parameter-status ) TO it_params.
  ENDMETHOD.

* Hintergrundfarben setzen
  METHOD set_color.

    CASE status.
      WHEN abap_true.
* Grün / ON
        color = VALUE #( ( fname = co_status color-col = co_color_on ) ).
      WHEN abap_false.
* Rot / OFF
        color = VALUE #( ( fname = co_status color-col = co_color_off ) ).
      WHEN abap_undefined.
* Gelb / UNDEF
        color = VALUE #( ( fname = co_status color-col = co_color_undef ) ).
    ENDCASE.

  ENDMETHOD.

  METHOD on_hotspot_click.

* geklickte ALV-Zeile holen
    READ TABLE it_ui_params ASSIGNING FIELD-SYMBOL(<ui_param>) INDEX e_row_id-index.
* korrespondierenden Parameter ermitteln
    READ TABLE it_params ASSIGNING FIELD-SYMBOL(<param>) WITH KEY name = <ui_param>-name.

    CASE <param>-status.
      WHEN abap_true.
* ON->OFF
        <ui_param>-status = |{ status_icon_off } { co_off }|.
        <ui_param>-t_color = me->set_color( abap_false ).
        <param->-status = abap_false.
      WHEN abap_false.
* OFF->UNDEF
        <ui_param>-status = |{ status_icon_undef } { co_undef }|.
        <ui_param>-t_color = me->set_color( abap_undefined ).
        <param>-status = abap_undefined.
      WHEN abap_undefined.
* UNDEF->ON
        <ui_param>-status = |{ status_icon_on } { co_on }|.
        <ui_param>-t_color = me->set_color( abap_true ).
        <param>-status = abap_true.
    ENDCASE.

    o_grid->refresh_table_display( is_stable = VALUE lvc_s_stbl( row = abap_true
                                                                 col = abap_true )
                                   i_soft_refresh = abap_false ).
  ENDMETHOD.

  METHOD on_button_click.
* geklickte ALV-Zeile holen
    READ TABLE it_ui_params ASSIGNING FIELD-SYMBOL(<ui_param>) INDEX es_row_no-row_id.
* korrespondierenden Parameter ermitteln
    READ TABLE it_params ASSIGNING FIELD-SYMBOL(<param>) WITH KEY name = <ui_param>-name.

    CASE <param>-status.
      WHEN abap_true.
* ON->OFF
        <ui_param>-status = status_icon_off.
        <ui_param>-t_color = me->set_color( abap_false ).
        <param>-status = abap_false.
      WHEN abap_false.
* OFF->UNDEF
        <ui_param>-status = status_icon_undef.
        <ui_param>-t_color = me->set_color( abap_undefined ).
        <param>-status = abap_undefined.
      WHEN abap_undefined.
* UNDEF->ON
        <ui_param>-status = status_icon_on.
        <ui_param>-t_color = me->set_color( abap_true ).
        <param>-status = abap_true.
    ENDCASE.

    o_grid->refresh_table_display( is_stable = VALUE lvc_s_stbl( row = abap_true
                                                                 col = abap_true )
                                   i_soft_refresh = abap_false ).
  ENDMETHOD.


ENDCLASS.

**********************************************************************
*
* Datentypen, Variablen, Konstanten
*
**********************************************************************
DATA: o_main TYPE REF TO lcl_main.

**********************************************************************
*
* SELECTION-SCREEN
*
**********************************************************************
SELECTION-SCREEN BEGIN OF SCREEN 2000.
SELECTION-SCREEN END OF SCREEN 2000.

**********************************************************************
*
* INITIALIZATION
*
**********************************************************************
INITIALIZATION.

  o_main = NEW #( o_parent = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_right
                                                           extension = 400
                                                           no_autodef_progid_dynnr = abap_true ) ).

  o_main->add_parameter( VALUE #( name = 'SHOW_RESULT' text = 'Ergebnisse anzeigen' status = abap_true ) ).
  o_main->add_parameter( VALUE #( name = 'HIDE_COLS' text = 'Spalten ausblenden' status = abap_false ) ).
  o_main->add_parameter( VALUE #( name = 'DELETE_ON_EXIT' text = 'Beim Beenden löschen' status = abap_undefined ) ).

**********************************************************************
*
* AT SELECTION-SCREEN OUTPUT
*
**********************************************************************
AT SELECTION-SCREEN OUTPUT.

  IF o_main IS BOUND.
* Flag cell_type triggert den Typ (Hotspot / Button) des Klick-Feldes
    o_main->init_grid( cell_type = lcl_main=>co_celltype_hotspot ).
  ENDIF.

**********************************************************************
*
* AT SELECTION-SCREEN
*
**********************************************************************
AT SELECTION-SCREEN.
* wenn "Ausführen" (F8) geklickt wurde
  IF sy-ucomm = 'CRET'.
    cl_demo_output=>display_data( o_main->get_params( ) ).
  ENDIF.

**********************************************************************
*
* START-OF-SELECTION
*
**********************************************************************
START-OF-SELECTION.
* leeres Selektionbild 2000 anzeigen
  CALL SELECTION-SCREEN 2000.