TN040: Cambio de tamaño y zoom en contexto de MFC/OLE
Nota:
La nota técnica siguiente no se ha actualizado desde que se incluyó por primera vez en la documentación en línea. Como resultado, algunos procedimientos y temas podrían estar obsoletos o ser incorrectos. Para obtener información más reciente, se recomienda buscar el tema de interés en el índice de la documentación en línea.
En esta nota se describen los problemas relacionados con la edición en contexto y cómo un servidor debe lograr el zoom correcto y el cambio de tamaño en contexto. Con la activación en contexto, el concepto WYSIWYG se lleva un paso más allá ya que los contenedores y los servidores cooperan entre sí y, en particular, interpretan la especificación OLE de la misma manera.
Debido a la estrecha interacción entre un contenedor y un servidor que admite la activación en contexto, hay una serie de expectativas del usuario final que se deben mantener:
La presentación (el metarchivo dibujado en la invalidación
COleServerItem::OnDraw
) debe tener exactamente el mismo aspecto que cuando se dibuja para su edición (excepto que las herramientas de edición no son visibles).Cuando el contenedor hace zoom, la ventana del servidor también debe hacerlo.
Tanto el contenedor como el servidor deben mostrar objetos para editarlos con las mismas métricas. Esto significa usar un modo de asignación basado en el número de píxeles lógicos por pulgada, no píxeles físicos por pulgada, cuando se representa en el dispositivo de pantalla.
Nota:
Dado que la activación en contexto solo se aplica a los elementos incrustados (no vinculados), el zoom solo se aplica a los objetos incrustados. Verá API en COleServerDoc
y COleServerItem
que se usan para el zoom. La razón de esta dicotomía es que solo las funciones válidas tanto para los elementos vinculados como para los incrustados están en COleServerItem
(esto le permite tener una implementación común), y las funciones que son válidas solo para los objetos incrustados se encuentran en la clase COleServerDoc
(desde la perspectiva del servidor, documento es lo que está incrustado).
La mayor parte de la carga se coloca en el implementador del servidor, en que el servidor debe tener en cuenta el factor de zoom del contenedor y modificar su interfaz de edición según corresponda. ¿Pero cómo determina el servidor el factor de zoom que usa el contenedor?
Compatibilidad con MFC para hacer zoom
El factor de zoom actual se puede determinar llamando a COleServerDoc::GetZoomFactor
. Llamar cuando el documento no esté activo en contexto siempre dará como resultado un factor de zoom del 100 % (o una relación de 1:1). Llamar mientras está activo puede devolver algo distinto del 100 %.
Para obtener un ejemplo de hacer zoom correctamente, vea el ejemplo OLE de MFC HIERSVR. Hacer zoom en HIERSVR es complicado por el hecho de que muestra texto, y el texto, en general, no se escala de forma lineal (sugerencias, convenciones tipográficas, anchos de diseño y alturas, todo complica el asunto). Aun así, HIERSVR es una referencia razonable para implementar el zoom correctamente, así como el tutorial de MFC SCRIBBLE (paso 7).
COleServerDoc::GetZoomFactor
determina el factor de zoom basado en varias métricas diferentes disponibles desde el contenedor o desde la implementación de las clases COleServerItem
y COleServerDoc
. En resumen, el factor de zoom actual viene determinado por la fórmula siguiente:
Position Rectangle (PR) / Container Extent (CE)
El contenedor determina POSITION RECTANGLE. Se devuelve al servidor durante la activación en contexto cuando se llama a COleClientItem::OnGetItemPosition
, y se actualiza cuando el contenedor llama a COleServerDoc::OnSetItemRects
del servidor (con una llamada a COleClientItem::SetItemRects
).
CONTAINER EXTENT es ligeramente más complejo de calcular. Si el contenedor ha llamado a COleServerItem::OnSetExtent
(con una llamada a COleClientItem::SetExtent
), CONTAINER EXTENT es este valor convertido a píxeles en función del número de píxeles por pulgada lógica. Si el contenedor no ha llamado a SetExtent (que suele ser el caso), CONTAINER EXTENT es el tamaño devuelto desde COleServerItem::OnGetExtent
. Por lo tanto, si el contenedor no ha llamado a SetExtent, el marco supone que si lo hiciera, el contenedor lo hubiera llamado con el 100 % de la extensión natural (el valor devuelto desde COleServerItem::GetExtent
). Dicho de otra manera, el marco supone que el contenedor muestra el 100 % (ni más, ni menos) del elemento.
Es importante tener en cuenta que aunque COleServerItem::OnSetExtent
y COleServerItem::OnGetExtent
tienen nombres similares, no manipulan el mismo atributo del elemento. Se llama a OnSetExtent
para que el servidor sepa cuánto del objeto está visible en el contenedor (independientemente del factor de zoom) y el contenedor llama a OnGetExtent
para determinar el tamaño ideal del objeto.
Examinando cada una de las API implicadas puede obtener una imagen más clara:
COleServerItem::OnGetExtent
Esta función debe devolver el "tamaño natural" del elemento en unidades HIMETRIC. La mejor manera de pensar en el "tamaño natural" es definirlo como el tamaño que puede aparecer cuando se imprime. El tamaño devuelto aquí es constante para un contenido de elemento determinado (al igual que el metarchivo, que es constante para un elemento determinado). Este tamaño no cambia al aplicar zoom al elemento. Normalmente no cambia cuando el contenedor proporciona al elemento más o menos espacio llamando a OnSetExtent
. Un ejemplo de un cambio puede ser el de un editor de texto simple sin ninguna funcionalidad de "margen" que encapsula texto en función de la última extensión enviada por el contenedor. Si un servidor cambia, es probable que el servidor establezca el fragmento de OLEMISC_RECOMPOSEONRESIZE en el registro del sistema (consulte la documentación del SDK de OLE para obtener más información sobre esta opción).
COleServerItem::OnSetExtent
Se llama a esta función cuando el contenedor muestra "más o menos" del objeto. La mayoría de los contenedores no la llamarán en absoluto. La implementación predeterminada almacena el último valor recibido del contenedor en "m_sizeExtent", que se usa en COleServerDoc::GetZoomFactor
al calcular el valor CONTAINER EXTENT descrito anteriormente.
COleServerDoc::OnSetItemRects
Se llama a esta función solo cuando el documento está activo en contexto. Se llama cuando el contenedor actualiza la posición del elemento o el recorte aplicado al elemento. POSITION RECTANGLE, como se explicó anteriormente, proporciona el numerador para el cálculo del factor de zoom. Un servidor puede solicitar que se cambie la posición del elemento mediante una llamada a COleServerDoc::RequestPositionChange
. El contenedor puede o no responder a esta solicitud llamando a OnSetItemRects
(con una llamada a COleServerItem::SetItemRects
).
COleServerDoc::OnDraw
Es importante tener en cuenta que el metarchivo creado por invalidación de COleServerItem::OnDraw
produce exactamente el mismo metarchivo, independientemente del factor de zoom actual. El contenedor escalará el metarchivo según corresponda. Se trata de una distinción importante entre OnDraw
de la vista y OnDraw
del elemento del servidor. La vista controla el zoom, el elemento solo crea un metarchivo ampliable y deja al contenedor para realizar el zoom adecuado.
La mejor manera de asegurarse de que el servidor se comporta correctamente es usar la implementación de COleServerDoc::GetZoomFactor
si el documento está activo en contexto.
Compatibilidad con MFC para el cambio de tamaño en contexto
MFC implementa completamente la interfaz de cambio de tamaño en contexto tal como se describe en la especificación OLE 2. La interfaz de usuario es compatible con la clase COleResizeBar
, un mensaje personalizado WM_SIZECHILD y un control especial de este mensaje en COleIPFrameWnd
.
Es posible que desee implementar un manejo diferente de este mensaje que el que proporciona el marco. Como se ha descrito anteriormente, el marco deja los resultados del cambio de tamaño en contexto al contenedor; el servidor responde al cambio en el factor de zoom. Si el contenedor reacciona estableciendo tanto CONTAINER EXTENT como POSITION RECTANGLE durante el procesamiento de su COleClientItem::OnChangeItemPosition
(llamado como resultado de una llamada a COleServerDoc::RequestPositionChange
), el cambio de tamaño en contexto dará como resultado "más o menos" del elemento en la ventana de edición. Si el contenedor reacciona estableciendo solo POSITION RECTANGLE durante el procesamiento de COleClientItem::OnChangeItemPosition
, el factor de zoom cambiará y el elemento se mostrará "ampliado o reducido".
Un servidor puede controlar (hasta cierto punto) lo que sucede durante esta negociación. Una hoja de cálculo, por ejemplo, podría optar por mostrar más o menos celdas cuando el usuario cambia el tamaño de la ventana mientras edita el elemento en contexto. Un procesador de texto podría optar por cambiar los "márgenes de página" para que sean los mismos que la ventana y reajustar el texto al nuevo margen. Los servidores implementan esto cambiando la extensión natural (el tamaño devuelto desde COleServerItem::OnGetExtent
) cuando se realiza el cambio de tamaño. Esto hará que tanto POSITIO RECTANGLE como CONTAINER EXTENT cambien en la misma cantidad, lo que dará como resultado el mismo factor de zoom, pero un área de visualización mayor o menor. Además, más o menos del documento será visible en el metarchivo generado por OnDraw
. En este caso, el propio documento cambia cuando el usuario cambia el tamaño del elemento, en lugar de simplemente el área de visualización.
Puede implementar el cambio de tamaño personalizado y seguir aprovechando la interfaz de usuario proporcionada por COleResizeBar
mediante la invalidación del mensaje WM_SIZECHILD en la clase COleIPFrameWnd
. Para obtener más información sobre los detalles de WM_SIZECHILD, vea Nota técnica 24.