Download the Source Code for this example here!
I have spent a fair amount of time in the past researching an OO approach to classic Dynpro ABAP Screen development.
The approach that I have used in the past is basically a hack. It isn’t nearly as elegant as Model View Controller.
Always being on the lookout for a better approach to Dynpro based development, I was surprise to stumble across a little gem the other day as I was doing research on the new ALV Object Model in WebAS 640. What I found was a set of classes in Package SALV_DYNPRO that looked strangely like an OO Screen Framework for Dynpro. Sure enough after a little bit of investigation, it even began to vaguely resemble MVC. It isn’t quite the Holy Grail of Dynpro development because you still need a Function Group to house your Screens and Statuses; but with the right structure and some clever use of Includes, even this isn’t too big a deal.
Unfortunately the SAP classes are rather bound up in the complex coding of the ALV OM. My goal then was to try and create a simple example to prove out if these classes could be used outside of the ALV OM. I just wanted to create a very simple example with two screen. The program navigates between the two screens and responds to PBO/PAI events through OO event handlers.
The Old Stuff
Like I said earlier, there are a few legacy pieces to this puzzle. We might as well get those out of the way to begin with.
We need to create a function group to house our legacy elements. This is where we will create our GUI Status, a generic Gui Title, the screen definitions themselves and a generic function module to actually call the screens.
The GUI Status would be defined like normal. For the Gui Title we will just enter dynamic elements so that a single Title can service any number of screens that we have (&1 &2 &3 &4 &5).
For the Screens, we will define them in the Screen Painter just like normal. Be sure to set the OKCode to the variable G_OKCODE. One of the screens will have a few buttons on them so that we can demonstrate OO Event Handlers for them.
The flow Logic for all the screens will be exactly the same. We will use a generic set of modules (written by SAP and linked in via several includes) in every screen.
process before output. module d0000_pbo_set_status. module d0000_pbo. process after input. module d0000_pai_fcode at exit-command. module d0000_pai. module d0000_pai_fcode.
The function module itself, Z_DYNPRO_CALL_SCREEN, is designed to call a screen dynamically (either full screen or as a popup). The following is its coding.
function z_dynpro_call_screen . *"-------------------------------------------------------------------- *" *"Local Interface: *" IMPORTING *" REFERENCE(I_DYNNR) TYPE SYDYNNR *" REFERENCE(I_POPUP) TYPE SAP_BOOL OPTIONAL *" REFERENCE(I_STARTING_X) TYPE I OPTIONAL *" REFERENCE(I_ENDING_X) TYPE I OPTIONAL *" REFERENCE(I_STARTING_Y) TYPE I OPTIONAL *" REFERENCE(I_ENDING_Y) TYPE I OPTIONAL *"-------------------------------------------------------------------- data: l_starting_x type i, l_ending_x type i, l_starting_y type i, l_ending_y type i. case i_popup. when space. call screen i_dynnr. when others. l_starting_x = i_starting_x. l_ending_x = i_ending_x. l_starting_y = i_starting_y. l_ending_y = i_ending_y. if l_starting_x is initial. l_starting_x = 1. endif. if l_ending_x is initial. endif. if l_starting_y is initial. l_starting_y = 1. endif. if l_ending_y is initial. endif. call screen i_dynnr starting at l_starting_x l_starting_y ending at l_ending_x l_ending_y. endcase. endfunction.
The final piece is to link in the SAP includes for our Flow Logic Modules. That is done in the Global Data Section of the Function Group.
function-pool zesu_bc640_oo_dynpro_leg. "MESSAGE-ID .. include lsalv_dynpro_frameworkdef. include lsalv_dynpro_frameworki00. include lsalv_dynpro_frameworko00. include lsalv_dynpro_frameworkf00.
The New Stuff
We will have few attributes in this class that link our Screen Class to the Legacy Components. This is where we can supply the name of the Title, Status and Program to use for linking to these Legacy Components. The C_REPID field has the name of our Function Group Program.
You can see that the Framework provided by the inheritance (CL_CTRLER_SCREEN and CL_CTRLER_SCREEN_WINOW) provide plenty of event handlers that we can redefine with our own coding. However we will start with the CONSTRUCTOR. This is where we will initialize the screen framework and register our event handlers.
method constructor. super->constructor( ). repid = c_repid. dynnr = '0100'. data: l_pfstatus type sypfkey. case popup. when space. l_pfstatus = c_pfstatus_window. when others. l_pfstatus = c_pfstatus_popup. endcase. r_status->set_pfstatus( pfstatus = l_pfstatus pfstatus_repid = me->c_repid ). set handler navigate for me. endmethod.
Next we have the ON_CALL_SCREEN method. This is the event handler that is called by the Screen Framework whenever a Call Screen event is raised. By redefining this event we can hook into our Function Module from earlier thereby controlling which screens we call.
method on_call_screen. call function 'Z_DYNPRO_CALL_SCREEN' exporting i_dynnr = dynnr i_popup = popup i_starting_x = starting_x i_ending_x = ending_x i_starting_y = starting_y i_ending_y = ending_y. endmethod.
Next we have the logic that is the OO replacement for the PAI Processing. By redefining ON_PROCESS_FCODE, we have our custom event handler for classic Dynpro Events.
method on_process_fcode. *@78QImporting@ VALUE( FCODE ) TYPE SYUCOMM super->on_process_fcode( fcode ). if r_status->pfstatus_repid eq c_repid and ( r_status->pfstatus eq c_pfstatus_window or r_status->pfstatus eq c_pfstatus_popup ). case fcode. when 'BACK' or 'CANC' or 'OK'. set screen 0. leave screen. set_fcode_handled( ). when 'EXIT'. leave program. when 'PRESS_ME'. raise event navigation_requested. when 'HI'. message 'OO Event Handler! Yay!' type 'I'. set_fcode_handled( ). when others. raise event handle_fcode exporting fcode = fcode. endcase. endif. endmethod.
When you press one of the buttons in my application I want to navigate to my second screen. I decided to implement this Event through my own custom event handler. Notice that in the processing for PRESS_ME, I just raise another event, event navigation_requested.
We then can create our own custom event handler for this event.
method navigate . if dynnr = '0100'. dynnr = '0200'. else. dynnr = '0100'. endif. clear r_screen. me->display( ). set_fcode_handled( ). endmethod.
So now all we need is a TCode to call our class. We could create an executable ABAP program that initializes our class and calls the constructor. We can then attach a traditional TCode to that Program. But that feels a little wrong somehow. Instead let’s stick with OO and create an OO Transaction Code that directly initializes our class. That way we can avoid procedural ABAP as much as possible.
This has been a rather simplistic example, but hopefully it shows the potential for an OO (even MVC) approach to Dynpro Screen Programming. I am looking forward to creating a real world application using this approach in next few weeks. That will be the real test of how useful it might be.