Su consultor TI

Conozca su infraestructura, mejore lo que necesite

Como evitar que un diálogo MFC se cierre al pulsar las teclas de Enter o ESC

tecla return o enter

tecla return o enter

Este problema se me presentó al desarrollar la calculadora para especular en bolsa que publiqué hace poco.

Al ser una aplicación que se usa puntualmente pero que siempre tengo arrancada mientras analizo los gráficos de los valores, muchas veces capturaba el foco y cuando pulsaba Enter (Return según el teclado) o ESC, se cerraba sin que yo realmente quisiera hacerlo, probablemente ni siquiera estaba usándola en ese momento.

No era un problema serio, pero sí muy molesto, puesto que cuando iba a usarla, me daba cuenta de que se había cerrado.

La aplicación está programada en C++ con Visual Studio de Microsoft, usando las librerías MFC (Microsoft Foundation Classes), que proporcionan un marco estupendo para desarrollar rápidamente programas sin preocuparse de los detalles de más bajo nivel, pero que permiten, llegado el caso, profundizar mucho y, en este caso, he necesitado meterme un poco más profundamente en el código del manejador de mensajes para solucionar el problema.

tecla_escEL caso es que no tenía muy claro porque pasaba, no me había ocurrido en otros desarrollos en C++. Probé varias soluciones como a sustituir las funciones que por defecto vienen con MFC para manejar los eventos generados por los botones de “Aceptar” o “Cancelar” que aparecen por defecto en todas las aplicaciones basadas en diálogos MFC, pero no me sirvió de mucho. Tampoco sirvió eliminar y sustituir los identificadores de esos botones que realmente no usaba (“IDOK” e “IDCANCEL“).

Al final, la solución que he encontrado pasa por interceptar todos los mensajes de eventos que recibe el diálogo (mi aplicación está basada en una sola ventana de diálogo), y descartar todos los que hacen referencia a la pulsación de las teclas Enter o ESC, para así simular la desactivación de las mismas. Os pongo el sencillo código a continuación.

En el fichero de cabecera (.h) donde se define vuestra clase del diálogo deberéis incluir esta línea:

virtual BOOL PreTranslateMessage(MSG* pMsg);

Y en el fichero de código (.cpp), estas que os pongo a continuación:

BOOL CTuclaseDlg::PreTranslateMessage(MSG* pMsg)
{
	if((pMsg->wParam == VK_ESCAPE) || (pMsg->wParam == VK_RETURN))
	{
		return false;
	}

	return CDialog::PreTranslateMessage(pMsg);
}

La función PreTranslateMessage, miembro de la clase CWnd, recibe todos los mensajes que deben ser procesados por la ventana de diálogo, desde los click de ratón, pulsaciones de teclas, focos, etc, antes de que se reciban por la funciones que realmente los procesan, que son TranslateMessage y DispatchMessage .

Lo que recibe esta función como parámetro, es un puntero al mensaje con una serie de datos que os muestro abajo:

typedef struct tagMSG {
	HWND hwnd;
	UINT message;
	WPARAM wParam;
	LPARAM lParam;
	DWORD time;
	POINT pt;
} MSG;

Esa estructura contine mucha información, pero lo interesante en este caso, es que, en caso de que se haya pulsado una tecla, su código, vendrá en el parámetro wParam. Podría complicar el código filtrando el tipo de mensajes, probablemente sería más elegante, pero para mi caso, dado que no necesito las pulsaciones de Enter o ESC para nada en ninguna parte de la ventana, simplemente miro si hace referencia a alguna de esas dos teclas, independientemente del tipo de mensaje recibido o incluso de para quien es ese mensaje.

Si por ejemplo, quisiera solamente obviar la pulsaciones de esas teclas para alguno de los controles, debería poner un filtro antes sobre el tipo de mensaje y el destinatario. Quedaría algo similar a:

UINT ctrlID = GetDlgCtrlID(msg->hwnd);

if (ctrlID == "ID_DEL_CONTROL")  
{
	if(msg->wParam==VK_ENTER)
	{
		return FALSE;
	}
}

En este caso, con la función GetDlgCtrlID(msg->hwnd) obtendríamos el identificador de la ventana que recibe el mensaje y en el caso de ser la ventana del control que nos interese, haríamos lo que necesitáramos, que en mi caso es filtrar las pulsaciones de Enter (VK_RETURN) o la tecla ESC (VK_ESCAPE).

Espero que os pueda ser útil.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *


*

Su consultor TI © 2014 Frontier Theme