Modificaciones basadas en eventos de la página XPS | C++
¿Qué es el enfoque basado en eventos en la programación?
El enfoque basado en eventos en programación es un paradigma que gira en torno al concepto de eventos y manejo de eventos. En este modelo, el flujo del programa está determinado por eventos, que pueden ser acciones del usuario (como clics del mouse o pulsaciones de teclas), notificaciones generadas por el sistema o mensajes de otras aplicaciones. A continuación se presentan algunos aspectos clave del enfoque basado en eventos:
Eventos: Los eventos representan sucesos importantes en un programa. Estos pueden incluir interacciones del usuario, cambios en los datos o mensajes de otras partes de un sistema. Por ejemplo, un clic en un botón o la carga de un archivo pueden desencadenar eventos.
Escuchas de eventos: para responder a eventos, los programadores utilizan detectores de eventos (o controladores). Estas son funciones o métodos que están definidos para ejecutarse cuando ocurre un evento específico. Por ejemplo, se puede configurar un detector de eventos para ejecutar una función cuando un usuario hace clic en un botón.
Ejecución asincrónica: el modelo basado en eventos a menudo admite programación asincrónica, lo que permite que los programas sigan respondiendo mientras esperan que ocurran eventos. Por ejemplo, una aplicación web puede seguir funcionando mientras espera datos de un servidor.
Desacoplamiento: el enfoque basado en eventos promueve el desacoplamiento entre diferentes partes de un programa. Los componentes pueden comunicarse a través de eventos sin necesidad de conocer los detalles de la implementación de cada uno, lo que hace que el código sea más modular y más fácil de mantener.
Casos de uso comunes: la programación basada en eventos se usa ampliamente en interfaces gráficas de usuario (GUI), aplicaciones web y sistemas que requieren interacciones en tiempo real. Los marcos y bibliotecas como Node.js, React y muchos otros utilizan patrones basados en eventos.
Gestión de estado: en un sistema controlado por eventos, la gestión del estado puede ser crucial ya que la aplicación puede estar en diferentes estados dependiendo de las interacciones o eventos del usuario. A menudo se emplean estrategias de gestión de estado adecuadas para garantizar que la aplicación se comporte como se espera.
En general, el enfoque basado en eventos es una forma poderosa de gestionar interacciones y flujos de trabajo dentro de un programa, lo que lo hace particularmente efectivo para aplicaciones que requieren capacidad de respuesta e interacción del usuario.
Eventos que ocurren durante la conversión de documentos XPS
Cuando necesita realizar cambios en una página específica de un documento XPS utilizando la API Aspose.Page, normalmente selecciona el documento activo (si hay varios documentos en el archivo XPS), selecciona la página activa y luego realiza los cambios ellos mismos.
Ahora, supongamos que necesita realizar cambios repetidos en todas las páginas de un archivo XPS y luego convertir el resultado a PDF o a un formato de imagen. Algunos ejemplos de dichos cambios incluyen colocar una marca de agua sobre las páginas o agregar hipervínculos de navegación. La forma directa de realizar dichos cambios implica recorrer los documentos del paquete XPS, recorrer las páginas del documento activo actual y luego, finalmente, aplicar los cambios. Por lo tanto, el código para realizar esta tarea quedaría de la siguiente manera:
1for (uint32_t i = 1; i <= document->DocumentCount(); i++)
2{
3 document->SelectActiveDocument(i);
4 for (uint32_t j = 1; j <= document->PageCount(); j++)
5 {
6 document->SelectActivePage(j);
7 // Your changes ...
8 }
9}
10document->SaveAsPdf(u"file-name.pdf", saveOptions);
Si también necesita realizar algunos cambios irregulares antes de los repetidos, este enfoque puede generar cierta confusión o recorridos excesivos a través de documentos y páginas, y mucho menos estos bucles pueden parecer un poco engorrosos. Cuando convierte un documento XPS a PDF o una imagen, el proceso ocurre página por página. Cuando el trabajo de conversión está listo para procesar la página siguiente, activa un evento de “página anterior”. El usuario puede definir el manejo de dichos eventos extendiendo la clase BeforePageSavingEventHandler, aprovechando así algunos de los beneficios descritos en la sección introductoria de este artículo.
Ejemplo de adición de hipervínculos de navegación
Aquí proporcionaremos un ejemplo relacionado con el caso de los hipervínculos de navegación. Y para complicar un poco más la tarea, convertiremos solo un subconjunto de todas las páginas a PDF, como lo especifica la propiedad PdfSaveOptions.PageNumbers
.
La clase de controlador de eventos
A continuación se muestra la extensión de la clase BeforePageSavingEventHandler
:
1 /// <summary>
2 /// The class to handle the before-page event while converting an XPS document.
3 /// </summary>
4 class NavigationInjector : public Aspose::Page::XPS::Features::EventBasedModifications::BeforePageSavingEventHandler
5 {
6 typedef NavigationInjector ThisType;
7 typedef Aspose::Page::XPS::Features::EventBasedModifications::BeforePageSavingEventHandler BaseType;
8
9 typedef ::System::BaseTypesInfo<BaseType> ThisTypeBaseTypesInfo;
10 RTTI_INFO_DECL();
11
12 public:
13
14 NavigationInjector(System::SharedPtr<Aspose::Page::XPS::XpsModel::XpsFont> font, System::ArrayPtr<int32_t> pageNumbers);
15
16 /// <summary>
17 /// The action itself to be triggered on a before-page event.
18 /// </summary>
19 /// <param name="args">The event arguments.</param>
20 void Handle(System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::BeforeSavingEventArgs<System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::PageAPI>>> args) override;
21
22 private:
23
24 System::SharedPtr<Aspose::Page::XPS::XpsModel::XpsFont> _font;
25 System::SharedPtr<System::Collections::Generic::SortedList<int32_t, int32_t>> _pageNumbers;
26
27 };
1ModifyXpsPageOnConversion::NavigationInjector::NavigationInjector(System::SharedPtr<Aspose::Page::XPS::XpsModel::XpsFont> font, System::ArrayPtr<int32_t> pageNumbers)
2{
3 _font = font;
4 if (pageNumbers == nullptr)
5 {
6 return;
7 }
8
9 // Turn the page number array into a sorted collection of unique values.
10 _pageNumbers = System::MakeObject<System::Collections::Generic::SortedList<int32_t, int32_t>>();
11 for (int32_t pn : pageNumbers)
12 {
13 _pageNumbers->idx_set(pn, 0);
14 }
15
16}
17
18void ModifyXpsPageOnConversion::NavigationInjector::Handle(System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::BeforeSavingEventArgs<System::SharedPtr<Aspose::Page::XPS::Features::EventBasedModifications::PageAPI>>> args)
19{
20 System::SharedPtr<PageAPI> api = args->get_ElementAPI();
21
22 System::SharedPtr<XpsGlyphs> glyphs;
23 // For all pages in the output PDF except the first one...
24 if (args->get_OutputPageNumber() > 1)
25 {
26 // ...insert a hyperlink to the first page...
27 glyphs = api->CreateGlyphs(_font, 15.f, 5.f, api->get_Height() - 10.f, u"[First]");
28 glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
29 glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? 1 : _pageNumbers->get_Keys()->idx_get(0)));
30 api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
31
32 // ...and to the previous page.
33 glyphs = api->CreateGlyphs(_font, 15.f, 60.f, api->get_Height() - 10.f, u"[Prev]");
34 glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
35 glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? args->get_AbsolutePageNumber() - 1 : _pageNumbers->get_Keys()->idx_get(args->get_OutputPageNumber() - 2)));
36 api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
37 }
38
39 // For all pages in the output PDF except the last one...
40 if ((_pageNumbers != nullptr && args->get_OutputPageNumber() < _pageNumbers->get_Count()) || (_pageNumbers == nullptr && args->get_OutputPageNumber() < api->get_TotalPageCount()))
41 {
42 // ...insert a hyperlink to the next page...
43 glyphs = api->CreateGlyphs(_font, 15.f, 110.f, api->get_Height() - 10.f, u"[Next]");
44 glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
45 glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? args->get_AbsolutePageNumber() + 1 : _pageNumbers->get_Keys()->idx_get(args->get_OutputPageNumber())));
46 api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
47
48 // ...and to the last page.
49 glyphs = api->CreateGlyphs(_font, 15.f, 160.f, api->get_Height() - 10.f, u"[Last]");
50 glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Blue()));
51 glyphs->set_HyperlinkTarget(System::MakeObject<XpsPageLinkTarget>(_pageNumbers == nullptr ? api->get_TotalPageCount() : _pageNumbers->get_Keys()->idx_get(_pageNumbers->get_Keys()->get_Count() - 1)));
52 api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
53 }
54
55 // Insert a page number in the bottom-right corner.
56 glyphs = api->CreateGlyphs(_font, 15.f, api->get_Width() - 20.f, api->get_Height() - 10.f, System::Convert::ToString(args->get_OutputPageNumber()));
57 glyphs->set_Fill(api->CreateSolidColorBrush(System::Drawing::Color::get_Black()));
58 api->Add<System::SharedPtr<XpsGlyphs>>(glyphs);
59
60 // Add an outline entry to display the links to the converted pages in the navigation pane of a PDF viewer.
61 api->AddOutlineEntry(System::String::Format(u"Page {0}", args->get_OutputPageNumber()), 1, args->get_AbsolutePageNumber());
62}
La clase de controlador debe conocer las páginas que queremos guardar como PDF para poder crear los destinos de hipervínculo correctos. Por lo tanto, el constructor debe tomar la propiedad de matriz de opciones como argumento. Si se especifica la matriz de números de página, creamos una colección ordenada de ellos, evitando duplicados al mismo tiempo. (Por cierto, esta solución no es del todo precisa. ¿Puedes descubrir qué podría causar inconsistencia en la salida?) También necesitaremos un objeto XpsFont
que contenga los datos de fuente para el texto del hipervínculo.
El método Handle()
anulado es donde sucede todo. El argumento del método es un objeto que contiene la API de modificación para la página actual, el número de documento dentro del paquete XPS, el número de página absoluto en todos los documentos, el número de página relativo dentro del documento actual (que es igual al número anterior en caso de que solo haya un documento en el paquete) y el número de página de salida (que es igual al número de página absoluto cuando convertimos el paquete completo).
La lógica de los siguientes dos bloques “if” es bastante sencilla. Se basa en el análisis del argumento del evento OutputPageNumber
para omitir algunos de los enlaces cuando corresponda: los enlaces [First]
y [Prev]
se agregarán a todas las páginas de salida excepto a la primera, mientras que Los enlaces [Siguiente]
y [Último]
aparecerán en todas las páginas excepto en la última. La lógica también se adapta a ambos casos, ya sea que se especifiquen los números de página o no.
Después de los bloques “if”, hay un código para agregar un número de página en la esquina inferior derecha de la página.
La última línea agrega la entrada del esquema de la página, el elemento que se mostrará en el panel de navegación de un visor de PDF (si es compatible).
El código de conversión
Ahora que el controlador de eventos “antes de la página” está definido, podemos escribir el código que convierte el documento:
Abrimos un archivo XPS y luego creamos una instancia de un objeto de flujo con el archivo de datos de fuente. A continuación, creamos una instancia de la clase PdfSaveOptions
y especificamos el número de páginas que necesitamos convertir. La siguiente línea es donde el controlador de eventos “antes de la página” se “conecta” al trabajo de conversión a través de la opción de colección BeforePageSavingEventHandlers
.
Todo lo que queda por hacer es ejecutar la conversión a PDF usando el método SaveAsPdf()
del documento.
Conclusión
En este artículo, exploramos los puntos clave del enfoque basado en eventos en programación, examinamos el método directo para modificar páginas de un documento XPS y aprendimos una técnica más avanzada y sofisticada para realizar cambios repetidos en todas las páginas de salida durante el proceso. proceso de conversión, utilizando como ejemplo la inserción de hipervínculos de navegación. Para ver los ejemplos completos, explore nuestro Proyecto de ejemplo.