Thursday, 30 March 2017

ALV With Calculator Functionality

Scenario: The report will create an ALV with an input section in the right side. Numbers & operators will be given in the input & the results will be shown in ALV on the left side. The ALV will have two rows - one editable & other non editable.

On changing the value at the editable section, value must get updated automatically in the ALV. Dropdown list has to be provided for the operator selection in the ALV. On updating the ALV the cursor position should not move to the beginning of the ALV cell.

If the resultant value is negative then the ALV should be highlighted with a different colour.

The entire activity will be carried out with OO approach.


Expected Output:


The Selection Screen For The Initial Input

ALV and the Input section on the right side

On changing the Operator in the ALV, the resultant column should also get change accordingly

After adding a new record in the ALV from the right input section

When the value is negative, the result is displayed 


Solution:

*^--------------------------------------------------------------------^*
*^ Description             : The report will create an ALV with an input section in the right side.
*^                         : Numbers & operators will be given in the input & the results will be shown in ALV
*^                         : The ALV will have two rows - one editable & other non editable
*^                         : On changing the value at the editable section, value must get updated in the ALV
*^                         : Dropdown list has to be provided for the operator selection
*^                         : On updating the ALV the cursor position should not be in the 1st cell of the ALV
*^                         : If the resultant value is negative it should be highloghted with a different colour
*^                         :
*^--------------------------------------------------------------------^*

REPORT zdemo7.
CLASS lcl_event_receiver DEFINITION DEFERRED.  "Means the class definition has been defined somewhere in the prog

*^--------------------------------------------------------------------^*
*^                      Database-Table-Declarations
*^--------------------------------------------------------------------^*

INCLUDE zdemo7_top.

*^--------------------------------------------------------------------^*
*^                      Selection-screen
*^--------------------------------------------------------------------^*

INCLUDE zdemo7_sel.

*
**^--------------------------------------------------------------------^*
**^                      Subroutines
**^--------------------------------------------------------------------^*

INCLUDE zdemo7_sub.

*^--------------------------------------------------------------------^*
*^                      At Selection-Screen
*^--------------------------------------------------------------------^*

AT SELECTION-SCREEN OUTPUT.
  PERFORM create_dropdown USING 'P_OP'.

*^--------------------------------------------------------------------^*
*^                      Start-of-Selection
*^--------------------------------------------------------------------^*

START-OF-SELECTION.

  PERFORM populate_record USING p_num1 p_num2 p_op ' '.
  PERFORM populate_record USING p_num1 p_num2 p_op 'X'.
  PERFORM build_catalog.

  CALL SCREEN 0100.


ZDEMO7_TOP
*&---------------------------------------------------------------------*
*&  Include           ZDEMO7_TOP
*&---------------------------------------------------------------------*

TYPES: BEGIN OF gty_tab,
         num1  TYPE ZBTPRICE,"i,
         num2  TYPE ZBTPRICE,"i,
         op(1),
         res   TYPE int4,
         edit_cell TYPE lvc_t_styl,   "DETERMINES WHICH RECORDS SHOULD BE EDITED
         cellcolor TYPE lvc_t_scol,  "CELL COLOURING
       END OF gty_tab.



DATA: ip_num1       TYPE ZBTPRICE ,"i,
      ip_num2       TYPE ZBTPRICE ,"i,
      ip_op(1),
      op_res        TYPE ZBTPRICE,"i,
      gt_tab        TYPE TABLE OF gty_tab,
      gt_fcat       TYPE lvc_t_fcat, "TABLE OF lvc_s_fcat,
      gv_flag       TYPE i VALUE 0,
      gv_container  TYPE REF TO cl_gui_docking_container,
      gv_grid       TYPE REF TO cl_gui_alv_grid,
      gs_layout     TYPE lvc_s_layo


ZDEMO7_SEL
*&---------------------------------------------------------------------*
*&  Include           ZDEMO7_SEL
*&---------------------------------------------------------------------*

SELECTION-SCREEN: BEGIN OF BLOCK b1 WITH FRAME.
PARAMETERS: p_num1  TYPE  ZBTPRICE,"i,
            p_num2  TYPE  ZBTPRICE,"i,
            p_op(1) AS LISTBOX VISIBLE LENGTH 5
            .
SELECTION-SCREEN: END OF BLOCK b1.


