El dato del ítem

Ya sabemos que cada ítem tiene asociado un índice y una cadena. Pero también tiene asociado un dato entero de 32 bits: el ítem data, o dato de ítem.

A cada ítem le podemos asignar un valor entero mediante el mensaje CB_SETITEMDATA, y recuperarlo mediante CB_GETITEMDATA.

Podemos aprovechar que el valor de retorno del mensaje CB_ADDSTRING es el índice del ítem insertado, y usar ese valor en el mensaje CB_SETITEMDATA, para asignar el valor del índice en el array:

void IniciarLista(HWND hctrl)
{
   char* mes[] = {"Enero", "Febrero", "Marzo", "Abril", "Mayo",
      "Junio", "Julio", "Agosto", "Septiembre", "Octubre",
      "Noviembre", "Diciembre"};
   int i;
   int actual;
   
   for(i = 0; i < 12; i++) {
      actual = SendMessage(hctrl, CB_ADDSTRING, 0, (LPARAM)mes[i]);
      SendMessage}(hctrl, CB_SETITEMDATA, (WPARAM)actual, i);
   }

Ya veremos que el dato de ítem tiene otras utilidades, pero en muchos casos nos proporciona una forma útil de almacenar un dato relativo a un ítem. Al tratarse de un entero de 32 bits también puede contener punteros.

Interfaces de usuario

Existen dos comportamientos diferentes de los combo boxes con listas desplegables (con el estilo CBS_DROPDOWN o CBS_DROPDOWNLIST), con respecto al teclado. Cada uno de estos comportamientos viene definido por un interfaz.

En el interfaz por defecto, la tecla F4 despliega u oculta la lista desplegable, y las teclas de flecha arriba y abajo nos permiten desplazarnos a través de las distintas opciones.

En el interfaz extendido la tecla F4 no tiene ninguna función, y la lista se despliega tan pronto como se pulsa una de las teclas de flecha arriba o abajo.

Las flechas funcionan tanto si la lista está desplegada como si no.

Para cambiar el interfaz de un control combo box se usa el mensaje CB_SETEXTENDEDUI, si se usa el valor FALSE en el parámetro wParam, se activa el interfaz por defecto, y con el valor TRUE se activa el interfaz extendido.

Mediante el mensaje CB_GETEXTENDEDUI se puede obtener el valor actual del interfaz para un control combo box determinado. Este mensaje no tiene parámetros, y el valor de retorno indica el interfaz asociado al control. TRUE si es el extendido y FALSE si es el interfaz por defecto.

Funciones para ficheros y directorios

Como vimos con los list boxes, en los combo boxes también es posible iniciar la lista usando los nombres de ficheros de una unidad de disco o un directorio.

La función DlgDirListComboBox nos permite iniciar el contenido de una lista asociada a un combo box a partir de los ficheros, carpetas, unidades de disco, etc.

Esta función necesita cinco parámetros. El primero es un manipulador de la ventana o diálogo que contiene el combo box que vamos a inicializar. El segundo es un puntero a una cadena con el camino del directorio a mostrar. El tercer parámetro es el identificador del combo box. El cuarto el identificador de un control estático, que se usa para mostrar el camino actualmente mostrado en el combo box. El último parámetro nos permite seleccionar el tipo de entradas que se mostrarán.

Mediante este último parámetro podemos restringir el tipo de entradas, impidiendo o permitiendo que se muestren directorios o unidades de almacenamiento, o limitando los atributos de los ficheros y directorios a mostrar.

Ya hemos dicho que se necesita un control estático.

   HWND hestatico;
...
           hestatico = CreateWindowEx(
              0,
              "STATIC",        /* Nombre de la clase */
              "",              /* Texto del título, no tiene */
              WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, /* Estilo */ 
              9, 4,            /* Posición */
              344, 18,         /* Tamaño */
              hwnd,            /* Ventana padre */
              (HMENU)ID_TITULO,/* Identificador del control */
              hInstance,       /* Instancia */
              NULL);           /* Sin datos de creación de ventana */ 
           SendMessage(hestatico, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));

Por supuesto, podemos usar los comodines '*' y '?' para los nombres de fichero:

...
   IniciarCombo(hwnd, "*.c");
...

void IniciarCombo(HWND hwnd, char* p)
{
   char path[512];
   
   strcpy(path, p);
   
   DlgDirListComboBox(
    hwnd,           /* manipulador de cuadro de diálogo con list box  */
    path,           /* puntero a cadena de camino o nombre de fichero */
    ID_COMBO,       /* identificador de list box                      */
    ID_TITULO,      /* identificador de control estático              */
    DDL_DIRECTORY | DDL_DRIVES /* atributos de ficheros a mostrar     */
   );   
}

