Skip to Content
1
Former Member
Jan 03, 2008 at 10:50 AM

Implementing a Generic Function module for simple GRIDS.

490 Views

The concept of ALV grid uisng OO looks fine on the surface but an underlying drawback is that each program needs to have a screen and GUI status. ( I'm not discussing the new SALV type as this does not have any editable facility yet).

By building the Screen handling and Class calls within a Function module we can define a reasonably Generic method of creating and displaying Grids via simple Function Module call.

This way for displaying simple grids programs will no longer need a separate screen. The Dynamic table concept can also be used to build almost any type of display you want.

Note this process is designed for essentially "Normal" type table displays -- I haven't tried the approachjfor "Deep Structures".

Using the methodology shown here you should be able to put together any simple ALV display very quickly and in about 15 mins.

Here is a simple program that displays a few sales orders. When the sales order is double clicked in the grid the sales order is displayed via VA03.

All you need to do is pass the structure you want to display to the function module together with some other parameters as shown below. For an editable grid just make i_edit = 'X'.

PROGRAM  zzjimbozzz.
TABLES : vapma.

TYPES:  BEGIN OF s_elements,
  vbeln   TYPE vapma-vbeln,
  posnr   TYPE vapma-posnr,
  matnr   TYPE vapma-matnr,
  kunnr   TYPE vapma-kunnr,
  werks   TYPE vapma-werks,
  vkorg   TYPE vapma-vkorg,
  vkbur   TYPE vapma-vkbur,
  status  TYPE c,

END OF  s_elements.
INCLUDE zz_jimbo_incl.

DATA: ord_nr TYPE vapma-vbeln.

START-OF-SELECTION.

  CREATE DATA dref TYPE s_elements.
  ASSIGN dref->* TO <fs>.
  i_routine = 'POPULATE_DYNAMIC_ITAB'.
  i_names   = 'NAME_COLUMNS'.
  i_gridtitle = 'Sales Order Display'.
  invoker = sy-repid.
  i_zebra = ' '.
  i_edit = ' '.
  CALL FUNCTION 'ZZ_DISPLAY_SINGLE_ALV_GRID'
       EXPORTING
            invoker     = invoker
            my_line     = <fs>
            i_gridtitle = i_gridtitle
            i_edit      = i_edit
            i_zebra     = i_zebra
            i_names     = i_names
            i_routine   = i_routine
       IMPORTING
            z_object    = z_object
            dy_table    = dy_table.

FORM populate_dynamic_itab CHANGING dy_table.
  ASSIGN dy_table->* TO <dyn_table>.
  CREATE DATA dy_line LIKE LINE OF <dyn_table>.
  ASSIGN dy_line->* TO <dyn_wa>.

  SELECT vbeln posnr matnr kunnr werks vkorg vkbur
         UP TO 200 ROWS
         FROM vapma
         INTO  CORRESPONDING FIELDS OF TABLE <dyn_table>.

ENDFORM.

FORM verwerk.

ENDFORM.

FORM refresh.
  CALL METHOD z_object->refresh_grid.

ENDFORM.

FORM dubbelklik USING
        e_row   TYPE lvc_s_row
        e_column TYPE lvc_s_col
        es_row_no TYPE lvc_s_roid.

  READ TABLE <dyn_table> INDEX e_row INTO wa_elements.
  ord_nr = wa_elements-vbeln.
  SET PARAMETER ID 'AUN'  FIELD ord_nr.

  CALL TRANSACTION  'VA03' AND SKIP FIRST SCREEN.
  wa_elements-status = 'V'.
  MODIFY <dyn_table> FROM wa_elements INDEX e_row.


  PERFORM refresh.

  row_number-row_id = e_row.
  CALL METHOD z_object->set_cell
    EXPORTING
            e_column = e_column
            es_row_no = row_number.

ENDFORM.


FORM name_columns CHANGING it_fldcat TYPE lvc_t_fcat.
* Here before displaying you can change the field catalog to
* adjust your own names
* Method call just uses the names in the table structure.

  col_name 1 'Order Nr' 12.
  col_name 2 'Item'  4.
  col_name 3 'Material' 16.
  col_name 4 'Customer' 12.
  col_name 5 'Plant' 4.
  col_name 6 'Sales Org' 4.
  col_name 7 'Sales Office' 4.
  col_name 8 'Status' 2.
ENDFORM.
FORM data_changed
USING
  changed_tab
  inserted_tab
  deleted_tab
  modified_cells_tab.

  ASSIGN  changed_tab->* TO <fs1>.
* code anything here to be done when data in the grid is changed.
ENDFORM.

FORM data_changed_finished.

  IF <fs1> IS ASSIGNED.
* code for any processing needed at end of data change
* updated data is in <dyn_table>.
* if <fs1> not assigned then no data has been changed.
    UNASSIGN <fs1>.
  ENDIF.
ENDFORM.

The INCLUDE


***INCLUDE ZZ_JIMBO_INCL .
* Generic editable ALV prog with dynamic structure and FCAT.
* Jimbo 2007.
 DEFINE col_name.
   read table it_fldcat into  wa_it_fldcat index &1.
   wa_it_fldcat-coltext = &2.
   wa_it_fldcat-outputlen = &3.
   modify it_fldcat from wa_it_fldcat index &1.
 END-OF-DEFINITION.
 DATA:  dref               TYPE REF TO data,
  z_object TYPE REF TO zcl_alv_test, "My ALV class
  invoker                TYPE sy-repid,
  dy_line            TYPE REF TO data,
  dy_table           TYPE REF TO data,
  it_fldcat          TYPE lvc_t_fcat,
   wa_it_fldcat       TYPE lvc_s_fcat,
   i_gridtitle        TYPE lvc_title,
   i_zebra            TYPE lvc_edit,
   i_edit             TYPE lvc_edit,
   wa_elements        TYPE s_elements,
   row_number         TYPE lvc_s_roid,
   i_routine(30)        TYPE c,
   i_names(30)          TYPE c,
   lt_dropdown TYPE lvc_t_drop,
   ls_dropdown TYPE lvc_s_drop.

 FIELD-SYMBOLS: <fs> TYPE ANY,
   <fs1>           TYPE  ANY,
   <dyn_table>    TYPE  STANDARD TABLE,
    <dyn_wa>.

The Function module

function zz_display_single_alv_grid .
*"----------------------------------------------------------------------
*"*"Local interface:
*"  IMPORTING
*"     REFERENCE(INVOKER) TYPE  SYREPID
*"     REFERENCE(MY_LINE) TYPE  ANY
*"     REFERENCE(I_GRIDTITLE) TYPE  LVC_TITLE
*"     REFERENCE(I_EDIT) TYPE  LVC_EDIT
*"     REFERENCE(I_ZEBRA) TYPE  LVC_EDIT
*"     REFERENCE(I_ROUTINE) TYPE  CHAR30
*"     REFERENCE(I_NAMES) TYPE  CHAR30 OPTIONAL
*"  EXPORTING
*"     REFERENCE(DY_TABLE) TYPE REF TO  DATA
*"     REFERENCE(Z_OBJECT) TYPE REF TO  ZCL_ALV_TEST
*"----------------------------------------------------------------------
*
* This function module instantiates a generic
* ALV handling class
* Builds a dynamic fcat from the structure passed in my_line
* Creates a dynmic table using the FCAT created in the class
* calls the alv display
* Using this approach means that the calling programs
* now no longer need a separate screen.
* The dynamic table is now filled in the
* form whose name is passed via parameter i_routine
* which MUST exist in the calling program.
* It is done this way as it is not praticable to have
* a completely generic method of filling the dynamic table
* as data selection depends on the application - could be via
* joins etc etc.

* Note that screen 100 and a standard interface (se41) are contained *in
* the main program of this function module.
* screen just has one element a custom container called *CCONTAINER1
* status (SE41) is just a standard status with BACK EXIT and CANCEL
* buttons.
* screen logic simply
* PROCESS BEFORE OUTPUT.
* MODULE STATUS_0100.
*
* PROCESS AFTER INPUT.
* MODULE USER_COMMAND_0100.


*
*module STATUS_0100 output.
*z_object = <zogzilla>.
* call method z_object->display_grid
* exporting
*  g_outtab = <dyn_table>
*  g_fldcat = it_fldcat
*  i_gridtitle = w_gridtitle
*  i_edit = w_edit
*  i_zebra = w_zebra
*  changing
*  it_fldcat = it_fldcat
*  gt_outtab = <dyn_table>.
*  set pf-status '001'.
*     set titlebar '000'.
*  ENDMODULE.


*MODULE user_command_0100 INPUT.
*
*  CASE sy-ucomm.
*    WHEN 'BACK'.
*      LEAVE PROGRAM.
*    WHEN 'EXIT'.
*      LEAVE PROGRAM.
*    WHEN 'RETURN'.
*      LEAVE PROGRAM.
*    WHEN OTHERS.
*  ENDCASE.
*ENDMODULE.



* Function module code
* Create instance of the ALV handling class ZCL_ALV_TEST
* Build an FCAT based on the structure passes in my_line
* create a dynmic table based on the FCAT created
* call back to the calling program (invoker) to fill
* the dynamic table
* call the screen to display tha ALV grid
*
* event handling etc all built into the class

  if z_object is initial.
    create object z_object
          exporting z_object = z_object.
    call method z_object->build_dynamic_structures
  exporting
    my_line = my_line
    calling_program = invoker
  importing
    dy_table = dy_table
  changing
    it_fldcat = it_fldcat.

  endif.

* variable z_object contains the instance of our class zcl_alv_test
* we need to keep the value as it needs to be passed to the PBO routine
* when screen 100 is called.

  assign z_object to <zogzilla>.

*
  perform (i_routine) in program (invoker)
  changing dy_table.

* As detailed in the comments above this form MUST exist in the calling
* program
*

* change column headings etc if required  - not mandatory
  if not i_names is initial.
    perform (i_names) in program (invoker)  if found
       changing it_fldcat.
  endif.
* now display the grid

  assign dy_table->* to <dyn_table>.
  w_gridtitle = i_gridtitle.
  w_edit = i_edit.
  w_zebra = i_zebra.
  call screen 100.

endfunction.

All you need to do is call your ALV handling class -- the methods etc are in a class ZCL_ALV_TEST


class zcl_alv_test definition
  public
  final
  create public .

*"* public components of class ZCL_ALV_TEST
*"* do not include other source files here!!!
public section.

  events before_user_command .
  events toolbar .

  methods set_cell
    importing
      !e_column type lvc_s_col
      !es_row_no type lvc_s_roid .
  methods build_dynamic_structures
    importing
      !my_line type any
      !calling_program type sy-repid
    exporting
      !dy_table type ref to data
    changing
      !it_fldcat type lvc_t_fcat .
  methods change_title
    importing
      !i_gridtitle type lvc_title .
  methods constructor
    importing
      !z_object type ref to zcl_alv_test .
  methods display_grid
    importing
      !g_outtab type standard table
      !g_fldcat type lvc_t_fcat
      !i_gridtitle type lvc_title
      !i_edit type lvc_edit
      !i_zebra type lvc_zebra
    changing
      !it_fldcat type lvc_t_fcat
      !gt_outtab type standard table .
  methods refresh_grid .
  methods set_drop_down_table
    importing
      !it_drop_down type lvc_t_drop .




*"* private components of class ZCL_ALV_TEST
*"* do not include other source files here!!!
private section.

  data lr_rtti_struc type ref to cl_abap_structdescr .
  data:
    zog                     like line of lr_rtti_struc->components .
  data:
    zogt                    like table of zog .
  data wa_it_fldcat type lvc_s_fcat .
  data it_fldcat type lvc_t_fcat .
  data dy_table type ref to data .
  data dy_line type ref to data .
  data struct_grid_lset type lvc_s_layo .
  data e_row type lvc_s_row .
  data e_column type lvc_s_col .
  data es_rowid type lvc_s_roid .
  data grid_container1 type ref to cl_gui_custom_container .
  data grid1 type ref to cl_gui_alv_grid .
  data ls_layout type kkblo_layout .
  data lt_fieldcat_wa type kkblo_fieldcat .
  data gt_outtab type ref to data .
  data l_mode type raw4 .
  data celltab type lvc_t_styl .
  data wa_celltab type lvc_s_styl .
  data lt_fieldcat type kkblo_t_fieldcat .
  data l_tabname type slis_tabname .
  data ls_toolbar type stb_button .
  data inserted_tab type lvc_t_moce .
  data deleted_tab type lvc_t_moce .
  data changed_tab type ref to data .
  data caller type sy-repid .
  data modified_cells_tab type lvc_t_modi .
  data g_outtab1 type ref to data .
  data g_fldcat1 type ref to data .

  methods on_user_command
    for event before_user_command of cl_gui_alv_grid
    importing
      !e_ucomm
      !sender .
  methods on_toolbar
    for event toolbar of cl_gui_alv_grid
    importing
      !e_object
      !e_interactive .
  methods on_dubbelklik
    for event double_click of cl_gui_alv_grid
    importing
      !e_row
      !e_column
      !es_row_no .
  methods handle_data_changed
    for event data_changed of cl_gui_alv_grid
    importing
      !er_data_changed .
  methods handle_data_changed_finished
    for event data_changed_finished of cl_gui_alv_grid
    importing
      !e_modified .
  methods process .
  methods dubbelklik
    importing
      !e_row type lvc_s_row
      !e_column type lvc_s_col
      !es_row_no type lvc_s_roid .
  methods return_structure
    importing
      !my_line type any .
  methods create_dynamic_fcat
    exporting
      !it_fldcat type lvc_t_fcat .
  methods create_dynamic_table
    importing
      !it_fldcat type lvc_t_fcat
    exporting
      !dy_table type ref to data .
  methods download_to_excel .
  methods refresh .
  methods switch .




method set_cell.
call method grid1->set_current_cell_via_id

exporting
  is_column_id =  e_column
  is_row_no  =  es_row_no.

* ...
endmethod.



method build_dynamic_structures.
caller = calling_program.
    call method me->return_structure
       exporting
            my_line = my_line.
    call method me->create_dynamic_fcat
      importing
            it_fldcat = it_fldcat.
    call method me->create_dynamic_table
      exporting
            it_fldcat = it_fldcat
      importing
            dy_table        = dy_table.

* ...
endmethod.

method change_title.
   call method grid1->set_gridtitle
         exporting
             i_gridtitle =  i_gridtitle.

* ...
endmethod.



method constructor.
create object grid_container1
        exporting
           container_name = 'CCONTAINER1'.
    create object  grid1
       exporting
          i_parent = grid_container1.
    set handler z_object->on_user_command for grid1.
    set handler z_object->on_toolbar for grid1.
    set handler z_object->handle_data_changed for grid1.
    set handler z_object->handle_data_changed_finished for grid1.
    set handler z_object->on_dubbelklik for grid1.
    call method grid1->register_edit_event
        exporting
           i_event_id = cl_gui_alv_grid=>mc_evt_enter.
  endmethod.



method display_grid.
get reference of g_outtab into g_outtab1.
    get reference of g_fldcat into g_fldcat1.
    struct_grid_lset-edit = i_edit.    "To enable editing in ALV
    struct_grid_lset-zebra = i_zebra.

    struct_grid_lset-grid_title = i_gridtitle.
*    struct_grid_lset-grid_title = 'TEST ALV USE generic class'.

    struct_grid_lset-ctab_fname = 'T_CELLCOLORS'.
    struct_grid_lset-stylefname = 'CELLTAB'.
     call method grid1->set_ready_for_input
        exporting
            i_ready_for_input = '1'.
    call method grid1->set_table_for_first_display


       exporting
             is_layout       = struct_grid_lset

       changing
             it_outtab       = gt_outtab
             it_fieldcatalog = it_fldcat.
  endmethod.

* ...

method refresh_grid .
call method cl_gui_cfw=>flush.
    call method grid1->refresh_table_display.

* ...
endmethod.

method set_drop_down_table.
call method grid1->set_drop_down_table
exporting it_drop_down = it_drop_down.
* ...
endmethod.



method on_user_command.
*        FOR EVENT before_user_command OF cl_gui_alv_grid
*        IMPORTING
*          e_ucomm
*          sender.
case e_ucomm.
      when 'EXIT'.
        leave program.
      when 'EXCEL'.
        call method me->download_to_excel.
      when 'SAVE'.
      when 'PROC'.
        call method me->process.
      when 'REFR'.
        call method me->refresh.
        when 'SWITCH'.
        call method me->switch.
    endcase.

* ...
endmethod.

method on_toolbar.
type-pools icon.
clear ls_toolbar.
    move 0 to ls_toolbar-butn_type.
    move 'EXIT' to ls_toolbar-function.
    move space to ls_toolbar-disabled.
    move icon_system_end to ls_toolbar-icon.
    move 'Click2Exit' to ls_toolbar-quickinfo.
    append ls_toolbar to e_object->mt_toolbar.
    clear ls_toolbar.
    move  0 to ls_toolbar-butn_type.
    move 'SAVE' to ls_toolbar-function.
    move space to ls_toolbar-disabled.
    move  icon_system_save to ls_toolbar-icon.
    move 'Save data' to ls_toolbar-quickinfo.
    append ls_toolbar to e_object->mt_toolbar.
    clear ls_toolbar.
    move  0 to ls_toolbar-butn_type.
    move 'SWITCH' to ls_toolbar-function.
    move  space to ls_toolbar-disabled.
    move  icon_toggle_display_change to ls_toolbar-icon.
    move 'Switch processing mode' to ls_toolbar-quickinfo.
    move  'SWITCH' to ls_toolbar-text.
    append ls_toolbar to e_object->mt_toolbar.
    clear ls_toolbar.
    move  0 to ls_toolbar-butn_type.
    move 'PROC' to ls_toolbar-function.
    move  space to ls_toolbar-disabled.
    move   icon_businav_process to ls_toolbar-icon.
    move 'Process.' to ls_toolbar-quickinfo.
    move  'PROC' to ls_toolbar-text.
    append ls_toolbar to e_object->mt_toolbar.
    clear ls_toolbar.
    move  0 to ls_toolbar-butn_type.
    move 'EXCEL' to ls_toolbar-function.
    move  space to ls_toolbar-disabled.
    move  icon_xxl to ls_toolbar-icon.
    move 'Excel' to ls_toolbar-quickinfo.
    move  'EXCEL' to ls_toolbar-text.
    append ls_toolbar to e_object->mt_toolbar.
    move  0 to ls_toolbar-butn_type.
    move 'REFR' to ls_toolbar-function.
    move  space to ls_toolbar-disabled.
    move  icon_refresh to ls_toolbar-icon.
    move  'Refresh' to ls_toolbar-quickinfo.
    move  'REFR' to ls_toolbar-text.
    append ls_toolbar to e_object->mt_toolbar.

* ...
endmethod.

method on_dubbelklik.
call method me->dubbelklik
        exporting
           e_row  = e_row
           e_column =  e_column
           es_row_no = es_row_no.

* ...
endmethod.

method handle_data_changed.
* Insert user code here if required
* this METHOD is entered if user ENTERS DATA.
    changed_tab  = er_data_changed->mp_mod_rows.
    inserted_tab = er_data_changed->mt_inserted_rows.
    deleted_tab  = er_data_changed->mt_deleted_rows.
    modified_cells_tab = er_data_changed->mt_mod_cells.
    perform data_changed  in program (caller) if found
       using changed_tab
             inserted_tab
              deleted_tab
              modified_cells_tab.

* ...
endmethod.

method handle_data_changed_finished.
* if field symbol is unassigned it means no data has been changed;

* Insert user code here if required
* METHOD entered here after data entry has finished.
    perform data_changed_finished  in program (caller) if found.

* ...
endmethod.

method process.
perform process in program (caller) if found.


* ...
endmethod.

method dubbelklik.
perform dubbelklik in program (caller)  if found

     using
      e_row
      e_column
      es_row_no.

* ...
endmethod.

method return_structure.
 lr_rtti_struc ?= cl_abap_structdescr=>describe_by_data( my_line ).
    zogt[]  = lr_rtti_struc->components.

* ...
endmethod.

method create_dynamic_fcat.
 loop at zogt into zog.
      clear wa_it_fldcat.
      wa_it_fldcat-fieldname = zog-name .
      wa_it_fldcat-datatype = zog-type_kind.
      wa_it_fldcat-inttype = zog-type_kind.
      wa_it_fldcat-intlen = zog-length.
      wa_it_fldcat-decimals = zog-decimals.
      wa_it_fldcat-coltext = zog-name.
      wa_it_fldcat-lowercase = 'X'.
      append wa_it_fldcat to it_fldcat .
    endloop.

* ...
endmethod.

method create_dynamic_table.
call method cl_alv_table_create=>create_dynamic_table
       exporting
            it_fieldcatalog = it_fldcat
       importing
            ep_table = dy_table.

* ...
endmethod.

method download_to_excel.
field-symbols:
       <fs0> type standard table,
       <fs1> type standard table.
    assign g_outtab1->* to <fs0>.
    assign g_fldcat1->* to <fs1>.
       call function  'LVC_TRANSFER_TO_KKBLO'
      exporting
        it_fieldcat_lvc   = <fs1>
*     is_layout_lvc     = m_cl_variant->ms_layout
         is_tech_complete  = ' '
      importing
        es_layout_kkblo   = ls_layout
        et_fieldcat_kkblo = lt_fieldcat.

    loop at lt_fieldcat into lt_fieldcat_wa.
      clear lt_fieldcat_wa-tech_complete.
      if lt_fieldcat_wa-tabname is initial.
        lt_fieldcat_wa-tabname = '1'.
        modify lt_fieldcat from lt_fieldcat_wa.
      endif.
      l_tabname = lt_fieldcat_wa-tabname.
    endloop.
    call function 'ALV_XXL_CALL'
         exporting
              i_tabname           = l_tabname
              is_layout           = ls_layout
              it_fieldcat         = lt_fieldcat
              i_title             = sy-title
         tables
              it_outtab           = <fs0>
         exceptions
              fatal_error         = 1
              no_display_possible = 2
              others              = 3.
    if  sy-subrc <> 0.
      message id sy-msgid type 'S' number sy-msgno
             with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    endif.

* ...
endmethod.

method refresh.
perform refresh in program (caller) if found.

* ...
endmethod.

method switch.
if grid1->is_ready_for_input( ) eq 0.
 call method grid1->set_ready_for_input
                     exporting i_ready_for_input = 1.
  else.
    call method grid1->set_ready_for_input
                     exporting i_ready_for_input = 0.
  endif.


* ...
endmethod.

Have fun

Cheers

Jimbo