ZDEMO7_SUB
*&---------------------------------------------------------------------*
*&  Include           ZDEMO7_SUB
*&---------------------------------------------------------------------*

*&---------------------------------------------------------------------*
*&      Form  CREATE_DROPDOWN
*&---------------------------------------------------------------------*
*       Dropdown list creation for the operator
*       Used in the selection screen & in the control beside ALV
*
*----------------------------------------------------------------------*

FORM create_dropdown USING lv_name TYPE vrm_id.
  DATA: lt_value TYPE vrm_values,
        ls_value LIKE LINE OF lt_value.
*        lv_name  TYPE vrm_id.

  FREE: lt_value[].
  CLEAR: ls_value.

  ls_value-key = '+'.
  ls_value-text = '+'.
  APPEND ls_value TO lt_value.
  CLEAR: ls_value.

  ls_value-key = '-'.
  ls_value-text = '-'.
  APPEND ls_value TO lt_value.
  CLEAR: ls_value.

  ls_value-key = '*'.
  ls_value-text = '*'.
  APPEND ls_value TO lt_value.
  CLEAR: ls_value.

  ls_value-key = '/'.
  ls_value-text = '/'.
  APPEND ls_value TO lt_value.
  CLEAR: ls_value.

*  lv_name = 'P_OP'.
  CALL FUNCTION 'VRM_SET_VALUES'
    EXPORTING
      id              = lv_name
      values          = lt_value
    EXCEPTIONS
      id_illegal_name = 1
      OTHERS          = 2.

  IF sy-subrc NE 0.
    MESSAGE 'Error in generation of Dropdown' TYPE 'E'.
  ENDIF.

ENDFORM.                    "create_dropdown

*&---------------------------------------------------------------------*
*&      Form  POPULATE_RECORD
*&---------------------------------------------------------------------*
*       Populate Records in the Internal Table
*       If LV_FLAG_EDITABLE is set, the record will be editable
*
*----------------------------------------------------------------------*
FORM populate_record USING lv_num1 TYPE ZBTPRICE"i
                           lv_num2 TYPE ZBTPRICE"i
                           lv_op TYPE c
                           lv_flag_editable TYPE c
                           .
  DATA: ls_tab LIKE LINE OF gt_tab,
        lt_editcell TYPE lvc_t_styl,
        ls_editcell TYPE lvc_s_styl "LIKE LINE OF lt_editcell
        .
  CLEAR: ls_tab.
  ls_tab-num1 = lv_num1.
  ls_tab-num2 = lv_num2.
  ls_tab-op = lv_op.
  CASE lv_op.
    WHEN '+'.
      ls_tab-res = ls_tab-num1 + ls_tab-num2.
    WHEN '-'.
      ls_tab-res = ls_tab-num1 - ls_tab-num2.
    WHEN '*'.
      ls_tab-res = ls_tab-num1 * ls_tab-num2.
    WHEN '/'.
      IF ls_tab-num2 EQ 0.
        ls_tab-res = 0.
      ELSE.
        ls_tab-res = ls_tab-num1 / ls_tab-num2.
      ENDIF.
  ENDCASE.

*  IF THE FLAG IS SET THEN THE RECORD WILL BE EDITABLE
  IF lv_flag_editable = 'X' OR lv_flag_editable = 'x'.

    ls_editcell-fieldname = 'NUM1'.
    ls_editcell-style = '00080000'. " the value represents EDIT ENABLED
*    ls_editcell-style = cl_gui_alv_grid=>mc_style_enabled. " the value represents EDIT ENABLED

    APPEND ls_editcell TO lt_editcell.

    ls_editcell-fieldname = 'NUM2'.
    ls_editcell-style = '00080000'. " the value represents EDIT ENABLED
    APPEND ls_editcell TO lt_editcell.

    ls_editcell-fieldname = 'OP'.
    ls_editcell-style = '00080000'. " the value represents EDIT ENABLED
    APPEND ls_editcell TO lt_editcell.
    ls_tab-edit_cell[] = lt_editcell[].
  ENDIF.

  "IF THE RESULT IS LESS THAN 0 THEN IT SHOULD BE RED
  IF ls_tab-res < 0.
    DATA: w_cellcolor TYPE lvc_s_scol.
    CLEAR w_cellcolor.
    w_cellcolor-fname = 'RES'.
    w_cellcolor-color-col = '7'.
    w_cellcolor-color-int = '1'.
    w_cellcolor-color-inv = '1'.
    INSERT w_cellcolor INTO TABLE ls_tab-cellcolor.
  ELSE.
    REFRESH ls_tab-cellcolor.
  ENDIF.

  APPEND ls_tab TO gt_tab.