Por otra parte, la función DlgDirSelectComboBoxEx nos permite leer la selección actual de un combo box inicializado mediante la función DlgDirListComboBox. Si el valor de retorno de esta función es distinto de cero, la selección actual es un directorio o unidad de almacenamiento, por lo que será posible hacer un cambio de directorio. Si el valor de retorno es cero, se trata de un fichero.

Aprovecharemos esto para navegar a lo largo de los discos de nuestro ordenador, para lo que responderemos al mensaje de notificación CBN_DBLCLK, cambiando a la nueva ubicación o mostrando el nombre del fichero seleccionado:

        case WM_COMMAND:
           switch(LOWORD(wParam)) {
              case ID_COMBO:
                 switch(HIWORD(wParam)) {
                   case CBN_CLOSEUP:
                       if(DlgDirSelectComboBoxEx(hwnd, cad, 512, ID_COMBO)) {
                         strcat(cad, "*.c");
                         IniciarCombo(hwnd, cad);
                      } else
                         {MessageBox(hwnd, cad, "Fichero seleccionado", MB_OK);
                      break;
...

También existe un mensaje relacionado con este tema.

El mensaje CB_DIR tiene un uso equivalente a la función DlgDirComboBox. En el parámetro wParam se indican los atributos de los ficheros a mostrar, así como si se deben mostrar directorios y unidades de almacenamiento. En el parámetro lParam se suministra el nombre de fichero, que puede tener comodines) o el camino de los ficheros a insertar.

Por ejemplo, podemos añadir los ficheros de cabecera al contenido del combo box, de modo que se muestren los ficheros fuente en c y los de cabecera:

void IniciarLista(HWND hwnd, char* p)
{
   char path[512];
   
   strcpy(path, p);
   
   DlgDirComboBox(hwnd, path, ID_LISTA, ID_TITULO, 
      DDL_DIRECTORY | DDL_DRIVES);

   strcpy(path, "*.h");
   SendMessage(GetDlgItem(hwnd, ID_LISTA), CB_DIR, 
      (WPARAM)0, (LPARAM)path);

Juegos de caracteres

Disponemos de un estilo específico para controles combo box que contienen nombres de ficheros, se trata del estilo CBS_OEMCONVERT. Cuando un control tiene este estilo, las cadenas insertadas se convierten desde juego de caracteres de Windows al juego de caracteres OEM y después se vuelve a convertir al juego de caracteres de Windows. Esto asegura una conversión correcta si la aplicación llama a la función CharToOem para convertir una cadena Windows del combo box a una cadena OEM. Este sólo se puede aplicar a controles con el estilo CBS_SIMPLE o CBS_DROPDOWN.

Procesar CBN_CLOSEUP

Es aconsejable procesar el mensaje de notificación CBN_CLOSEUP cuando se trabaja con combo boxes que contienen directorios o ficheros, sobre todo cuando la elección de una de las opciones requiera algún tipo de proceso, por ejemplo, al cambiar de directorio se deberá limpiar la lista y volver a generarla. En estos casos no sería lógico procesar el mensaje de notificación CBN_SELCHANGE.

Selección actual

Es el ítem de la lista del combo box seleccionado por el usuario. Su texto se copia en el campo de selección, tanto si se trata de un control de edición o de uno estático. Salvo en el caso de la lista desplegable, existe otra forma de introducir datos en un combo box: teclearlos en el control edit.

Ya hemos visto que es posible recuperar el valor de la selección actual mediante un mensaje CB_GETCURSEL, o cambiarlo mediante un mensaje CB_SETCURSEL o CB_SELECTSTRING.

También hemos visto que existe un mensaje de notificación CBN_SELCHANGE que se envía a la ventana padre del combo box cada vez que el usuario cambia la selección actual. Hay que tener en cuenta que este mensaje de notificación no se envía si la selección actual se modifica directamente usando un mensaje CB_SETCURSEL.

Ejemplo 73

En este ejemplo hemos usado algunas funciones y estructuras del API, relacionadas con información sobre ficheros y manejo de tiempos, que no hemos comentado con anterioridad:

  • GetFileAttributesEx sirve para obtener información sobre un fichero, sus atributos, fechas de creación, modificación y último acceso y tamaño.
  • WIN32_FILE_ATTRIBUTE_DATA es la estructura usada por la función anterior para devolver los datos de un fichero.
  • FileTimeToSystemTime las fechas devueltas por la función anterior están en formato de fecha de fichero, esta función permite traducir ese formato a formato de fecha de sistema, que es más manejable.
  • FILETIME estructura que almacena una fecha en forma de número entero.
  • SYSTEMTIME estructura que almacena una fecha en forma de campos individuales.

Veremos todos estos conceptos en capítulos futuros dedicados específicamente a ello.


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 73 win073.zip 2007-03-15 4107 bytes 124