Interactive Reports: The GET CURSOR Way (Program 5)
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.
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-subrc | Meaning |
|---|---|
0 | The cursor was on a field of the list |
4 | The cursor was not on a field (empty space, separator, line) |
This check replaces the CN trick from Blog 8.
3. GET CURSOR variants
| Statement | Returns |
|---|---|
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 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 as | Name in lv_field |
|---|---|
WRITE ls_order-vbeln | LS_ORDER-VBELN |
WRITE ls_order-ernam | LS_ORDER-ERNAM |
WRITE lv_total | LV_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
| Part | What it does |
|---|---|
gs_order as a global work area | Every WRITE uses the same variable, so the field names stay stable: GS_ORDER-VBELN, GS_ORDER-ERNAM. |
HOTSPOT ON | Turns the pointer into a hand. One click is enough on those fields. |
GET CURSOR FIELD ... VALUE | Reads which field was clicked and what it showed. No offsets. |
IF sy-subrc <> 0 | Handles a click on empty space or a line. |
CONDENSE lv_value | Removes extra blanks around the displayed text. |
CASE lv_field | Chooses the action by the field name. This is how one list holds several clickable fields. |
WHEN OTHERS | Tells the user what is clickable when they pick something else. |
CONVERSION_EXIT_ALPHA_INPUT | Restores the leading zeros of the order number. |
REDUCE ... WHERE | Counts 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.
| Type | Display | Program |
|---|---|---|
I Information | Popup window. The user confirms with Enter. | Continues after the popup |
S Success | One line in the status bar | Continues at once |
S + DISPLAY LIKE 'E' | Status bar message with an error icon | Continues at once |
E Error | Status bar, in red | Stops the current action |
- Use
Ifor 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.
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-lisel | GET CURSOR | |
|---|---|---|
| What you get | The text of the whole line | The field name and its value |
| Depends on layout | Yes, fixed offsets | No |
| Several clickable fields | Hard, by character positions | Easy, with CASE on the name |
| Click on empty space | You must check the text yourself | sy-subrc = 4 |
| Leading zeros | Lost, needs ALPHA | Lost, needs ALPHA |
| Value of a hidden column | Not available | Not available |
| Verdict | Fragile, learn to read it | Preferred for classical lists |
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-erdatclickable and show all orders from that day in a new list. - Use
GET CURSOR FIELD ... LINEand show the line number in a message. - Rename the work area to
ls_rowand watch theCASEstop 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-subrccheck. A click on empty space gives an empty field name. - Forgetting the leading zeros.
VALUEis 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
Imessage in a background job. The job waits for a click that never comes. - Using
GET CURSORwith 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.
WhatsApp us