Wednesday, 22 January 2020

BUS Screen Framework – Working with Tabstrips

This blog assumes an elementary knowledge of the BUS screen framework and some experience in working with tabstrip controls in classic dynpro screens. the short introduction above may well be helpful.

Let’s get started:

A dynpro screen contains the definition of the screen layout and flow logic expressed as screen modules.  However, when using the BUS framework, the implementation of the screen flow logic behaviour is realised using local classes inheriting from the global classes of the BUS screen framework.

To demonstrate the use of tabstrips with the BUS screen framework, I’ll outline the development of a single screen containing a single tabstrip control with three tabs. Each tab reveals a sub-screen. The screen displays a booking from the SFLIGHT model, which I’ve chosen to use because it is distributed with every SAP ABAP system.

For those visual readers – a view of the screen with the booking details shown in three tabs. The customer tab is active.

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning, SAP ABAP Online Exam

In this example, I’ve defined the main screen as number 0100 with screen behaviour implemented in a local class LCL_0100 inheriting from CL_BUS_ABSTRACT_MAIN_SCREEN.

The 3 sub-screens displayed in the tabstrip area of the main screen I’ve numbered 0101, 0102 and 0103. For simplicity, these screens do not have any behaviour – but if they did, their behaviour would be implemented in local classes ( perhaps LCL_0101, LCL_0102 etc ) inheriting from CL_BUS_ABSTRACT_SUB_SCREEN.

So let’s start with the mechanics of the build.

Consistent with the classical screen programming model, it is necessary to define a tabstrip control as a global definition in the program to which the screens belong.

CONTROL TABSTRIP_0100 TYPE TABSTRIP. 

Next I define a local class to control the behaviour of the main screen – screen 0100. I’ll defined the local class as class LCL_0100. In the blog I refer to this local class as the screen class of screen 0100.

The screen class interacts with the BUS framework. Without a tabstrip, the inheritance and redefinition of methods from the global class CL_BUS_ABSTRACT_MAIN_SCREEN would be sufficient. However, because the screen also contains a tabstrip, the screen class also contains references to the class CL_BUS_TABSTRIP and the structure BUS_SCREEN_TABSTRIP.

CLASS LCL_0100 DEFINITION
INHERITING FROM CL_BUS_ABSTRACT_MAIN_SCREEN.
PUBLIC SECTION.
...
 DATA MR_TABSTRIP TYPE REF TO CL_BUS_TABSTRIP.
 CLASS-DATA MS_TABSTRIP TYPE BUS_SCREEN_TABSTRIP.
...
ENDCLASS. 

Having defined the tabstrip control in the program and the BUS related attributes in the screen class LCL_0100, I can now proceed using the graphical screen painter to define the tabstrip in the SAPGUI screen 0100 following the well documented path described in the SAP Help. I’ve chosen to name the subscreen area SUB_0100_01. The structure of the name isn’t important to the framework.

Care does need to be taken when defining the tabstrip and the tabs in the screen painter to ensure that the element names and functions assigned correspond to the BUS related attributes defined in the local class.

For example, note how the names of each tab refer to LCL_0100=>MS_TABSTRIP-TAB_xx where xx is the number of the tab e.g.  LCL_0100=>MS_TABSTRIP-TAB_01 for the first tab. This mapping allows the BUS framework to set the title and potentially the icon of the tab.

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning, SAP ABAP Online Exam

Each tab is also assigned a function – in this example FKT_TAB_xx where xx is the number of the tab e.g FKT_TAB_01 for the first tab. Each tab is also linked to the subscreen area by entry of the subscreen area name SUB_0100_01 in the reference field. For clarity, an image below of the definition of tab 03 .

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning, SAP ABAP Online Exam

That was a lot of detail, so before I go further, a summary of what has been done.

1. Declared the tabstrip control in the program of the main screen
2. Declared the reference to the BUS tabstrip class in the local class of the main screen
3. Declared the reference to the BUS tabstrip attributes in the local class of the main screen
4. Defined the tabstrip area in the main screen using screen painter
5. Defined the details of each tab in the tabstrip referencing the BUS tabstrip details.

It is worth reviewing the flow logic of the screen 0100. Note the call of the subscreen and the use of the BUS tabstrip details to specify the subscreen to be called. The called subscreen is dynamically determined at runtime based upon the contents of the ms_tabstrip. I’ll show shortly how that is achieved.

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning, SAP ABAP Online Exam

At this stage, I’ve completed the screen definition and now need to consider the implementation of the screen class LCL_0100 to ensure the BUS framework sets up the tabstrip in the PROCESS BEFORE OUTPUT processing of screen 0100.

Having read Tudor’s previous blog, we are aware that the screen modules of the dynpro call the BUS screen framework which in turn interacts with our screen class. Following the approach in Tudor’s blog,  I define screen modules that call the methods of the BUS framework.

MODULE dynpro_pbo_begin OUTPUT.

  cl_bus_abstract_main_screen=>dynpro_pbo_begin(
    EXPORTING
      iv_program_name  = sy-repid                 " ABAP Program Name
      iv_dynpro_number = sy-dynnr                 " ABAP Program: Number of Current Screen
  ).

ENDMODULE.

The framework method dynpro_pbo_begin calls the method pbo_begin in the screen class LCL_0100. It is in the call of this method, during the pbo of the screen that the tabstrip is added to the BUS framework using the inherited method add_tabstrip.

CLASS lcl_0100 IMPLEMENTATION.

  METHOD pbo_begin.

