Listbox de selección sencilla y múltiple

Bien, hasta ahora sólo hemos hablado de list boxes de selección sencilla. En estos list boxes sólo se puede seleccionar un ítem (o ninguno), y cada nueva selección anula a la anterior.

Pero también podemos crear list boxes de selección múltiple, en los que será posible seleccionar rangos de ítems, o varios ítems, aunque no estén seguidos.

Para ello, lo primero será crear el list box con el estilo LBS_MULTIPLESEL o el estilo LBS_EXTENDEDSEL.

Ambos estilos definen listas de selección múltiple. La diferencia está en el modo en que se seleccionan los ítems.

En un list box con el estilo LBS_MULTIPLESEL la selección se hace de manera individual, cada vez que se pulsa sobre un ítem no seleccionado, pasa a estado seleccionado, y viceversa.

En un list box con el estilo LBS_EXTENDEDSEL, las selecciones se comportan de la misma forma que en un list box de selección sencilla. Pero mediante las teclas de mayúculas y de control podemos hacer selecciones múltiples. La tecla de mayúsculas nos permite seleccionar rangos. El último ítem seleccionado se comporta como un "ancla", de modo que si pulsamos la tecla de mayusculas y pulsamos con el ratón sobre otro ítem se seleccionarán todos los ítems entre en "ancla" y el actual.

Por otra parte, la tecla de control permite usar el list box del mismo modo que si tuviese el estilo LBS_MULTIPLESEL. Con la tecla de control pulsada, si pulsamos sobre el ratón en un ítem seleccinado, se deseleccionará, y viceversa.

Selecciones

Disponemos de varios mensajes para tratar la selección de ítems en list boxes de selección múltiple.

El mensaje LB_GETSELCOUNT nos sirve para obtener el número de ítems seleccionados actualmente en un list box:

   int nSeleccionados;
...
   nSeleccionados = SendMessage(hlista, LB_GETSELCOUNT, 0, 0);

Mediante el mensaje LB_GETSELITEMS podemos obtener una lista de los índices de los ítems seleccionados. Para ello indicaremos en el parámetro lParam un puntero a un array de enteros, en los que recibiremos la lista de índices, y en wParam el número máximo de ítems que podemos recuperar:

   int nSeleccionados;
   int *seleccionado;
...
   nSeleccionados = SendMessage(hlista, LB_GETSELCOUNT, 0, 0);
   /* Obtener memoria para nSeleccionados índices */
   seleccionado = (int *)malloc(nSeleccionados*sizeof(int));
   /* Obtener la lista */
   SendMessage(hlista, LB_GETSELITEMS,
      (WPARAM)nSeleccionados, (LPARAM)seleccionado);
   /* Tratamiento */
   for(i = nSeleccionados-1; i >= 0; i--) {
      SendMessage(hlista, LB_GETTEXT, (WPARAM)seleccionado[i], (LPARAM)cad);
   }
   /* Liberar buffer */
   free(seleccionado);

Otra alternativa para averiguar qué ítems están seleccionados consiste en enviar un mensaje LB_GETSEL a cada uno de los ítems. Este mensaje nos devuelve un valor distinto de cero si el ítem está seleccionado, y cero si no lo está. En el parámetro wParam indicaremos el índice del ítem:

   int n, i;
   char cad[64];
...
   n = SendMessage(hlista, LB_GETCOUNT, 0, 0);
   for(i = 0; i < n; i++) {
      if(SendMessage(hlista, LB_GETSEL, (WPARAM)i, 0)) {
         SendMessage(hlista, LB_GETTEXT, (WPARAM)i, (LPARAM)cad);
         MessageBox(hwnd, cad, "Ítem seleccionado", MB_OK);
      }
   }

Finalmente, el mensaje LB_SETSEL nos permite seleccionar o deselecionar un ítem determinado. En el parámetro lParam indicaremos en índice del ítem, en el parámetro wParam especificaremos mediante el valor TRUE que queremos seleccionar el ítem, y mediante FALSE que queremos deselecionarlo:

   int n, i;
   char cad[64];
...
   /* Seleccionar ítems de posiciones pares (con índice impar) */
   n = SendMessage(hlista1, LB_GETCOUNT, 0, 0);
   for(i = 0; i < n; i++) {
      SendMessage(hlista1, LB_SETSEL, (WPARAM)i%2, (LPARAM)i);
   }

También podemos seleccionar rangos de ítems mediante el mensaje LB_SELITEMRANGE. En este caso, en el parámetro wParam también indicaremos el tipo de selección, TRUE para seleccionar y FALSE para deselecionar. En el parámetro lParam indicaremos el rango, en la palabra de menor peso el primer ítem y en la de mayor peso, el último. Para crear un LPARAM usaremos la macro MAKELPARAM:

   int n;
...
   n = SendMessage(hlista1, LB_GETCOUNT, 0, 0);
   SendMessage(hlista1, LB_SELITEMRANGE, (WPARAM)TRUE, MAKELPARAM(0, n));

El mensaje LB_SELITEMRANGEEX es similar, aunque en el parámetro wParam se indica el primer ítem y en el parámetro lParam el último. Si el índice del primero es menor que el del segundo, se seleccionará el rango. Si el mayor es el segundo, el rango se deseleccionará.

Mensajes especiales para list box de selección extendida

Existen ciertos mensajes para manipular el ítem ancla y el ítem actual (caret).

El mensaje LB_GETANCHORINDEX nos permite obtener el ítem ancla, y el mensaje LB_GETCARETINDEX, el ítem actual. En ninguno de los dos mensajes se necesitan parámetros:

   int i;
   char cad[64];
...
   case CM_ANCLA:
     i = SendMessage(hlista2, LB_GETANCHORINDEX, 0, 0);
     SendMessage(hlista2, LB_GETTEXT, (WPARAM)i, (LPARAM)cad);
     MessageBox(hwnd, cad, "Ítem ancla", MB_OK);
     break;
   case CM_CARET:
     i = SendMessage(hlista2, LB_GETCARETINDEX, 0, 0);
     SendMessage(hlista2, LB_GETTEXT, (WPARAM)i, (LPARAM)cad);
     MessageBox(hwnd, cad, "Ítem caret", MB_OK);
     break;
...

De forma simétrica, podemos asignar los ítems ancla y actual mediante los mensajes LB_SETANCHORINDEX y LB_SETCARETINDEX, respectivamente. En ambos casos indicaremos en el parámetro wParam el valor del íncide en cuestión, (aunque ignoro qué utilidad puede tener esto):

   int n;
...
   n = SendMessage(hlista2, LB_GETCOUNT, 0, 0);
   SendMessage(hlista2, LB_SETANCHORINDEX, 0, 0);
   SendMessage(hlista2, LB_SETCARETINDEX, (WPARAM)n, 0);

Ejemplo 60


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 60 win060.zip 2007-03-15 3801 bytes 110