Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
AB
Contributor
Recently I had reason to go back in time and read a set of blogs by riscutia.tudor on the ABAP BUS screen framework. For those unfamiliar with the framework, the BUS screen framework separates dynpro screen definition from the implementation of screen behaviour using an ABAP object oriented framework.

The first of Tudor's blogs provides a short introduction to the BUS framework

I was prompted by a recent reader's question requesting more details on how to use tabstrip controls with the framework. Given I'd recently had to use tabstrip controls in the framework, I thought I'd build upon Tudor's good work and contribute a short how-to blog with some coding snippets on using tabstrips in the BUS framework.

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.



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.



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 .



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.



 

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.

I can also recommend the now nearly 12 year old SAP Press book ABAP Objects: Application Development from Scratch by thorsten.franz.operatics and tobias.trapp which contains nearly 40 pages on the topic.

Enjoy!