ENDFORM.                    "populate_record
*&---------------------------------------------------------------------*
*&      Form  BUILD_CATALOG
*&---------------------------------------------------------------------*
*       Building Fieldcatalog
*       Emphasize the result column & Make a dropdown for the operator column
*
*----------------------------------------------------------------------*
FORM build_catalog .
  DATA: ls_fcat  TYPE lvc_s_fcat,
        lv_count TYPE i VALUE 1
        .
  CLEAR: ls_fcat.

  ls_fcat-fieldname = 'NUM1'.
  ls_fcat-scrtext_m = '1st Number'.
  ls_fcat-col_pos = lv_count.
  APPEND ls_fcat TO gt_fcat.
  lv_count = lv_count + 1.
  CLEAR ls_fcat.

  ls_fcat-fieldname = 'OP'.
  ls_fcat-scrtext_m = 'Operator'.
  ls_fcat-col_pos = lv_count.
  ls_fcat-drdn_hndl = '1'.    "For Dropdown
  APPEND ls_fcat TO gt_fcat.
  lv_count = lv_count + 1.
  CLEAR ls_fcat.

  ls_fcat-fieldname = 'NUM2'.
  ls_fcat-scrtext_m = '2nd Number'.
  ls_fcat-col_pos = lv_count.
  APPEND ls_fcat TO gt_fcat.
  lv_count = lv_count + 1.
  CLEAR ls_fcat.

*    ls_fcat-tech = 'X' .
   ls_fcat-no_sign = ' ' .
  ls_fcat-fieldname = 'RES'.
  ls_fcat-NO_CONVEXT = 'X' .
  ls_fcat-TABNAME = 'GT_TAB' .
  ls_fcat-scrtext_m = 'Result'.
  ls_fcat-col_pos = lv_count.
  ls_fcat-emphasize = 'X'.
  APPEND ls_fcat TO gt_fcat.
  lv_count = lv_count + 1.
  CLEAR ls_fcat.
ENDFORM.                    "build_catalog

*----------------------------------------------------------------------*
*       CLASS lcl_event_receiver DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_event_receiver DEFINITION.
*   EVENT RECEIVER DEFINITIONS FOR ANY DATA CHANGE THAT OCCURS IN THE ALV
  PUBLIC SECTION.
    METHODS:
       handle_user_command
        FOR EVENT data_changed OF cl_gui_alv_grid
            IMPORTING er_data_changed
                      e_onf4
                      e_onf4_before
                      e_onf4_after
                      e_ucomm.
ENDCLASS.                    "lcl_event_receiver DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_event_receiver IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_event_receiver IMPLEMENTATION.
  METHOD handle_user_command.
    DATA: ls_good TYPE lvc_s_modi,
          ls_tab TYPE gty_tab
          .
    LOOP AT er_data_changed->mt_good_cells INTO ls_good.

      READ TABLE gt_tab INTO ls_tab INDEX ls_good-row_id.

      IF sy-subrc EQ 0.

*       CHECKING WHICH FIELD HAS BEEN CHANGED, ACCORDINGLY UPDATE THAT FIELD OF THE INTERNAL TABLE
        IF ls_good-fieldname EQ 'NUM1'.
          ls_tab-num1 = ls_good-value.
        ELSEIF ls_good-fieldname EQ 'OP'.
          ls_tab-op = ls_good-value.
        ELSEIF ls_good-fieldname EQ 'NUM2'.
          ls_tab-num2 = ls_good-value.
        ENDIF.

