Modifications basées sur les événements de page XPSC++
Quelle est l’approche événementielle en programmation ?
L’approche événementielle en programmation est un paradigme qui s’articule autour du concept d’événements et de leur gestion. Dans ce modèle, le flux du programme est déterminé par des événements, qui peuvent être des actions de l’utilisateur (comme des clics de souris ou des pressions sur des touches), des notifications générées par le système ou des messages provenant d’autres applications. Voici quelques aspects clés de l’approche événementielle :
Événements : les événements représentent des occurrences significatives dans un programme. Ceux-ci peuvent inclure des interactions utilisateur, des modifications de données ou des messages provenant d’autres parties d’un système. Par exemple, un clic sur un bouton ou un fichier en cours de chargement peut déclencher des événements.
Écouteurs d’événements : pour répondre aux événements, les programmeurs utilisent des écouteurs d’événements (ou gestionnaires). Il s’agit de fonctions ou de méthodes définies pour s’exécuter lorsqu’un événement spécifique se produit. Par exemple, un écouteur d’événements peut être configuré pour exécuter une fonction lorsqu’un utilisateur clique sur un bouton.
Exécution asynchrone : le modèle basé sur les événements prend souvent en charge la programmation asynchrone, permettant aux programmes de rester réactifs en attendant que les événements se produisent. Par exemple, une application Web peut continuer à fonctionner en attendant les données d’un serveur.
Découplage : L’approche basée sur les événements favorise le découplage entre les différentes parties d’un programme. Les composants peuvent communiquer via des événements sans avoir besoin de connaître les détails de l’implémentation de chacun, ce qui rend le code plus modulaire et plus facile à maintenir.
Cas d’utilisation courants : la programmation basée sur les événements est largement utilisée dans les interfaces utilisateur graphiques (GUI), les applications Web et les systèmes qui nécessitent des interactions en temps réel. Les frameworks et bibliothèques comme Node.js, React et bien d’autres utilisent des modèles basés sur les événements.
Gestion de l’état : dans un système piloté par événements, la gestion de l’état peut être cruciale puisque l’application peut se trouver dans différents états en fonction des interactions ou des événements de l’utilisateur. Des stratégies de gestion d’état appropriées sont souvent utilisées pour garantir que l’application se comporte comme prévu.
Dans l’ensemble, l’approche basée sur les événements constitue un moyen puissant de gérer les interactions et les flux de travail au sein d’un programme, ce qui la rend particulièrement efficace pour les applications nécessitant réactivité et interaction de l’utilisateur.
Événements qui se produisent lors de la conversion du document XPS
Lorsque vous devez apporter des modifications à une page spécifique d’un document XPS à l’aide de l’API Aspose.Page, vous sélectionnez généralement le document actif (s’il existe plusieurs documents dans le fichier XPS), sélectionnez la page active, puis effectuez les modifications vous-même. .
Supposons maintenant que vous deviez apporter des modifications répétitives à toutes les pages d’un fichier XPS, puis convertir le résultat au format PDF ou au format image. Quelques exemples de tels changements incluent le placement d’un filigrane sur les pages ou l’ajout d’hyperliens de navigation. La manière directe d’effectuer de telles modifications consiste à parcourir les documents du package XPS, à parcourir les pages du document actif actuel, puis, enfin, à appliquer vos modifications. Par conséquent, le code pour accomplir cette tâche ressemblerait à ceci :
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 vous devez également effectuer des modifications irrégulières avant les modifications répétées, cette approche peut entraîner une certaine confusion ou des parcours excessifs à travers les documents et les pages, sans parler de ces boucles qui peuvent sembler un peu lourdes. Lorsque vous convertissez un document XPS en PDF ou en image, le processus se déroule page par page. Lorsque la tâche de conversion est prête à traiter la page suivante, elle déclenche un événement « avant la page ». L’utilisateur peut définir la gestion de tels événements en étendant la classe BeforePageSavingEventHandler, profitant ainsi de certains avantages décrits dans la section d’introduction de cet article.
Exemple d’ajout d’hyperliens de navigation
Nous fournirons ici un exemple lié au cas des hyperliens de navigation. Et pour rendre la tâche un peu plus compliquée, nous allons convertir uniquement un sous-ensemble de toutes les pages en PDF, comme spécifié par la propriété « PdfSaveOptions.PageNumbers ».
La classe du gestionnaire d’événements
Ci-dessous se trouve l’extension de la classe 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 classe de gestionnaire doit connaître les pages que nous souhaitons enregistrer au format PDF afin de créer les cibles de lien hypertexte correctes. Par conséquent, le constructeur doit prendre la propriété array des options comme argument. Si le tableau de numéros de page est spécifié, nous créons une collection triée de ceux-ci, en évitant en même temps les doublons. (Soit dit en passant, cette solution n’est pas tout à fait exacte. Pouvez-vous comprendre ce qui pourrait provoquer une incohérence dans la sortie ?) Nous aurons également besoin d’un objet « XpsFont » contenant les données de police pour le texte du lien hypertexte.
La méthode Handle()
remplacée est l’endroit où tout se passe. L’argument de la méthode est un objet qui contient l’API de modification pour la page actuelle, le numéro du document dans le package XPS, le numéro de page absolu dans tous les documents, le numéro de page relatif dans le document actuel (qui est égal au numéro précédent dans le cas d’un seul document dans le package), et le numéro de page de sortie (qui est égal au numéro de page absolu lorsque nous convertissons l’ensemble du package).
La logique des deux blocs « if » suivants est assez simple. Il est basé sur l’analyse de l’argument de l’événement OutputPageNumber
pour omettre certains liens le cas échéant : les liens [First]
et [Prev]
seront ajoutés à toutes les pages de sortie sauf la première, tandis que le Les liens [Suivant]
et [Dernier]
apparaîtront sur toutes les pages sauf la dernière. La logique est également adaptée aux deux cas, que les numéros de page soient spécifiés ou non.
Après les blocs « if », il y a un code pour ajouter un numéro de page dans le coin inférieur droit de la page.
La dernière ligne ajoute l’entrée de plan de la page, l’élément qui sera affiché dans le volet de navigation d’une visionneuse PDF (si pris en charge).
Le code de conversion
Maintenant que le gestionnaire d’événements “avant la page” est défini, nous pouvons écrire le code qui convertit le document :
Nous ouvrons un fichier XPS puis instancions un objet flux avec le fichier de données de police. Ensuite, nous créons une instance de la classe PdfSaveOptions
et spécifions le nombre de pages que nous devons convertir. La ligne suivante est l’endroit où le gestionnaire d’événements “page avant” devient “connecté” au travail de conversion via l’option de collection BeforePageSavingEventHandlers
.
Il ne reste plus qu’à exécuter la conversion en PDF en utilisant la méthode SaveAsPdf()
du document.
Conclusion
Dans cet article, nous avons exploré les points clés de l’approche basée sur les événements en programmation, examiné la méthode directe de modification des pages d’un document XPS et appris une technique plus avancée et sophistiquée pour apporter des modifications répétitives à toutes les pages de sortie au cours du processus. processus de conversion, en utilisant l’insertion d’hyperliens de navigation comme exemple. Pour les exemples complets, explorez notre Exemple de projet.