Interactive Reports — The GET CURSOR Way (Program 5)

Interactive Reports: The GET CURSOR Way (Program 5)
ABAP Reports Series · Blog 9 of 15

Interactive Reports: The GET CURSOR Way (Program 5)

Intermediate · 13 min read · Needs Blog 8

1. The problem with SY-LISEL

In Blog 8 we cut the order number out of the line with a fixed offset: sy-lisel+1(10). It worked, but only because we guessed where the number sits in the text. Move one column and the program reads the wrong characters, without any error.

The root issue

sy-lisel gives you text. It does not tell you which field the user clicked. You have to work that out from the character position.

2. GET CURSOR: the solution

GET CURSOR asks ABAP directly: “Which field is the cursor on, and what does it contain?” No offsets, no guessing.

DATA: lv_field TYPE c LENGTH 132,
      lv_value TYPE c LENGTH 50.

AT LINE-SELECTION.
  GET CURSOR FIELD lv_field VALUE lv_value.
  IF sy-subrc = 0.
    WRITE: / 'Field:', lv_field,
           / 'Value:', lv_value.
  ENDIF.

After the statement, lv_field holds the name of the clicked field and lv_value holds what was shown in it. Moving a column has no effect.

sy-subrcMeaning
0The cursor was on a field of the list
4The cursor was not on a field (empty space, separator, line)

This check replaces the CN trick from Blog 8.

3. GET CURSOR variants

StatementReturns
GET CURSOR FIELD f.The name of the field under the cursor
GET CURSOR FIELD f VALUE v.The name and the displayed content
GET CURSOR FIELD f LINE l.The name and the line number of the list
GET CURSOR FIELD f OFFSET o.The name and the cursor’s position inside the field
GET CURSOR LINE l.Only the line number
VALUE is the displayed text

VALUE returns the content as it appears on the list. For an order number that means 4970 without the leading zeros. You still need CONVERSION_EXIT_ALPHA_INPUT before searching the database, as in Blog 8.

4. The field name format

The name returned is the name of the ABAP variable you wrote, in capitals. If the list was written like this:

LOOP AT gt_orders INTO DATA(ls_order).
  WRITE: / ls_order-vbeln, ls_order-ernam.
ENDLOOP.

then the name is the work area, a hyphen, and the component:

Written asName in lv_field
WRITE ls_order-vbelnLS_ORDER-VBELN
WRITE ls_order-ernamLS_ORDER-ERNAM
WRITE lv_totalLV_TOTAL
  • The name belongs to the variable, not to the column heading.
  • If you write the same column through a different variable, the name changes. Keep one work area for the list.
  • Compare in capitals: 'LS_ORDER-VBELN', not 'ls_order-vbeln'.

5. Program 5: full code

Same sales order list as Program 4, but now two fields are clickable: the order number shows its items, and the user name shows how many orders that user created.

REPORT zlist_getcursor.

TYPES: BEGIN OF ty_order,
         vbeln TYPE vbak-vbeln,
         erdat TYPE vbak-erdat,
         ernam TYPE vbak-ernam,
         netwr TYPE vbak-netwr,
         waerk TYPE vbak-waerk,
       END OF ty_order.

DATA: gt_orders TYPE STANDARD TABLE OF ty_order WITH DEFAULT KEY,
      gs_order  TYPE ty_order,
      gv_erdat  TYPE vbak-erdat.

SELECT-OPTIONS s_erdat FOR gv_erdat.
PARAMETERS     p_max   TYPE i DEFAULT 50.

INITIALIZATION.
  s_erdat-sign   = 'I'.
  s_erdat-option = 'BT'.
  s_erdat-low    = sy-datum - 30.
  s_erdat-high   = sy-datum.
  APPEND s_erdat.

*---------------------------------------------------------------------*
* Basic list
*---------------------------------------------------------------------*
START-OF-SELECTION.
  SELECT vbeln, erdat, ernam, netwr, waerk
    FROM vbak
    WHERE erdat IN @s_erdat
    ORDER BY erdat DESCENDING, vbeln
    INTO TABLE @gt_orders
    UP TO @p_max ROWS.

  IF sy-subrc <> 0.
    MESSAGE 'No sales orders found for your selection'
            TYPE 'S' DISPLAY LIKE 'E'.
    RETURN.
  ENDIF.

  PERFORM write_basic_list.

*---------------------------------------------------------------------*
* Click handler
*---------------------------------------------------------------------*
AT LINE-SELECTION.
  PERFORM handle_click.

*---------------------------------------------------------------------*
FORM write_basic_list.
  FORMAT COLOR col_heading.
  WRITE: /1 'Sales Doc', 14 'Created on', 27 'Created by',
         42 'Net value', 62 'Curr.'.
  FORMAT COLOR OFF.
  ULINE.

  LOOP AT gt_orders INTO gs_order.
    WRITE: /1  gs_order-vbeln COLOR col_key HOTSPOT ON,
           14 gs_order-erdat,
           27 gs_order-ernam HOTSPOT ON,
           42 gs_order-netwr CURRENCY gs_order-waerk,
           62 gs_order-waerk.
  ENDLOOP.
ENDFORM.