*       PERFORM THE NECESSARY OPERATION ON THE NEWLY CHANGED VALUE OF THE ALV
        CASE ls_tab-op.
          WHEN '+'.
            ls_tab-res = ls_tab-num1 + ls_tab-num2.
          WHEN '-'.
            ls_tab-res = ls_tab-num1 - ls_tab-num2.
          WHEN '*'.
            ls_tab-res = ls_tab-num1 * ls_tab-num2.
          WHEN '/'.
            ls_tab-res = ls_tab-num1 / ls_tab-num2.
        ENDCASE.

        "IF THE RESULT IS LESS THAN 0 THEN IT SHOULD BE RED
        IF ls_tab-res < 0.
          DATA: w_cellcolor TYPE lvc_s_scol.
          CLEAR w_cellcolor.
          w_cellcolor-fname = 'RES'.
          w_cellcolor-color-col = '7'.
          w_cellcolor-color-int = '1'.
          w_cellcolor-color-inv = '1'.
          INSERT w_cellcolor INTO TABLE ls_tab-cellcolor.
        ELSE.
          REFRESH ls_tab-cellcolor.
        ENDIF.

        MODIFY gt_tab FROM ls_tab INDEX ls_good-row_id.

        IF sy-subrc EQ 0.

*          WHEN THE ALV GETS REFRESHED THE CURSOR GETS SET IN THE 1ST CELL OF THE ALV. TO SET THE CURSOR IN THE LAST POSITION BEFORE THE REFRESH BELOW METHOD IS USED (STABALISER)

          DATA: ls_stable TYPE lvc_s_stbl.
          ls_stable-row = 'X'.
          ls_stable-col = 'X'.
          CALL METHOD gv_grid->refresh_table_display
            EXPORTING
              is_stable = ls_stable
            EXCEPTIONS
              finished  = 1
              OTHERS    = 2.
        ELSE.
          MESSAGE 'Error Occured' TYPE 'E'.
        ENDIF.
      ENDIF.
    ENDLOOP.
  ENDMETHOD.                    "handle_user_command
ENDCLASS.                    "lcl_event_receiver IMPLEMENTATION

*&---------------------------------------------------------------------*
*&      Module  STATUS_0100  OUTPUT
*&---------------------------------------------------------------------*
*       PBO EVENTS OF THE SCREEN
*----------------------------------------------------------------------*
MODULE status_0100 OUTPUT.

  IF gv_flag EQ 0. "MEANS FIRST TIME ALV GENERATION

    SET PF-STATUS 'PF_STATUS'.
    PERFORM create_dropdown USING 'IP_OP'.  "DROPDOWN FOR THE OPERATOR FIELD ON RIGHT SIDE OF ALV
    PERFORM prepare_grid.

    "CREATING EVENT HANDLER FOR ALV INTERACTION
    DATA: lo_event TYPE REF TO lcl_event_receiver.
    CREATE OBJECT lo_event.
    SET HANDLER lo_event->handle_user_command FOR gv_grid.

    "REGISTER EDIT EVENT SO THAT WHEN ENTER IS PRESSED EVENT HANDLER GETS CALLED
    CALL METHOD gv_grid->register_edit_event
      EXPORTING
        i_event_id = cl_gui_alv_grid=>mc_evt_modified
      EXCEPTIONS
        error      = 1
        OTHERS     = 2.

    "FOR DROPDOWN
    PERFORM create_dropdown_for_grid.

    "FOR DISPLAY
    PERFORM display_alv.
  else .
     "FOR DISPLAY
    PERFORM display_alv.
  ENDIF.

ENDMODULE.                    "status_0100 OUTPUT

*&---------------------------------------------------------------------*
*&      Module  USER_COMMAND_0100  INPUT
*&---------------------------------------------------------------------*
*       PAI EVENT OF THE SCREEN
*----------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
  DATA: ls_tab TYPE gty_tab,
        lv_tmp TYPE i
        .
  CLEAR: ls_tab.
  CASE sy-ucomm.
    WHEN '&F03' OR 'BACK' OR 'BCK' OR '&F15' OR '&F12' .
      LEAVE TO SCREEN 0.

    WHEN ' ' OR 'ENTR'.
      PERFORM populate_record USING ip_num1 ip_num2 ip_op ' '.
      PERFORM populate_record USING ip_num1 ip_num2 ip_op 'X'.

      DESCRIBE TABLE gt_tab LINES lv_tmp.
      READ TABLE gt_tab INTO ls_tab INDEX lv_tmp.
      op_res = ls_tab-res.
      PERFORM refresh_alv.
  ENDCASE.
ENDMODULE.                    "user_command_0100 INPUT

