Contoles edit de sólo lectura

Uno de los estilos que se pueden aplicar a un control edit es el de sólo lectura. ES_READONLY. Cuando se activa estilo el contenido del control no podrá ser modificado por el usuario.

Esto es, aparentemente, una contradicción. Bien pensado, un control edit cuyo contenido no puede ser modificado es un control estático. Sin embargo, en determinadas circunstancias puede que no sea tan absurdo, sobre todo si tenemos en cuenta que este estilo se puede modificar durante la ejecución. Esto puede ser útil si en ciertas situaciones, determinados valores están predefinidos. Por ejemplo, dependiendo de la opción seleccionada en un conjunto de RadioButtons, determinadas entradas de texto pueden ser innecesarias, o tener valores predefinidos o predecibles, que no necesitan ser editados. Otro ejemplo puede ser un programa en el que, dependiendo del nivel de privilegios de un usuario, determinados valores puedan o no ser modificados.

Además, si queremos ser precisos, un control edit de sólo lectura no es en todo equivalente a un control estático. Por ejemplo, el texto del control edit siempre puede ser marcado y copiado al portapapeles, algo que no se puede hacer con los textos de los controles estáticos.

Para modificar esta opción para un control edit se envía un mensaje EM_SETREADONLY.

Para averiguar si un control edit tiene el estilo ES_READONLY se debe usar la función GetWindowLong usando la constante GWL_STYLE.

Para ilustar esto, modificaremos el ejemplo 5 para añadir un checkbox que active y desactive el control edit. Empezaremos por modificar la definición del diálogo en el fichero de recursos:

DialogoPrueba DIALOG 0, 0, 118, 58
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Diálogo de prueba"
FONT 8, "Helv"
BEGIN
 CONTROL "Sólo lectura", ID_ACTIVAR, "BUTTON",
    BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
    12, 4, 60, 12
 CONTROL "Texto:", -1, "STATIC", 
    SS_LEFT | WS_CHILD | WS_VISIBLE, 
    8, 20, 28, 8
 CONTROL "", ID_TEXTO, "EDIT", 
    ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 
    36, 20, 76, 12
 CONTROL "Aceptar", IDOK, "BUTTON", 
    BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    8, 36, 45, 14
 CONTROL "Cancelar", IDCANCEL, "BUTTON", 
    BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
    61, 36, 45, 14
END

Añadiremos un identificador para el control CheckBox en win050.h:

#define ID_ACTIVAR 101

Añadiremos un dato a la estructura de datos del cuador de diálogo para almacenar el estado del CheckBox:

typedef struct stDatos {
   char Texto[80];
   BOOL Estado;
} DATOS;

Por supuesto, asignaremos un valor inicial a ese estado en el procedimiento de ventana:

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HINSTANCE hInstance;
    /* Variables para diálogo */
    static DATOS Datos;

    switch (msg)                  /* manipulador del mensaje */
    {
        case WM_CREATE:
           hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
           /* Inicialización de los datos de la aplicación */
           strcpy(Datos.Texto, "Inicial");
           Datos.Estado = FALSE;
           return 0;
...

Y modificaremos el procedimiento de diálogo para tratar este nuevo control:

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static DATOS *Datos;

    switch (msg)                  /* manipulador del mensaje */
    {
        case WM_INITDIALOG:
           SendDlgItemMessage(hDlg, ID_TEXTO, EM_LIMITTEXT, 80, 0L);
           Datos = (DATOS *)lParam;
           SetDlgItemText(hDlg, ID_TEXTO, Datos->Texto);
           /* Acticar el estilo según el valor actual de estado */
           SendMessage(GetDlgItem(hDlg, ID_TEXTO), EM_SETREADONLY, Datos->Estado, 0);
           /* Aplicar el estado actual del CheckBox */
           CheckDlgButton(hDlg, ID_ACTIVAR,
              Datos->Estado ? BST_CHECKED : BST_UNCHECKED);
           SetFocus(GetDlgItem(hDlg, ID_TEXTO));
           return FALSE;  
        case WM_COMMAND:
           switch(LOWORD(wParam)) {
              case ID_ACTIVAR:
                 Datos->Estado = !Datos->Estado;
                 SendMessage(GetDlgItem(hDlg, ID_TEXTO), EM_SETREADONLY, Datos->Estado, 0);
                 break;
              case IDOK: 
                 GetDlgItemText(hDlg, ID_TEXTO, Datos->Texto, 80);
                 EndDialog(hDlg, FALSE);
                 break;
              case IDCANCEL:
                 EndDialog(hDlg, FALSE);
                 break;
           }
           return TRUE;
    }
    return FALSE;
}

Ejemplo 50


  Nombre Fichero Fecha Tamaño Contador Descarga
D Ejemplo 50 win050.zip 2005-11-07 3301 bytes 138