TN030: Personalizar la impresión y la vista previa de impresión
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 explica el proceso de personalización y la vista previa de la impresión, y se describen los propósitos de las rutinas de devolución de llamada que se usan en CView
y las rutinas de devolución de llamada y las funciones miembro de CPreviewView
.
El problema
MFC proporciona una solución completa para la mayoría de las necesidades de impresión y de vista previa de esta. En la mayoría de los casos, se requiere poco código adicional para tener una vista de la que se pueda obtener una vista previa y se pueda imprimir. Sin embargo, hay maneras de optimizar la impresión que requieren un esfuerzo significativo por parte del desarrollador, y algunas aplicaciones tienen que agregar elementos de interfaz de usuario específicos al modo de vista previa de impresión.
Impresión eficiente
Cuando una aplicación MFC imprime mediante los métodos estándar, Windows dirige todas las llamadas de salida de la interfaz de dispositivo gráfico (GDI) a un metarchivo en memoria. Cuando se llama a EndPage
, Windows reproduce el metarchivo una vez para cada banda física que la impresora necesita para imprimir una página. Durante esta representación, GDI consulta con frecuencia el procedimiento Abort para determinar si debe continuar. Normalmente, el procedimiento Abort permite procesar los mensajes para que el usuario pueda anular el trabajo de impresión mediante un cuadro de diálogo de impresión.
Desafortunadamente, esto puede ralentizar el proceso de impresión. Si la impresión en la aplicación debe ser más rápida de la que se puede lograr mediante la técnica estándar, debe implementar bandas manuales.
Bandas de impresión
Para implementar bandas manualmente, debe volver a implementar el bucle de impresión, de modo que se llame varias veces a OnPrint
por cada página (una vez por banda). El bucle de impresión se implementa en la función OnFilePrint
en viewprnt.cpp. En la clase derivada de CView
, sobrecargue esta función para que la entrada del mapa de mensajes para controlar el comando de impresión llame a la función de impresión. Copie la rutina OnFilePrint
y cambie el bucle de impresión para implementar bandas. Probablemente también querrá pasar el rectángulo de bandas a las funciones de impresión para que pueda optimizar el dibujo en función de la sección de la página que se va a imprimir.
En segundo lugar, debe llamar a QueryAbort
con frecuencia mientras dibuja la banda. De lo contrario, no se llamará al procedimiento Abort y el usuario no podrá cancelar el trabajo de impresión.
Vista previa de impresión: papel electrónico con interfaz de usuario
La vista previa de impresión, en esencia, intenta convertir la pantalla en una emulación de una impresora. De forma predeterminada, el área cliente de la ventana principal se usa para mostrar una o dos páginas totalmente dentro de la ventana. El usuario puede acercar un área de la página para verlo con más detalle. Con asistencia adicional, el usuario puede incluso tener permiso para editar el documento en modo de vista previa.
Personalización de la vista previa de impresión
Esta nota solo se ocupa de un aspecto de la modificación de la vista previa de impresión: agregar interfaz de usuario al modo de vista previa. Otras modificaciones son posibles, pero estos cambios están fuera del ámbito de esta discusión.
Para agregar la interfaz de usuario al modo de vista previa
Derive una clase de vista a partir de
CPreviewView
.Agregue controladores de comandos para los aspectos de la interfaz de usuario que desee.
Si va a agregar aspectos visuales a la pantalla, invalide
OnDraw
y realice el dibujo después de llamar aCPreviewView::OnDraw
.
OnFilePrintPreview
Este es el controlador de comandos para la vista previa de impresión. La implementación predeterminada es:
void CView::OnFilePrintPreview()
{
// In derived classes, implement special window handling here
// Be sure to Unhook Frame Window close if hooked.
// must not create this on the frame. Must outlive this function
CPrintPreviewState* pState = new CPrintPreviewState;
if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,
RUNTIME_CLASS(CPreviewView), pState))
{
// In derived classes, reverse special window handling
// here for Preview failure case
TRACE0("Error: DoPrintPreview failed");
AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
delete pState; // preview failed to initialize, delete State now
}
}
DoPrintPreview
ocultará el panel principal de la aplicación. Las barras de control, como la barra de estado, se pueden conservar especificándolas en el miembro pState->dwStates (se trata de una máscara de bits y los bits de las barras de control individuales se definen mediante AFX_CONTROLBAR_MASK( AFX_IDW_MYBAR)). La ventana pState->nIDMainPane es la ventana que se ocultará y volverá a mostrar automáticamente. DoPrintPreview
creará, a continuación, una barra de botones para la interfaz de usuario de la vista previa estándar. Si se necesita un control especial de ventanas, como ocultar u mostrar otras ventanas, debe realizarse antes de llamar a DoPrintPreview
.
De forma predeterminada, cuando finaliza la vista previa de impresión, devuelve las barras de control a sus estados originales y el panel principal para que sea visible. Si se necesita un control especial, debe realizarse mediante una invalidación de EndPrintPreview
. Si se produce un error en DoPrintPreview
, proporcione también un control especial.
Se llama a DoPrintPreview con:
Identificador de recurso de la plantilla de diálogo de la barra de herramientas de la vista previa.
Puntero a la vista para realizar la impresión de la vista previa.
Clase del entorno de ejecución de la clase de la vista previa. Esta se creará dinámicamente en DoPrintPreview.
Puntero CPrintPreviewState. Tenga en cuenta que la estructura de CPrintPreviewState (o la estructura derivada si la aplicación necesita más estado conservado) no debe crearse en el marco. DoPrintPreview es no modal y esta estructura debe sobrevivir hasta que se llame a EndPrintPreview.
Nota:
Si se necesita una vista o clase de vista independiente para la compatibilidad con la impresión, se debe pasar un puntero a ese objeto como segundo parámetro.
EndPrintPreview
Se llama a EndPrintPreview para finalizar el modo de vista previa de impresión. A menudo, es conveniente pasar a la página del documento que se mostró por última vez en la vista previa de impresión. EndPrintPreview
es la manera que tiene la aplicación de hacerlo. El miembro pInfo->m_nCurPage es la página que se mostró por última vez (la que está más a la izquierda si se mostraron dos páginas) y el puntero es una sugerencia sobre dónde estaba interesado el usuario en la página. Puesto que la estructura de la vista de la aplicación es desconocida para el marco de trabajo, debe proporcionar el código para pasar al punto elegido.
Debe realizar la mayoría de las acciones antes de llamar a CView::EndPrintPreview
. Esta llamada invierte los efectos de DoPrintPreview
y elimina pView, pDC y pInfo.
// Any further cleanup should be done here.
CView::EndPrintPreview(pDC, pInfo, point, pView);
CWinApp::OnFilePrintSetup
Este valor se debe asignar para el elemento de menú Configurar impresión. En la mayoría de los casos, no es necesario invalidar la implementación.
Nomenclatura de páginas
Otro problema es el de la numeración de páginas y el orden. En el caso de aplicaciones sencillas del tipo procesador de textos, se trata de un problema sencillo. La mayoría de los sistemas de vista previa de impresión suponen que cada página impresa corresponde a una página del documento.
A la hora de intentar proporcionar una solución generalizada, hay varias cosas que se deben tener en cuenta. Imagine un sistema CAD. El usuario tiene un dibujo que cubre varias hojas de tamaño E. En un trazador de tamaño E (u otro menor, escalado), la numeración de páginas sería como en el caso simple. Pero en una impresora láser, que imprime 16 páginas de tamaño A por hoja, ¿qué debe considerar la vista previa de impresión como una "página"?
Como indica el párrafo introductorio, la vista previa de impresión actúa como una impresora. Por lo tanto, el usuario verá lo que saldría de la impresora concreta seleccionada. Depende de la vista determinar qué imagen se imprime en cada página.
La cadena de descripción de página de la estructura CPrintInfo
proporciona un medio para mostrar el número de la página al usuario si se puede representar como un número por página (como en "Página 1" o "Páginas 1-2"). Esta cadena la usa la implementación predeterminada de CPreviewView::OnDisplayPageNumber
. Si se necesita una presentación diferente, puede invalidar esta función virtual para proporcionar, por ejemplo, "Hoja1, Secciones A, B".