*&---------------------------------------------------------------------*
*&      Form  PREPARE_GRID
*&---------------------------------------------------------------------*
*       PREPARING THE GRID
*----------------------------------------------------------------------*
FORM prepare_grid .
  CREATE OBJECT gv_container
    EXPORTING
      ratio                       = 50
    EXCEPTIONS
      cntl_error                  = 1
      cntl_system_error           = 2
      create_error                = 3
      lifetime_error              = 4
      lifetime_dynpro_dynpro_link = 5
      OTHERS                      = 6.
  IF sy-subrc <> 0.
    MESSAGE 'Exception in creating Container Object' TYPE 'E'.
  ENDIF.

  CREATE OBJECT gv_grid
    EXPORTING
      i_parent          = gv_container
    EXCEPTIONS
      error_cntl_create = 1
      error_cntl_init   = 2
      error_cntl_link   = 3
      error_dp_create   = 4
      OTHERS            = 5.
  IF sy-subrc <> 0.
    MESSAGE 'Exception in creating grid' TYPE 'E'.
  ENDIF.

  CALL METHOD gv_grid->set_ready_for_input
    EXPORTING
      i_ready_for_input = 1.

ENDFORM.                    " PREPARE_GRID

*&---------------------------------------------------------------------*
*&      Form  DISPLAY_ALV
*&---------------------------------------------------------------------*
*       DISPLAYING THE GRID
*----------------------------------------------------------------------*

FORM display_alv .
  gs_layout-cwidth_opt = 'X'.

*  THIS INDICATES THAT THE EDIT_CELL WILL BE USED FOR DETERMINING WHETHER THE ROW IS EDITABLE OR NOT
  gs_layout-stylefname = 'EDIT_CELL'.
  gs_layout-ctab_fname = 'CELLCOLOR'.   "SETTING THE CELL COLOUR

  CALL METHOD gv_grid->set_table_for_first_display
    EXPORTING
      is_layout                     = gs_layout
    CHANGING
      it_outtab                     = gt_tab[]
      it_fieldcatalog               = gt_fcat
*     it_sort                       =
*     it_filter                     =
    EXCEPTIONS
      invalid_parameter_combination = 1
      program_error                 = 2
      too_many_lines                = 3
      OTHERS                        = 4.
  IF sy-subrc EQ 0.
    gv_flag = 1. "Means once the ALV has been generated
  ELSE.
*   Implement suitable error handling here
  ENDIF.
ENDFORM.                    " DISPLAY_ALV

*&---------------------------------------------------------------------*
*&      Form  REFRESH_ALV
*&---------------------------------------------------------------------*
*       REFRESH ALV
*----------------------------------------------------------------------*
FORM refresh_alv .
  CALL METHOD gv_grid->refresh_table_display.
  LEAVE LIST-PROCESSING.
ENDFORM.                    " REFRESH_ALV

*&---------------------------------------------------------------------*
*&      Form  CREATE_DROPDOWN_FOR_GRID
*&---------------------------------------------------------------------*
*       DROPDOWN FOR EACH CELLS OF THE ALV
*----------------------------------------------------------------------*

FORM create_dropdown_for_grid .
  DATA: lt_dropdown TYPE lvc_t_drop,
            ls_dropdown TYPE lvc_s_drop
            .
  ls_dropdown-handle = '1'.
  ls_dropdown-value = '+'.
  APPEND ls_dropdown TO lt_dropdown.

  ls_dropdown-handle = '1'.
  ls_dropdown-value = '-'.
  APPEND ls_dropdown TO lt_dropdown.

  ls_dropdown-handle = '1'.
  ls_dropdown-value = '*'.
  APPEND ls_dropdown TO lt_dropdown.

  ls_dropdown-handle = '1'.
  ls_dropdown-value = '/'.
  APPEND ls_dropdown TO lt_dropdown.

  CALL METHOD gv_grid->set_drop_down_table
    EXPORTING
      it_drop_down = lt_dropdown.
ENDFORM.                    " CREATE_DROPDOWN_FOR_GRID


NOTE: Since the result can be negative in the input section, so in the Text I/O Template add V at the end of the Line, else it will give dump.
For the layout and the screen painter maintain the following fields:

General Attributes of the Screen


Layout in the screen painter


Since the result can be negative add 'V' at the end of the line as shown above


No comments:

Post a Comment

Report to find CDS view of Standard Table

A small change has been made to the original program ( SAP YARD Article ) so that it can also display the common CDS used by multiple table...