7 de octubre de 2017

Multiselección en un Grid

Esta la saque de http://www.tek-tips.com/faqs.cfm?fid=433. Aquí la pongo traducida:

¿Cómo agregar la funcionalidad de multiselección en un Grid?
faq184-433
Posted: 29 Jan 01 (Edited 30 Sep 06)

Si desean agregar la funcionalidad multiselección a un Grid para que emule la del explorador de Windows, intenten lo siguiente:

Subclaseen un Grid en una librería de clases y agregen 4 nuevas propiedades:

  • lMultiSelect con valor .F.
  • nActiveRow con valor 0 (cero)
  • nLastRow con valor 0 (cero)
  • nRecs2Change con valor 0 (cero)

Y un nuevo método:

  • mSelectRecords()

Asegurense de que RecordSource del Grid no este indexado, lo crean con una sentencia SELECT-SQL. El RecordSource necesita un campo logico adicional, "Selected".

En el evento AfterRowColChange() pongan:

THIS.mSelectRecords()

En el método mSelectRecords() del Grid pongan:

LOCAL lcSelected,lcRecordSource

#DEFINE VK_lSHIFT 0x10 && Relocate to a header file
#DEFINE VK_lCONTROL 0x11 && Relocate to a header file

DECLARE INTEGER GetKeyState IN WIN32API INTEGER && Relocate to where WinAPI calls are declared

WITH THIS
  .nActiveRow = .ACTIVEROW && Assign value to class property
  lcSelected = .RECORDSOURCE + [.selected] && Assign value to local variable
  lcRecordSource = .RECORDSOURCE && Assign value to local variable

  DO CASE
    CASE GetKeyState(VK_lSHIFT)    < 0    ;
        OR GetKeyState(VK_lSHIFT) > 1 && Check for shift key press

      DO CASE
        CASE .nLastRow > .nActiveRow && Last recd below current recd in grid

          .nRecs2Change = .nLastRow - .nActiveRow && Calculate no of recds to change

          REPLACE (lcSelected) WITH .T. IN (lcRecordSource) && Replace current recd
          FOR i = 1 TO .nRecs2Change
            REPLACE (lcSelected) WITH .T. IN (lcRecordSource)
            SKIP IN (lcRecordSource)
          ENDF

        CASE .nLastRow < .nActiveRow && Last recd above current recd in grid

          .nRecs2Change = .nActiveRow - .nLastRow && Calculate no of recds to change
          REPLACE  (lcSelected) WITH .T. IN (lcRecordSource) && Replace current recd

          GO .nLastRow IN (lcRecordSource) && Goto the last recd
          FOR i = 1 TO .nRecs2Change
            REPLACE (lcSelected) WITH .T. IN (lcRecordSource)
            SKIP IN (lcRecordSource)
          ENDF
      ENDC

      .lMultiSelect = .T.

    CASE GetKeyState(VK_lCONTROL) < 0 ;
        OR GetKeyState(VK_lCONTROL) > 1 && Check for control key press

      REPLACE (lcSelected) WITH .T. IN (lcRecordSource)

      .lMultiSelect = .T.

    OTHERWISE && Neither shift or ctrl pressed
      DO CASE
        CASE .lMultiSelect
          REPLACE (lcSelected) WITH .F. ;
            ALL IN (lcRecordSource) && Update all recds
        CASE .nLastRow    # 0
          TRY
            GO .nLastRow IN (lcRecordSource)
          CATCH
            GO BOTTOM IN (lcRecordSource)
          ENDTRY
          REPLACE (lcSelected) WITH .F. IN (lcRecordSource)
      ENDCASE

      GO .nActiveRow IN (lcRecordSource) && Change new value
      REPLACE (lcSelected) WITH .T. IN (lcRecordSource)

      .lMultiSelect = .F.
  ENDC

  IF RECCOUNT(lcRecordSource) > 0
    DO CASE && Set colours according to OS
      CASE UPPER(OS(1)) = [WINDOWS 5.00] && Win 2K
        .SETALL([DynamicBackColor], ;
          "IIF(&lcSelected, RGB(10,36,106), RGB(255,255,255))", ;
          [Column])
      CASE UPPER(OS(1)) = [WINDOWS 5.01] && Win XP
        .SETALL([DynamicBackColor], ;
          "IIF(&lcSelected, RGB(49,106,197), RGB(255,255,255))", ;
          [Column])
    ENDCASE

    .SETALL([DynamicForeColor], ; && All OS
      "IIF(&lcSelected, RGB(255,255,255), RGB(0,0,0))", ;
      [Column])

    .nLastRow = .nActiveRow && Mark current row for next time through
  ENDIF
ENDWITH

Seran seleccionados solos registros que se cliqueen con Mayusculas o Control. Usando los cursores direccionales no seleccionara registros.

Programaticamente pueden determinar si hay selecciones multiples de registros con:

IF THISFORM.grid1.lMultiSelect
  *!* Code
ENDIF

Otra solucion mas simple es agregar un campo numerico al cursor que esta en el RecordSource del Grid. Por ejemplo mselec n(5).

En el Init del Form poner:

THISFORMSET.frm_enviaryrecibir.grd_recibidos.SETALL("dynamicbackcolor", ;
  "IIF(mselec = 1,RGB(49,106,197), RGB(255,255,255))", "Column")
THISFORMSET.frm_enviaryrecibir.grd_recibidos.SETALL("dynamicforecolor", ;
  "IIF(mselec = 1,RGB(255,255,255), RGB(0,0,0))", "Column")

Y en el Click del Grid:

LOCAL lcSelected,lcRecordSource

#DEFINE VK_lSHIFT 0x10 && Relocate to a header file
#DEFINE VK_lCONTROL 0x11 && Relocate to a header file

DECLARE INTEGER GetKeyState IN WIN32API INTEGER && Relocate to where WinAPI calls are declared
DO CASE
  CASE GetKeyState(VK_lSHIFT) < 0 OR GetKeyState(VK_lSHIFT) > 1 && Check for shift key press
    IF mselec = 0
      REPLACE mselec WITH 1
    ELSE
      REPLACE mselec WITH 0
    ENDIF

  CASE GetKeyState(VK_lCONTROL) < 0 OR GetKeyState(VK_lCONTROL) > 1 && Check for control key press
    IF mselec = 0
      REPLACE mselec WITH 1
    ELSE
      REPLACE mselec WITH 0
    ENDIF
ENDCASE

con esto cada vez que hagan Click con Mayúscula o Control presionado van a seleccionar los registros y el Grid los pinta.

Para poder hacer algo con la selección hacen:

SELEC MICURSOR
SCAN FOR mselec = 1
  *! mi codigo para la seleccion
ENDSCAN

Suerte!!!!

Carlos Caremi

1 comentario :

  1. Yo solo agrego una columna "Marca" de tipo Logica, asocio el Grid a un cursor y luego solo verifico el campo Marca para ver cuales eligio el usuario y cuales no. Aunque tu ejemplo parece interesante. :)

    ResponderEliminar

Los comentarios son moderados, por lo que pueden demorar varias horas para su publicación.