...

    IF mr_tabstrip IS NOT BOUND.

      me->add_tabstrip(
        EXPORTING
          iv_field_name_prefix    = 'LCL_0100=>MS_TABSTRIP' " Prefix for Global Field Names
          iv_function_code_prefix = 'FKT'                   " Prefix for Functions Codes
        IMPORTING
          ev_tabstrip             = mr_tabstrip
        CHANGING
          cs_tabstrip_control     = tabstrip_0100            " Tabstrip defined with CONTROLS
          cs_tabstrip_fields      = lcl_0100=>ms_tabstrip    " Tabstrip Fields defined with DATA
      ).
...
    ENDIF.
 ...
    super->pbo_begin( ).

  ENDMETHOD.
..
ENDCLASS.

Having made the existence of the tabstrip known, the next steps are to add tabs to the tabstrip. This is achieved with the method add_tab of the tabstrip reference mr_tabstrip.

CLASS lcl_0100 IMPLEMENTATION.

  METHOD pbo_begin.

...

    IF mr_tabstrip IS NOT BOUND.

      me->add_tabstrip(
        EXPORTING
          iv_field_name_prefix    = 'LCL_0100=>MS_TABSTRIP' " Prefix for Global Field Names
          iv_function_code_prefix = 'FKT'                   " Prefix for Functions Codes
        IMPORTING
          ev_tabstrip             = mr_tabstrip
        CHANGING
          cs_tabstrip_control     = tabstrip_0100            " Tabstrip defined with CONTROLS
          cs_tabstrip_fields      = lcl_0100=>ms_tabstrip    " Tabstrip Fields defined with DATA
      ).

      DATA lr_tab TYPE REF TO cl_bus_tabstrip_tab.
      DATA ls_area TYPE bus_screen_area.

      CLEAR: lr_tab, ls_area.
      ls_area-program_name = sy-repid.
      ls_area-dynpro_number = '0101'.
      mr_tabstrip->add_tab(
        IMPORTING
          ev_tab = lr_tab  ).
      lr_tab->set_area( ls_area ).
      lr_tab->set_caption( iv_caption = 'Customer' ).

 " And further calls for each other tab that needs to be added
...

    ENDIF.
 ...
    super->pbo_begin( ).

  ENDMETHOD.
..
ENDCLASS.

I’ll leave it to you to discover some of the other methods of class CL_BUS_TABSTRIP_TAB with which the tab can be controlled.

Exhausted? We are almost there! The last remaining framework specific activity necessary to undertake is the handling of the tab functions.

Screen functions in the BUS framework are handled as events. The framework raises an event after all of the PAI processing is completed. The subscribed event handler handles the event and receives the function code to be handled. The event handler could be a method of the screen class or you may of course decide to implement a local controller to handle the events of several screens.

Whatever approach you choose, somewhere you define a method to handle the event below.

FOR EVENT process_after_input OF cl_bus_abstract_main_screen
                                                IMPORTING iv_function_code.

Whilst most other functions are to be directly handled by custom code in the event handler, the functions of tabs are directed to the framework. This is because the BUS framework is responsible for screen handling. So how do we decide what functions are tab functions that should go to the framework and those application specific functions that the handler should handle?

You may recall when the tab was defined, each tab was allocated a function. e.g. The 3rd tab was defined in screen painter with the function FKT_TAB_03. When the tab of the 3rd tab is pressed, the function FKT_TAB_03 is triggered. You may also have noticed when the tabstrip was added, using the add_tabstrip method, that the method call was provided a prefix for the tab function code. The prefix in the example was ‘FKT’.  The BUS framework is able to identify tab functions based upon the provided prefix.

So let’s assume the method dispatch is the handler for the event process_after_input. Then tab functions are handled in the BUS framework by calling the dispatch method of the tabstrip, as shown below.

method dispatch.
...         
        me->mr_tabstrip->dispatch(
          EXPORTING
            iv_function_code =  iv_function_code                " IV_FUNCTION_CODE
          IMPORTING
            ev_dispatched    =  lv_dispatched
        ).

...
 " Not yet dispatched - then custom functions to handle.
....

endmethod.

If the function is a tabstrip function, the function is handled and the tab pressed becomes the active tab. If the function is not a tabstrip function, then the function is not handled and the indicator lv_dispatched is not set. The event handler method and not the BUS framework handles such application events.

Whilst all this seems to be a lot at first glance, let me list out the steps I’ve taken.

1. Declare the tabstrip control in the program of the main screen
2. Declared the reference to the BUS tabstrip class in the local class of the main screen
3. Declared the reference to the BUS tabstrip attributes in the local class of the main screen
4. Defined the tabstrip area in the main screen using screen painter
5. Defined the details of each tab in the tabstrip referencing the BUS tabstrip details
6. Advise the BUS framework of the tabstrip and tabs in the method pbo_begin of the screen class.
7. In the event handler for the screen, dispatch the tab functions to the BUS framework – and handle other functions directly in the event handler.

That’s it in a nutshell.

Whilst the code snippets are not fully complete, I believe I’ve outlined the sufficient details needed to get started with using tabs and tabstrips in the BUS framework if you already understand how to use the framework for simpler screens.

For more details, I can point you to the global classes of the package BUS_TOOLS part of the software component SAP_ABA – Application Basis, particularly classes CL_BUS_ABSTRACT_* and CL_BUS_TABSTRIP* . These classes gives an insight into some of the capabilities of the framework not covered here.

No comments:

Post a Comment