Esta nota describe la arquitectura de enrutamiento y el envío de comandos así como temas avanzados de enrutamiento de mensajes de ventana general.
Consulte Guía del programador de Visual C++ para obtener información general sobre las arquitecturas descritas aquí, especialmente la distinción entre los mensajes, las notificaciones de control y comandos de Windows. Esta nota se supone que está muy familiarizados con los problemas descritos en la documentación impresa y sólo aborda temas muy avanzados.
Enrutamiento de comandos y envío MFC 1.0 funcionalidad evoluciona a MFC 2.0 arquitectura
Windows tiene el mensaje WM_COMMAND que está sobrecargado para proporcionar notificaciones de comandos de menú, teclas de aceleración y control de diálogo notificaciones.
MFC 1.0 basa un poco al permitir que a un controlador de comandos (por ejemplo, "OnFileNew") en un CWnd clase igualan en respuesta a una específica WM_COMMANDderivada. Esta está pegada junto con una estructura de datos llamada el mapa de mensajes y los resultados en un mecanismo de comando muy eficiente del espacio.
MFC 1.0 también proporciona funcionalidad adicional para separar las notificaciones de control de mensajes de comando. Los comandos están representados por un ID de 16 bits, conocido a veces como un identificador de comando. Comandos normalmente iniciar desde un CFrameWnd (p. ej.: un menú, seleccione o un acelerador traducido) y se enruta a una variedad de otras ventanas.
MFC 1.0 utiliza enrutamiento de comandos en un sentido limitado para la implementación de la interfaz de documentos múltiples (MDI). (Una ventana de marco MDI delegar comandos a su ventana MDI secundarios activa).
Esta funcionalidad se ha generalizado y extendido en MFC 2.0 para permitir comandos para ser manejados por una amplia gama de objetos (no sólo los objetos de ventana). Proporciona más formal y arquitectura extensible para el enrutamiento de mensajes y reutiliza el destino de comando enrutamiento para tratar no sólo de comandos, sino también para la actualización de los objetos de interfaz de usuario (como elementos de menú y botones de la barra de herramientas) para reflejar la disponibilidad actual de un comando.
Identificadores de comandos
Consulte la Guía del programador de Visual C++ para obtener una explicación del comando enrutamiento y proceso de enlace. 20 De nota técnica contiene información sobre nombres de ID.
Utilizamos el prefijo genérico "ID_" para identificadores de comando. Comando ID son gt; = 0 x 8000. La barra de Estado o línea de mensaje mostrará la cadena de descripción del comando si es un recurso STRIN>ABLE con el mismo ID como el identificador de comando.
En los recursos de la aplicación, un comando que ID puede aparece en varios lugares:
En el código fuente de su aplicación, un comando que ID puede aparece en varios lugares:
Actualmente, la aplicación sólo en MFC que requiere identificadores de comando ser gt; = 0 x 8000 es la aplicación de los cuadros de diálogo y comandos de &GOSUB.
GOSUB comandos, utilizando arquitectura de comando en los cuadros de diálogo
La arquitectura de comando del enrutamiento y activación de comandos funciona bien con ventanas de marco, elementos de menú, botones de barra de herramientas, botones de la barra de diálogo, otras barras de control y otros elementos de interfaz de usuario diseñadas para actualizar sobre demanda y ruta de comandos o control IDs a un destino de comando principal (normalmente la ventana de marco principal). Ese destino de comando principal puede enrutar los comando o control de notificaciones a otros objetos de destino de comando según corresponda.
Un cuadro de diálogo (modal o no modal) puede beneficiarse de algunas de las características de la arquitectura de comando si asigna el ID del control del control de cuadro de diálogo para el identificador de comando correspondiente. Soporte para cuadros de diálogo no es automático, por lo que puede que tenga que escribir código adicional.
Tenga en cuenta que para que todas estas características para que funcione correctamente, los identificadores de comando deberían ser gt; = 0 x 8000. Dado que muchos de los diálogos podrían obtener enruta al mismo fotograma, comandos compartidos deben ser > = 0 x 8000, mientras que los no compartidos IDC en un cuadro de diálogo específico debe ser < = 0x7FFF.
Puede colocar un botón normal en un cuadro de diálogo modal normal con el Cid del botón establecer para el identificador de comando correspondiente. Cuando el usuario selecciona el botón, el propietario del cuadro de diálogo (normalmente, la ventana de marco principal) obtiene el comando al igual que cualquier otro comando. Esto se denomina un comando GOSUB ya que normalmente se utiliza para abrir otro cuadro de diálogo (un GOSUB del primer cuadro de diálogo).
También puede llamar a la función CWnd::UpdateDialogControls en el cuadro de diálogo y pasarlo a la dirección de su ventana de marco principal. Esta voluntad de función activada o deshabilitar los controles de cuadro de diálogo basan en si tienen controladores de comando en el fotograma. Esta función se llama automáticamente para usted para las barras de control en bucle de inactividad de su aplicación, pero se debe llamar directamente para los diálogos normales que desea que tienen esta característica.
Cuando se llama a ON_UPDATE_COMMAND_UI
Mantener el estado permitió comprobar elementos de todo un programa de menú todo el tiempo, puede ser un problema computacionalmente caro. Una técnica común es activar y comprobar los elementos de menú sólo cuando el usuario selecciona en el menú emergente. La aplicación MFC 2.0 de CFrameWnd controla el mensaje WM_INITMENUPOPUP y utiliza la arquitectura de enrutamiento de comandos para determinar los Estados de menús mediante controladores de ON_UPDATE_COMMAND_UI.
CFrameWnd controla también el mensaje WM_ENTERIDLE para describir el menú actual del elemento seleccionado en el estado de la barra (también conocida como la línea del mensaje).
Estructura de menús de una aplicación, editado por Visual C++, se utiliza para representar los posibles comandos disponibles en el momento WM_INITMENUPOPUP . Controladores de ON_UPDATE_COMMAND_UI pueden modificar el texto de un menú o estado, o para usos avanzados (como la lista MRU de archivo o el menú de verbos OLE), realmente modificar la estructura de menú antes de la elaboración del menú.
El mismo tipo de procesamiento de ON_UPDATE_COMMAND_UI se realiza para las barras de herramientas (y otras barras de control) cuando la aplicación entra en su bucle inactivo. Consulte la Referencia de la biblioteca de clase y técnica 31 nota para obtener más información sobre barras de control.
Menús emergentes anidados
Si está utilizando una estructura de menús anidados, observará que se llama al controlador ON_UPDATE_COMMAND_UI para el primer elemento de menú en el menú emergente en dos casos diferentes.
En primer lugar es llamado por el emergente propia. Esto es necesario ya que los menús emergentes no tienen identificadores y usamos el ID del primer elemento del menú de la ventana emergente para referirse a la emergente toda. En este caso la variable miembro m_pSubMenu del objeto CCmdUI será distinto de NULL y apuntará al menú emergente.
En segundo lugar se llama justo antes de que los elementos de menú en el menú emergente son para establecerse. En este caso el ID se refiere sólo al primer elemento del menú y la variable miembro m_pSubMenu del objeto CCmdUI será NULL.
Esto le permite habilitar la ventana emergente distinta a sus elementos de menú, pero requiere que escribir algún código consciente de menú. Por ejemplo, en un menú anidado con la siguiente estructura:
Filegt;
Nuevo >
Hoja (ID_NEW_SHEET)
Gráfico (ID_NEW_CHART)
Pueden activarse o desactivarse independientemente los comandos ID_NEW_SHEET y ID_NEW_CHART. El menú emergente "Nuevo" debe habilitarse si cualquiera de los dos está activado.
El controlador del comando de ID_NEW_SHEET (el primer comando en el menú emergente) sería algo así:
void CMyApp::OnUpdateNewSheet (CCmdUI * pCmdUI)
{
nbsp; Si (pCmdUI - > m_pSubMenu! = NULL)
{
/ / Habilitar todo emergente para la "Nueva" hoja y de diagrama
BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;
/ / CCmdUI::Enable no es un-op para este caso, por lo que nos
/ / debe hacer lo que lo habría hecho.
pCmdUI - > m_pMenu - > EnableMenuItem (pCmdUI - > m_nIndex,
MF_BYPOSITION |
¿(bEnable? MF_ENABLED: (MF_DISABLED | MF_GRAYED)));
retorno;
}
/ / justo lo contrario, el comando nueva hoja
pCmdUI - > Enable(m_bCanCreateSheet);
}
El controlador del comando de ID_NEW_CHART sería un controlador de comandos de actualización normal y la mirada algo como:
void CMyApp::OnUpdateNewChart (CCmdUI * pCmdUI)
{
nbsp; pCmdUI - > Enable(m_bCanCreateChart);
}
ON_COMMAND y ON_BN_CLICKED
Las macros de mapa de mensajes para ON_COMMAND y ON_BN_CLICKED son los mismos. El MFC comando y control de enrutamiento mecanismo de notificación sólo utiliza el ID de comando para decidir dónde enrutar a. Las notificaciones de control con el código de notificación de control de cero (BN_CLICKED) se interpretan como comandos.
Avanzado Nota: en realidad, todos los mensajes de notificación de control ir a través de la cadena de comando controlador. Por lo tanto, es técnicamente posible para escribir un controlador de notificación de control para decir EN_CHANGE en la clase de documento. Esto no es generalmente recomendable desde las aplicaciones prácticas de esta función son pocos, la función no es compatible con ClassWizard y uso de la función puede dar como resultado código frágil.
Deshabilitar la desactivación automática de controles de botón
Si se coloca un control de botón en la barra de diálogo, o en un cuadro de diálogo mediante donde está llamando a CWnd::UpdateDialogControls en su propio, observará que botones que no tienen controladores de ON_COMMAND o ON_UPDATE_COMMAND_UI se desactiva automáticamente para usted por el marco. En algunos casos no será necesario disponer de un controlador, pero se desea que el botón seguir habilitado. La forma más sencilla de lograr esto es agregar un controlador de comandos maniquí (fácil de hacer con ClassWizard) y no hacer nada en ella.
Enrutamiento de mensajes de ventana
A continuación describen algunos temas más avanzados en las clases MFC y enrutamiento de mensajes de Windows y otros temas de impacto les. La información que aquí sólo se describe brevemente. Consulte la Referencia de la biblioteca de clases para obtener más información acerca de las API públicas. Consulte el código de biblioteca MFC para obtener más información sobre detalles de la implementación.
Consulte 17 de nota técnica para obtener más información sobre la limpieza de la ventana, un tema muy importante para todos CWnd-clases derivadas.
Cuestiones de CWnd
La función de miembro de aplicación CWnd::OnChildNotify proporciona una arquitectura potente y ampliable para ventanas secundarias (también conocido como controles) para enlazar o de lo contrario estar informado de mensajes, comandos y notificaciones de control que van a su padre (o "propietario"). Si la ventana secundaria (/ control) es un objeto de C++ CWnd propiamente dicho, la función virtual OnChildNotify se llama primero con los parámetros del mensaje original (es decir, una estructura MSG ). La ventana secundaria puede dejar el mensaje solo, comer o modificar el mensaje para el padre (raro).
La implementación predeterminada de CWnd maneja los siguientes mensajes y utiliza el gancho de OnChildNotify para permitir ventanas secundarias (controles) para obtener primera grieta en el mensaje:
Observará que el gancho OnChildNotify se utiliza para cambiar los mensajes dibujado por el propietario en mensajes self-draw.
Además el gancho OnChildNotify mensajes de desplazamiento tienen comportamiento de enrutamiento más. Consulte a continuación para obtener más detalles sobre las barras de desplazamiento y las fuentes de mensajes WM_HSCROLL y WM_VSCROLL.
Problemas de CFrameWnd
La clase CFrameWnd proporciona la mayor parte del enrutamiento de comandos y la interfaz de usuario actualizar la aplicación. Esto se utiliza principalmente para la ventana de marco principal de la aplicación (CWinApp::m_pMainWnd) pero se aplica a todas las ventanas de marco.
La ventana de marco principal es la ventana con la barra de menú y es el principal de la barra de Estado o línea del mensaje. Consulte la discusión anterior sobre enrutamiento de comandos y WM_INITMENUPOPUP.
La clase CFrameWnd proporciona administración de la vista activa. Los siguientes mensajes se enrutan a través de la vista activa:
Problemas de CMDIFrameWnd/CMDIChildWnd
Ambas clases de ventana de marco MDI derivan de CFrameWnd y por lo tanto, son ambos habilitados para el mismo tipo de enrutamiento de comandos y la interfaz de usuario actualización proporcionada en CFrameWnd. En una aplicación MDI típica, la ventana de marco principal (es decir, el objeto CMDIFrameWnd ) contiene la barra de menús y la barra de Estado y por lo tanto, es la principal fuente de la aplicación de enrutamiento de comandos.
El esquema de distribución general es que la ventana secundaria MDI activa obtiene primer crack comandos at. Las funciones predeterminadas que PreTranslateMessage manejan tablas de aceleradores para ambas ventanas MDI secundarias (primero) y el marco MDI (segundo), así como los aceleradores de comando del sistema MDI estándar normalmente manejados por TranslateMDISysAccel (último).
Problemas de la barra de desplazamiento
Al manipular el mensaje de desplazamiento (mensajes WM_HSCROLLyOnHScroll y WM_VSCROLL/OnVScroll ), debe intentar escribir el código del controlador por lo que no dependen de donde provenía el mensaje de la barra de desplazamiento. Esto no es sólo una cuestión de Windows general, desde mensajes de desplazamiento pueden proceder de verdadera barra controles de desplazamiento o de WS_HSCROLL/WS_VSCROLL las barras de desplazamiento que no barra de desplazamiento controles.
MFC amplía para permitir controles de la barra de desplazamiento ser hijo o hermanos de la ventana se desplaza (de hecho la relación padre-hijo entre la barra de desplazamiento y la ventana se desplaza puede ser cualquier cosa). Esto es especialmente importante para las barras de desplazamiento compartido con ventanas divisoras. Consulte 29 de nota técnica para obtener más información sobre la aplicación de CSplitterWnd incluyendo más información sobre cuestiones de la barra de desplazamiento compartido.
En una nota al margen, hay dos CWnd clases derivadas, donde los estilos de barra de desplazamiento especificados al creación tiempo son atrapadas y no pasar a Windows. Cuando se pasa a una rutina de creación, WS_HSCROLL y WS_VSCROLL pueden establecerse independientemente, pero después no se puede cambiar la creación. ¿Por supuesto, no directamente debe probar o establecer la WS_?Bits de estilo de desplazamiento de la ventana que crearon.
CMDIFrameWnd los estilos de barra de desplazamiento que pasa al crear o LoadFrame se utilizan para crear la MDICLIENT. Si desea tener un área MDICLIENT desplazable (como el programa Administrador de Windows) asegúrese de definir tanto desplazarse estilos de barra (WS_HSCROLL | WS_VSCROLL) para el estilo utilizado para crear el CMDIFrameWnd.
Los estilos de la barra de desplazamiento se aplicarán a las barras de desplazamiento compartido especial para las regiones de separador para CSplitterWnd . Para ventanas divisoras estáticas, normalmente no debe configurar uno u otro estilo de barra de desplazamiento. Para ventanas divisoras dinámicas normalmente tendrá el scroll bar conjunto de estilo para la dirección que se divide, es decir, WS_HSCROLL si se pueden dividir filas, WS_VSCROLL si se pueden dividir en columnas.
&Notas técnicas por número |nbsp; Notas técnicas por categoría