Archivos Mensuales: abril 2010

ALV template

Introducción

Este es mi template para cada vez que tengo que hacer una ALV. Es bastante completo, lo justo para que en el 95% de los casos lo único que tenga que hacer es cambiar la definición de campos y programar la interacción del usuario. Quizás te merezca la pena echarle un vistazo a mi artículo sobre el tratamiento de colores en ALV. A disfrutar.

El código

REPORT z_alv_template.


DATA it_alv TYPE STANDARD TABLE OF ekko.

SELECT * FROM ekko INTO TABLE it_alv
    UP TO 137 ROWS.

PERFORM alv_display.



*       _          _ _           _
*  __ _| |_   ____| |_)___ _ __ | | __ _ _   _
* / _` | | \ / / _` | | __| '_ \| |/ _` | | | |
*| (_| | |\ V / (_| | |__ \ |_) | | (_| | |_| |
* \__,_|_| \_/ \__,_|_|___/ .__/|_|\__,_|\__, |
*           FORM PRINCIPAL|_|            |___/
* necesaria tener definida globalmente IT_ALV con
*               los campos y contenidos a mostrar
* as seen on http://cranf.com
* ascii art made at http://ascii.cranf.net
***********************************************************************
FORM alv_display.

** VARIABLES NECESARIAS                       *no es necesario tocar
**------------------------------------------------------------------
  TYPE-POOLS slis.
  DATA alv_fieldcat TYPE slis_t_fieldcat_alv.
  DATA alv_layout   TYPE slis_layout_alv.
  DATA alv_sort     TYPE slis_t_sortinfo_alv.
  DATA ls_sort      TYPE slis_sortinfo_alv.
  DATA alv_events   TYPE slis_t_event.
  DATA ls_events    TYPE slis_alv_event.
  DATA lsyrepid LIKE sy-repid. lsyrepid = sy-repid.
  CLEAR alv_fieldcat. REFRESH alv_fieldcat.
  CLEAR alv_layout.

** definición de LAYOUT                                 *recomendado
**------------------------------------------------------------------
  alv_layout-colwidth_optimize = 'X'. "optimización de ancho columna
  alv_layout-cell_merge = 'X'.        "fusión de celdas
  alv_layout-no_vline = 'X'.          "sin línea separadora vertical
  alv_layout-zebra = ' '.             "franjas alternas de color


** campo de COLOR DE LÍNEA                                 *opcional
**------------------------------------------------------------------
* alv_layout-info_fieldname = 'COLOR'. "campo it_alv color de línea


** campo de COLOR DE CELDAS                                *opcional
**------------------------------------------------------------------
* alv_layout-coltab_fieldname = 'COLOR'  "campo it_alv color celdas


** campo de SELECCIÓN DE LÍNEA                             *opcional
** el campo puesto aquí no necesita ir en el fieldcat
**------------------------------------------------------------------
* alv_layout-box_fieldname = 'LOEKZ'.


** SORTING                                                 *opcional
** necesario si queremos que cell_merge funcione la primera vez
**------------------------------------------------------------------
*  ls_sort-fieldname = 'EBELN'.
*  ls_sort-up = 'X'. "contrario es ls_sort-down = 'X'
*  APPEND ls_sort TO alv_sort.


** definición de EVENTS                                    *opcional
**------------------------------------------------------------------
*  ls_events-name = 'TOP_OF_PAGE'.
*  ls_events-form = 'ALV_TOP_OF_PAGE'.
*  APPEND ls_events TO alv_events.


** definición de FIELDCAT       *obligatorio si no se usa estructura
**------------------------------------------------------------------
  PERFORM alv_fields USING alv_fieldcat[].

**                                             *llamada a la función
**------------------------------------------------------------------
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
       EXPORTING
            is_layout                = alv_layout
            it_fieldcat              = alv_fieldcat
            it_sort                  = alv_sort
            it_events                = alv_events
            i_callback_program       = lsyrepid
            i_callback_pf_status_set = 'ALV_SET_STATUS'
            i_callback_user_command  = 'ALV_COMMAND'
*           I_STRUCTURE_NAME         = 'TABLADICCIONARIO'
*                   en este caso no usaríamos it_fieldcat
       TABLES
            t_outtab                 = it_alv.
*-------------------------------------------------------------------
ENDFORM.                    "alv_display
***********************************************************************
*       _                _
*  __ _| |_   _____ ___ | | ___  _ __
* / _` | | \ / / __| _ \| |/ _ \| '__|
*| (_| | |\ V / (__ (_) | | (_) | |
* \__,_|_| \_/ \___|___/|_|\___/|_|
DEFINE alv_color.
* MACRO para convertir color humano en código color Cxyz
* uso: alv_color campo 'texto en español'

* en EMPHASIZE o en el campo COLOR usamos char(4)
* con la forma Cxyz, x€[0,7]; y,z€[0,1] / y+z<2
* valores de x:
*            0 COL_BACKGROUND fondo (gris)
*            1 COL_HEADING    azul oscuro
*            2 COL_NORMAL     azul claro
*            3 COL_TOTAL      amarillo
*            4 COL_KEY        azul
*            5 COL_POSITIVE   verde
*            6 COL_NEGATIVE   rojo
*            7 COL_GROUP      naranja
* valores de y: 0 = normal, 1 = intenso
* valores de z: 0 = xy afecta fondo, 1 = x invertido

*          OJO: ls_fieldcat-key = 'X' invalida lo anterior

  &1 = 'C000'. "gris fondo por definición
  find 'azul' in &2 ignoring case.
  if sy-subrc = 0.
    &1+1(1) = '4'.
    find 'claro' in &2 ignoring case.
    if sy-subrc = 0. &1+1(1) = '2'. endif.
    find 'oscuro' in &2 ignoring case.
    if sy-subrc = 0. &1+1(1) = '1'. endif.
  endif.
  find 'amar' in &2 ignoring case.
  if sy-subrc = 0. &1+1(1) = '3'. endif.
  find 'verd' in &2 ignoring case.
  if sy-subrc = 0. &1+1(1) = '5'. endif.
  find 'rojo' in &2 ignoring case.
  if sy-subrc = 0. &1+1(1) = '6'. endif.
  find 'nara' in &2 ignoring case.
  if sy-subrc = 0. &1+1(1) = '7'. endif.
  find 'ntens' in &2 ignoring case.
  if sy-subrc = 0. &1+2(2) = '10'. endif.
  find 'nver' in &2 ignoring case.
  if sy-subrc = 0. &1+2(2) = '01'. endif.
END-OF-DEFINITION.
***********************************************************************
* COLOR para su uso dentro del FORM ALV_FIELDS
DEFINE fld_color.
  alv_color ls_fieldcat-emphasize &1.
END-OF-DEFINITION.
***********************************************************************
* TEXTO para su uso dentro del FORM ALV_FIELDS
DEFINE fld_texto.
  ls_fieldcat-seltext_s   = &1.
  ls_fieldcat-seltext_m   = &1.
  ls_fieldcat-seltext_l   = &1.
END-OF-DEFINITION.
***********************************************************************
*       _        __ _      _     _
*  __ _| |_   __/ _|_) ___| | __| |___
* / _` | | \ / / |_| |/ _ \ |/ _` | __|
*| (_| | |\ V /|  _| |  __/ | (_| |__ \
* \__,_|_| \_/ |_| |_|\___|_|\__,_|___/DEFINICIÓN DE CAMPOS
*
FORM alv_fields USING pfieldcat TYPE slis_t_fieldcat_alv..
  DATA ls_fieldcat  TYPE slis_fieldcat_alv.
  REFRESH pfieldcat.

  CLEAR ls_fieldcat.
  ls_fieldcat-fieldname   = 'EBELN'.
  ls_fieldcat-ref_tabname = 'EKKO'.
  ls_fieldcat-key         = ''.
  ls_fieldcat-icon        = ''.
  ls_fieldcat-checkbox    = ''.
  ls_fieldcat-no_out      = ''.
  fld_color 'amarillo'.
  APPEND ls_fieldcat TO pfieldcat.

** TEMPLATE PARA CAMPOS DE DICCIONARIO
*  CLEAR ls_fieldcat.
*  ls_fieldcat-fieldname   = ''.
*  ls_fieldcat-ref_tabname = ''.
*  ls_fieldcat-key         = ''.
*  ls_fieldcat-no_out      = ''.
*  fld_color ''.
*  APPEND ls_fieldcat TO pfieldcat.

** TEMPLATE PARA TEXTOS S/M/L IGUALES
*  CLEAR ls_fieldcat.
*  ls_fieldcat-fieldname   = ''.
*  ls_fieldcat-key         = ''.
*  ls_fieldcat-icon        = ''.
*  ls_fieldcat-checkbox    = ''.
*  ls_fieldcat-no_out      = ''.
*  fld_texto ''.
*  fld_color ''.
*  APPEND ls_fieldcat TO pfieldcat.

** TEMPLATE PARA TEXTOS S/M/L DISTINTOS
*  CLEAR ls_fieldcat.
*  ls_fieldcat-fieldname   = ''.
*  ls_fieldcat-key         = ''.
*  ls_fieldcat-icon        = ''.
*  ls_fieldcat-checkbox    = ''.
*  ls_fieldcat-no_out      = ''.
*  ls_fieldcat-seltext_s   = ''.
*  ls_fieldcat-seltext_m   = ''.
*  ls_fieldcat-seltext_l   = ''.
*  fld_color ''.
*  APPEND ls_fieldcat TO pfieldcat.

ENDFORM.                    "alv_fields
*
* FORMS DE LLAMADA DINÁMICA DESDE LA ALV
***********************************************************************
*       _                _       _        _
*  __ _| |_   _____  ___| |_ ___| |_ __ _| |_ _   _ ___
* / _` | | \ / / __|/ _ \ __| __| __| _` | __| | | | __|
*| (_| | |\ V /\__ \  __/ |_\__ \ |_ (_| | |_| |_| |__ \
* \__,_|_| \_/ |___/\___|\__|___/\__|__,_|\__|\__,_|___/
*  DEFINICIÓN DE STATUS BAR
FORM alv_set_status USING prt_extab TYPE slis_t_extab.
* barra de status de referencia
**--------------------------------------------------------------------
  SET PF-STATUS 'STANDARD_FULLSCREEN' OF PROGRAM 'SAPLKKBL'.
ENDFORM.                    "alv_set_status
***********************************************************************
*       _       _                     __
*  __ _| |_   __ |_ ___  _ __   ___  / _|_ __   __ _  __ _  ___
* / _` | | \ / / __| _ \| '_ \ / _ \| |_| '_ \ / _` |/ _` |/ _ \
*| (_| | |\ V /| |_ (_) | |_) | (_) |  _| |_) | (_| | (_| |  __/
* \__,_|_| \_/  \__|___/| .__/ \___/|_| | .__/ \__,_|\__, |\___|
* CABECERA DE LISTA     |_|             |_|          |___/
FORM alv_top_of_page.

  DATA: lls_list TYPE slis_listheader.
  DATA: lalv_list TYPE slis_t_listheader.

**definición de cada línea de la cabecera
**el typ puede tener valores: H = header, S = selection, A = action
**--------------------------------------------------------------------
  lls_list-typ = 'H'.
  lls_list-info = 'TÍTULO DEL LISTADO'.
  APPEND lls_list TO lalv_list.

*---------------------------------------------------------------------
  CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE'
    EXPORTING
      it_list_commentary = lalv_list.
*---------------------------------------------------------------------
ENDFORM.                    "alv_top_of_page
***********************************************************************
*       _                                                    _
*  __ _| |_   _____ ___  _ __ ___  _ __ ___   __ _ _ __   __| |
* / _` | | \ / / __| _ \| '_ ` _ \| '_ ` _ \ / _` | '_ \ / _` |
*| (_| | |\ V / (__ (_) | | | | | | | | | | | (_| | | | | (_| |
* \__,_|_| \_/ \___|___/|_| |_| |_|_| |_| |_|\__,_|_| |_|\__,_|
*  RESPUESTA A COMANDOS
FORM alv_command USING
    r_ucomm LIKE sy-ucomm
    rs_selfield TYPE slis_selfield.


** actualiza celdas editadas en modo edición
**--------------------------------------------------------------------
*  DATA p_ref1 TYPE REF TO cl_gui_alv_grid.
*  CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
*    IMPORTING
*      e_grid = p_ref1.
*  CALL METHOD p_ref1->check_changed_data.


** toma de decisiones en función de UCOMM
**--------------------------------------------------------------------
  CASE r_ucomm.
********* doble click [rs_selfield-tabindex = línea seleccionada]
    WHEN '&IC1'.
********* otros comandos
    WHEN OTHERS.
  ENDCASE.


** cambiamos el field catalog si es necesario hacerlo sobre la marcha
**--------------------------------------------------------------------
*  DATA lfieldcat TYPE slis_t_fieldcat_alv.
*  CALL FUNCTION 'REUSE_ALV_GRID_LAYOUT_INFO_GET'
*    IMPORTING
*      et_fieldcat = lfieldcat[].
*
** podemos escoger el form original o utilizar otro que nos convenga
*  PERFORM alv_fields USING lfieldcat[].
*
*  CALL FUNCTION 'REUSE_ALV_GRID_LAYOUT_INFO_SET'
*    EXPORTING
*      it_fieldcat = lfieldcat[].

* conservamos la posición del click
  rs_selfield-row_stable = 'X'.
  rs_selfield-col_stable = 'X'.

* esencial para que redibuje: NUNCA se debe rellamar a la función
**--------------------------------------------------------------------
  rs_selfield-refresh = 'X'.

ENDFORM.                    "alv_command
***********************************************************************
Publicado en: SAP Sin comentarios ▼

Reloj de avance para tablas internas

Introducción

A veces es frustrante, tanto para el usuario como para nosotros mismos, no saber cuándo un programa acabará de ejecutarse. Para ello he creado una minilibrería con tres macros, muy sencilla de utilizar, que, convenientemente utilizada en cualquier LOOP, nos mostrará:

  1. lo que está haciendo (que se lo especificaremos nosotros como texto opcional)
  2. el porcentaje de avance de recorrido de la tabla
  3. el tiempo total estimado
  4. el tiempo faltante para acabar
  5. la hora de finalización
  6. línea actual y total de líneas de la tabla interna

Las macros

  • vc_clocktimer texto: Se sitúa dentro del LOOP que nos interesa especificándole un texto corto descriptivo. No hace falta nada más ya que el cálculo se hace a partir de la variable de sistema sy-tabix. Fuera de un LOOP no funcionará.
  • vc_clockreset tabla: se sitúa antes del LOOP para poner el contador de tiempo a cero y analizar la tabla interna en la que vamos a meter el reloj.

  • vc_seconds2hms: de uso interno, convierte segundos a formato HH:MM:SS indicando “+100h” en caso de que el tiempo resultante sea superior a 100 horas. También es utilizable de manera independiente

Observaciones

Al final del código de ejemplo que pongo más abajo, en negrita, se puede ver lo sencilla que es su inserción. El gráfico superior, que muestra el reloj en funcionamiento, corresponde a este mismo programa.

Es importante señalar que asume que la resolución temporal de la sentencia GET RUN TIME está afinada al microsegundo; la opción por defecto de los sistemas SAP. De otro modo dará resultados absurdos.

Más importante aún es avisar de que en conexiones lentas la actualización del reloj en el SAPgui puede afectar negativamente al rendimiento. En ese caso convendrá llamar a la macro vc_clocktimer sólo cada n pasos.

El código

REPORT  z_percentage_clock.
* _  __        _            _
*(_)/ /    ___| | ___   ___| | __
*  / /    / __| |/ _ \ / __| |/ /
* / /_   | (__| | (_) | (__|   <
*/_/(_)   \___|_|\___/ \___|_|\_\
* as seen in http://cranf.com
* ASCII art made using http://ascii.cranf.net
*
***********************************************************************
DATA vc_clocktlines TYPE i.
DATA vc_time0 TYPE f.
***********************************************************************
DEFINE vc_seconds2hms.
  perform vc_seconds2hms using &1 changing &2.
END-OF-DEFINITION.
*
FORM vc_seconds2hms USING pseconds CHANGING phms.
  DATA vc_segundos TYPE uzeit.
  DATA vc_segundosi TYPE i.
  vc_segundosi = pseconds.
  IF vc_segundosi < 360000.
    vc_segundos = vc_segundosi.
    WRITE vc_segundos TO phms.
  ELSE.
    phms = '+100h'.
  ENDIF.
ENDFORM.                    "vc_seconds2hms
***********************************************************************
DEFINE vc_clockreset.
  vc_clocktlines = 0.
  describe table &1 lines vc_clocktlines.
  get run time field vc_time0.
END-OF-DEFINITION.
***********************************************************************
DEFINE vc_clocktimer.
  perform vc_clocktimer using &1.
END-OF-DEFINITION.
*
FORM vc_clocktimer USING vc_ptexto.

  DATA vc_porcentaje TYPE i.
  DATA vc_porcentajet(4).
  DATA vc_pend TYPE f.
  DATA vc_tabixt(8).
  DATA vc_tfillt(8).
  DATA vc_linest(20).

  DATA vc_time TYPE f.
  DATA vc_timetotal TYPE f.
  DATA vc_timetotalt(8).
  DATA vc_timefalta TYPE f.
  DATA vc_timefaltat(8).
  DATA vc_timefin TYPE uzeit.
  DATA vc_timefint(8).
  DATA vc_mensaje(100).

  CHECK vc_clocktlines > 0.
  CHECK sy-tabix > 0.

  GET RUN TIME FIELD vc_time.

  vc_pend = ( vc_time - vc_time0 ) / sy-tabix .
  vc_timetotal = vc_pend * vc_clocktlines / 1000000.
  vc_timefalta = vc_pend * ( vc_clocktlines - sy-tabix ) / 1000000 + 1.
  vc_porcentaje = sy-tabix * 100 / vc_clocktlines.

  WRITE vc_porcentaje TO vc_porcentajet.
  CONCATENATE vc_porcentajet '%' INTO vc_porcentajet.
  CONDENSE vc_porcentajet NO-GAPS.
  WRITE sy-tabix TO vc_tabixt.
  WRITE vc_clocktlines TO vc_tfillt.
  CONCATENATE '[' vc_tabixt '/' vc_tfillt ']' INTO vc_linest.
  CONDENSE vc_linest NO-GAPS.
  vc_seconds2hms vc_timetotal vc_timetotalt.
  vc_seconds2hms vc_timefalta vc_timefaltat.
  vc_timefin = sy-uzeit + vc_timefalta.
  WRITE vc_timefin TO vc_timefint.

  CONCATENATE
    vc_ptexto
    vc_porcentajet
    'Total'
    vc_timetotalt
    'Resta'
    vc_timefaltat
    'Final'
    vc_timefint
    vc_linest
  INTO vc_mensaje SEPARATED BY space.
  CONDENSE vc_mensaje.

  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
       EXPORTING
            percentage = vc_porcentaje
            text       = vc_mensaje.
ENDFORM.                    "vc_clocktimer
***********************************************************************

*       _                      _
*  ___ (_) ___ _ __ ___  _ __ | | ___
* / _ \| |/ _ \ '_ ` _ \| '_ \| |/ _ \
*|  __/| |  __/ | | | | | |_) | | (_) |
* \___|/ |\___|_| |_| |_| .__/|_|\___/
*    |__/               |_|
*______________________________________________________________________

DATA it_dd02l TYPE TABLE OF dd02l WITH HEADER LINE.

START-OF-SELECTION.

  SELECT *
  FROM dd02l
  INTO TABLE it_dd02l
  UP TO 10 ROWS.

* pone a cero el reloj
  vc_clockreset it_dd02l.

* recorremos la tabla
  LOOP AT it_dd02l.

*   dibuja el reloj con el texto elegido
    vc_clocktimer 'Proceso'.

*   retraso temporal de un segundo por ciclo
    CALL FUNCTION 'RZL_SLEEP'
         EXPORTING
              seconds        = 1
         EXCEPTIONS
              argument_error = 1
              OTHERS         = 2.
  ENDLOOP.
Publicado en: SAP Sin comentarios ▼
[c] Alberto Viñuela Miranda / Cranfcom 2013-2014

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.