*---------------------------------------------------------------------*
FORM handle_click.
  DATA: lv_field TYPE c LENGTH 132,
        lv_value TYPE c LENGTH 50.

  GET CURSOR FIELD lv_field VALUE lv_value.
  IF sy-subrc <> 0.
    MESSAGE 'Click on a value in the list' TYPE 'S' DISPLAY LIKE 'E'.
    RETURN.
  ENDIF.

  CONDENSE lv_value.

  CASE lv_field.
    WHEN 'GS_ORDER-VBELN'.
      PERFORM show_items USING lv_value.
    WHEN 'GS_ORDER-ERNAM'.
      PERFORM show_user_info USING lv_value.
    WHEN OTHERS.
      MESSAGE 'Click on an order number or a user name' TYPE 'I'.
  ENDCASE.
ENDFORM.

*---------------------------------------------------------------------*
* Order number clicked: secondary list with the items
*---------------------------------------------------------------------*
FORM show_items USING pv_value TYPE c.
  DATA lv_vbeln TYPE vbak-vbeln.

  " VALUE is the displayed text, so restore the leading zeros
  CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
    EXPORTING input  = pv_value
    IMPORTING output = lv_vbeln.

  SELECT posnr, matnr, kwmeng, netwr, waerk
    FROM vbap
    WHERE vbeln = @lv_vbeln
    ORDER BY posnr
    INTO TABLE @DATA(lt_items).

  WRITE: / 'Items of order', pv_value.
  ULINE.

  IF lt_items IS INITIAL.
    WRITE: / 'This order has no items'.
    RETURN.
  ENDIF.

  LOOP AT lt_items INTO DATA(ls_item).
    WRITE: / ls_item-posnr, ls_item-matnr, ls_item-kwmeng,
             ls_item-netwr CURRENCY ls_item-waerk, ls_item-waerk.
  ENDLOOP.
ENDFORM.

*---------------------------------------------------------------------*
* User name clicked: popup with the number of orders in the list
*---------------------------------------------------------------------*
FORM show_user_info USING pv_user TYPE c.
  DATA lv_msg TYPE string.

  DATA(lv_count) = REDUCE i( INIT n = 0
                           FOR ls IN gt_orders WHERE ( ernam = pv_user )
                           NEXT n = n + 1 ).

  lv_msg = |User { pv_user } created { lv_count } order(s) in this list|.
  MESSAGE lv_msg TYPE 'I'.
ENDFORM.

6. Walkthrough

PartWhat it does
gs_order as a global work areaEvery WRITE uses the same variable, so the field names stay stable: GS_ORDER-VBELN, GS_ORDER-ERNAM.
HOTSPOT ONTurns the pointer into a hand. One click is enough on those fields.
GET CURSOR FIELD ... VALUEReads which field was clicked and what it showed. No offsets.
IF sy-subrc <> 0Handles a click on empty space or a line.
CONDENSE lv_valueRemoves extra blanks around the displayed text.
CASE lv_fieldChooses the action by the field name. This is how one list holds several clickable fields.
WHEN OTHERSTells the user what is clickable when they pick something else.
CONVERSION_EXIT_ALPHA_INPUTRestores the leading zeros of the order number.
REDUCE ... WHERECounts orders of one user in the table without writing a loop.

7. MESSAGE TYPE ‘I’: user feedback

Not every click needs a new list. For a short answer, a message is faster and lighter.

TypeDisplayProgram
I InformationPopup window. The user confirms with Enter.Continues after the popup
S SuccessOne line in the status barContinues at once
S + DISPLAY LIKE 'E'Status bar message with an error iconContinues at once
E ErrorStatus bar, in redStops the current action
  • Use I for a result the user should notice, like the user count.
  • Use S ... DISPLAY LIKE 'E' for a problem that should not interrupt the user with a popup.
Popups and background jobs

A type I popup waits for a person. In a background job there is nobody to confirm it. Blog 14 shows how to write background-safe reports.

8. SY-LISEL vs. GET CURSOR

sy-liselGET CURSOR
What you getThe text of the whole lineThe field name and its value
Depends on layoutYes, fixed offsetsNo
Several clickable fieldsHard, by character positionsEasy, with CASE on the name
Click on empty spaceYou must check the text yourselfsy-subrc = 4
Leading zerosLost, needs ALPHALost, needs ALPHA
Value of a hidden columnNot availableNot available
VerdictFragile, learn to read itPreferred for classical lists
A third option

The statement HIDE stores a value for each list line, even if it is not displayed. It is the most robust way to carry hidden keys in a classical list. You can look it up in the ABAP documentation (F1 in SE38).

9. Try it yourself

  • Move the Created by column to the front. Confirm that clicking still works.
  • Make gs_order-erdat clickable and show all orders from that day in a new list.
  • Use GET CURSOR FIELD ... LINE and show the line number in a message.
  • Rename the work area to ls_row and watch the CASE stop matching. Then fix it.
  • Add a total of the order values for a clicked user to the information popup.

10. Common mistakes

  • Comparing the field name in lowercase. It is always returned in capitals.
  • Writing the list with a different variable than the one in the CASE, so no branch matches.
  • Skipping the sy-subrc check. A click on empty space gives an empty field name.
  • Forgetting the leading zeros. VALUE is the displayed text.
  • No WHEN OTHERS. Clicks on unsupported fields do nothing and confuse the user.
  • Too short a target field for VALUE. The text is cut off.
  • Using a type I message in a background job. The job waits for a click that never comes.
  • Using GET CURSOR with an ALV grid. It is for classical lists only.

Up next: Blog 10

ALV Advanced. Layouts, variants, sorting, filters, custom toolbar buttons and Excel export, the features every production ALV needs.

ABAP Reports: Zero to Hero · Blog 9 of 15
WhatsApp WhatsApp us
Call Now Button