Introducción:
Estrenemos año con una nueva sección: trucos y cosas para MFC. La verdad es que
me he pensado muy seriamente iniciar una sección sobre este tema, ya que casi
cualquier cosa que queramos saber, ya está escrita por algún sitio en internet,
pero tras reflexionar me he dado cuenta de que en general todo está en inglés.
Con esto no pretendo dedicarme a traducir cosas existentes, o al menos no es esa
la idea de igual modo que no lo ha sido para la sección de C++/CLI (que sigue
viva) y la de bugs; eso no quiere decir que alguna vez, si lo considero
interesante, traduzca o parafrasee algo, pero en ese caso, y como viene siendo
habitual en mi, así lo diré.
La verdad es que lo que voy a contar en esta
entrada es bastante chorra, pero es una de esas cosas que nunca se me queda en
la cabeza y siempre tengo que estar buscándolo y recordándolo, así que lo pongo
y listo.
Y sin más preámbulo vamos al tajo.
Obtener un control de un cuadro de diálogo
La forma habitual de trabajar con cuadros de diálogo en MFC es derivar una clase
de CDialog que toma el valor del ID del recurso del diálogo en cuestión, cosa
que suele hacer el asistente adecuado. Dentro de esa clase pondremos nuestras
variables y utilizaremos el DDX o intercambio dinámico de datos, para mapear
cada control del cuadro con variables que representen a dicho control; también
suele hacerlo automáticamente el asistente desde la edición del plantilla, y es
una forma muy sencilla de mantener actualizados los controles, casi idéntica a
una ficha de Windows Forms.
Pero a veces puede resultarnos inadecuado montar
toda la parafernalia del DDX para un control al que solamente le vamos a cambiar
algo durante la creación del diálogo. O quizás estemos creando el diálogo de
forma dinámica a partir de una plantilla o, como es mi caso actual, cuanta menos
memoria ocupe, mejor.
Cada variable DDX es un objeto derivado de CWnd, y ocupa
su memoria, aparte de tener datos enlazados en las estructuras globales de la
aplicación (quizás más adelante explique cómo funciona eso, aunque ya hay algo
publicado por ahí), por lo que en determinadas circunstancias podríamos no
querer tener una variable completa.
Entonces, ¿cómo podemos acceder al control?
Hay que obtener un puntero a una clase que lo represente. ¿Cómo? Usando
GetDlgItem(), pero no la función global de WIN32, sino el método miembro de
CDialog (que realmente no está definido en CDialog, sino en CWnd). Este método
recibe como parámetro el ID del control o de la ventana hija y devuelve un
puntero a CWnd que representa dicho control.
Una vez obtenido el puntero,
podemos utilizar los métodos miembro de CWnd o de sus hijas para enviarle
mensajes y cambiar su aspecto y/o comportamiento.
Por ejemplo, el código 1:
GetDlgItem(IDC_BTNCONFMS)->EnableWindow(false);
situado dentro de una clase
derivada de CDialog deshabilitará en control IDC_BTNCONFMS, que en el caso que
nos ocupa es un botón normal y corriente. Lo que hace el código de arriba es
dejarlo deshabilitado, de modo que no se pueda presionar.
Pero ¿qué ocurre si
nuestro control es, por ejemplo, un CheckBox y queremos marcarlo o desmarcarlo?
GetDlgItem() devuelve un puntero a un objeto CWnd, pero CWnd no tiene ningún
método para marcar o desmarcar una casilla de verificación.
Una opción
perfectamente válida es la de enviarle un mensaje, en concreto un BM_SETCHECK
mediante SendMessage() o PostMessage(), ya que ambos métodos están definidos en
CWnd, pero resulta una forma bastante bruta de hacerlo.
La forma MFC consiste en
convertir el resultado de GetDlgItem() en el tipo de variable que nos interese y
luego usar dicha variable: 1:
CButton *ckb=(CButton *)GetDlgItem(IDC_INSTALLKB);
ckb->SetWindowText(TEXT("Remove Keyboard Driver"));
ckb->SetCheck(BST_CHECKED);
Lo acabamos de ver, aunque el ejemplo es bastante
atípico pero válido: estamos cambiando el estado de una caja de verificación
(esos a los que se les pone una x al hacer clic sobre ellos) pero que tiene la
presencia visual de un botón, es decir, se queda resaltado cuando está marcado.
De todos modos hay que andar con cuidado a la hora de realizar este tipo de
moldeos, ya que podríamos hacerlo sobre una clase no válida y entonces el
resultado podría ser cualquiera, en general el disparo de alguna aserción dentro
del código de MFC.
Ir al índice de los artículos de RFOG en el
sitio del Guille