Editar números

En muchas ocasiones necesitaremos editar valores de números enteros en nuestros diálogos.

Para eso, el API tiene previstas algunas constantes y funciones, (aunque no es así para números en coma flotante, para los que tendremos que crear nuestros propios controles).

Bien, vamos a modificar nuestro ejemplo para editar valores numéricos en lugar de cadenas de texto.

Fichero de recursos para editar enteros

Empezaremos añadiendo una constante al fichero de identificadores: "win006.h":

#define ID_NUMERO 100

Y redefiniendo el control edit en el fichero de recursos, al que añadiremos el flag ES_NUMBER para que sólo admita caracteres numéricos:

DialogoPrueba DIALOG 0, 0, 118, 48
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Diálogo de prueba"
FONT 8, "Helv"
BEGIN
 CONTROL "Número:", -1, "STATIC", 
    SS_LEFT | WS_CHILD | WS_VISIBLE, 
    8, 9, 28, 8
 CONTROL "", ID_NUMERO, "EDIT", 
    ES_NUMBER | ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 
    36, 9, 76, 12
 CONTROL "Aceptar", IDOK, "BUTTON", 
    BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    8, 26, 45, 14
 CONTROL "Cancelar", IDCANCEL, "BUTTON", 
    BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    61, 26, 45, 14
END

Variables a editar en los cuadros de diálogo

Ahora modificaremos la estructura de los datos para que el dato a editar sea de tipo numérico:

typedef struct stDatos {
   int Numero;
} DATOS;

Al igual que antes, daremos valores iniciales a las variables del diálogo al procesar el mensaje WM_CREATE.

        case WM_CREATE:
           /* Inicialización de los datos de la aplicación */
           Datos.Numero = 123;

Por supuesto, pasaremos un puntero a esta estructura a la función DialogBoxParam, haciendo uso el parámetro lParam:

static DATOS Datos;
...
   DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc, (LPARAM)&Datos);

Iniciar controles edit de enteros

Ahora tenemos que hacer que se actualice el contenido del control edit al abrir el cuadro de diálogo.

El lugar adecuado para hacer esto es en el proceso del mensaje WM_INITDIALOG:

    static DATOS *datos;
...
        case WM_INITDIALOG:
           datos = (DATOS *)lParam;
           SetDlgItemInt(hDlg, ID_NUMERO, (UINT)datos->Numero, FALSE);
           SetFocus(GetDlgItem(hDlg, ID_NUMERO));
           return FALSE;

En este caso no es necesario limitar el texto que podemos editar en el control, ya que, como veremos, las propias funciones del API se encargan de capturar y convertir el contenido del control en un número, de modo que no tenemos que preocuparnos de que no quepa en nuestra variable.

También hemos modificado la función a la que llamamos para modificar el contenido del control, ahora usaremos SetDlgItemInt, que cambia el contenido de un control edit con un valor numérico.

Devolver valores a la aplicación

Por último leeremos el contenido cuando procesemos el comando generado al pulsar el botón de "Aceptar".

    BOOL NumeroOk;
    int numero;
...
        case WM_COMMAND:
           switch(LOWORD(wParam)) {
              case IDOK: 
                 numero = GetDlgItemInt(hDlg, ID_NUMERO, &NumeroOk, FALSE);
                 if(NumeroOk) {
                    datos->Numero = numero;
                    EndDialog(hDlg, FALSE);
                 }
                 else 
                    MessageBox(hDlg, "Número no válido", "Error", 
                       MB_ICONEXCLAMATION | MB_OK);
                 break;

Para eso hemos añadido la llamada a la función GetDlgItemInt, que es simétrica a SetDlgItemInt. El proceso difiere del usado para capturar cadenas, ya que en este caso la función nos devuelve el valor numérico del contenido del control edit.

También devuelve un parámetro que indica si ha habido algún error durante la conversión. Si el valor de ese parámetro es TRUE, significa que la conversión se realizó sin problemas, si es FALSE, es que ha habido un error. Si nuestro programa detecta un error visualizará un mensaje de error y no permitirá abandonar el cuadro de diálogo.

Pero si ha habido un error, el valor de retorno de GetDlgItemInt será cero. Esto nos causa un problema. Si leemos el valor directamente en datos->Numero y el usuario introduce un valor no válido, y después pulsa "Cancelar", el valor devuelto no será el original, sino 0. Para evitar eso hemos usado una variable local, y el valor de datos->Numero sólo se actualiza antes de salir con "Aceptar" y con un valor válido.

Por último, hemos usado el flag BM_ICONEXCLAMATION en el MessageBox, que añade un icono al cuadro de mensaje y el sonido predeterminado para alertar al usuario.

Ejemplo 6


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 6 win006.zip 2004-05-17 3104 bytes 763

Comentarios de los usuarios (1)

SERGIO
2016-07-07 18:17:25

buenos dias por favor ayuda el ejemplo 6 no me corre y me salen 2 errores en el main con los corchetes