I. TCanvas et Printer (épisode 1)▲
La première chose à dire sur le sujet est que l'impression avec C++ Builder est des plus simples. Tout passe par une instance unique de la classe TPrinter qui s'obtient par la fonction Printer de l'unité Printers. L'unicité de Printer est nécessaire à cause de son utilisation intensive des API Windows (de façon transparente pour l'utilisateur). Ce modèle est une possibilité d'implémentation de la Design Pattern connue sous le nom de singleton. Voici un extrait de l'unité Printers !
// Appel de la fonction Printer: TPrinter;
TPrinter *
Prntr =
Printer();
Prntr->
BeginDoc();
// .....
Prntr->
EndDoc(); //libération automatique dans la partie finalisation
Puisque Printer est en fait une fonction de l'unité Printers, vous y avez accès directement dans votre code. On ne crée pas un objet Printer comme on crée un objet courant par sa méthode create. Le simple ajout de Printers.hpp dans l'entête de votre code vous donne accès à Printer. Alors, comment l'utiliser ? On demande à Printer de commencer une impression, on envoie les commandes désirées et on termine l'impression. C'est aussi simple que cela ! Sous forme de code, cela donne :
Printer()->
BeginDoc();
Printer()->
Canvas->
TextOutA(50
, 50
, " Ce que je veux imprimer "
);
// .....
Printer()->
EndDoc();
Vous connaissez plus simple ? Moi non ! Bien sûr, on ne peut se contenter de cela. Voyons maintenant les propriétés les plus importantes de Printer.
Comme vous le savez, Windows permet l'installation de plusieurs imprimantes. Pour connaitre la liste des imprimantes installées sur l'ordinateur, les utilisateurs de certains langages doivent utiliser des API du style EnumFont et des procédures de callback. Avec C++ Builder, rien de tout çab ! Les imprimantes installées sont répertoriées dans la propriété Printers (TStrings). Ainsi, pour afficher cette liste dans un composant du type TListBox, on placera le composant TListBox sur la feuille et on écrira :
ListBox1->
Items =
Printer()->
Printers;
Vous me direz : « C'est bien d'avoir la liste, mais comment savoir quelle imprimante est utilisée actuellement par défaut et comment choisir dans mon code celle qui m'intéresse pour une impression bien définie ! »
À cela je répondrai : PrinterIndex ! La valeur de PrinterIndex indique l'imprimante par défaut pour Windows. Donc, pour connaitre le nom de l'imprimante, il suffira d'écrire :
ImprimanteParDefaut =
Printer()->
Printers->
Strings[Printer()->
PrinterIndex];
Pour utiliser une imprimante de la liste dans votre code, il suffit de modifier la valeur de PrinterIndex en lui affectant l'index correspondant dans la liste. On écrira par exemple :
Printer()->
PrinterIndex =
1
;
Note : pour revenir à l'imprimante par défaut de Windows, on affectera à PrinterIndex la valeur -1 !
Bien ! Cette base étant établie, nous allons voir maintenant les propriétés PageHeight et PageWidth. Vous l'aurez compris, elles nous fournissent la hauteur et la largeur de la feuille à imprimer, définies par le choix du format de papier utilisé (A3, A4, etc.).
PageHeight et PageWidth renvoient des valeurs en pixels. Il faut savoir que l'objet Printer ne connait que les pixels. Inutile de lui parler en millimètres ou en pouces ! Comment sont définies les valeurs de PageHeight et PageWidth ? Tout simplement par utilisation de l'API GetDeviceCaps (que nous utiliserons plus tard).
// Vous n'avez pas à utiliser cette API. Printer le fait pour vous
Int PageHeight =
GetDeviceCaps(Printer()->
Handle, HORZRES);
Mais ça, c'est Printer qui s'en charge. Vous vous contentez de lui demander le résultat. Chose intéressante, c'est que les valeurs tiennent compte des zones non imprimables sur la feuille. Selon l'imprimante utilisée, une certaine zone en bordure de feuille n'est pas accessible à la tête d'impression. PageWidth et PageHeight fournissant la largeur et la hauteur de la zone imprimable, il peut-être intéressant de connaitre la taille de cette zone. Prenons par exemple le cas d'une impression de texte qui devra toujours débuter à 5 centimètres du bord gauche de la feuille, et ce, quelle que soit l'imprimante utilisée. Il faudra alors tenir compte de cette partie plus ou moins grande. Là, nous utiliserons aussi GetDeviceCaps. Pour le détail du calcul, je vous renvoie à 'Coordonnées imprimante en millimètres' où je décris le calcul à effectuer.
La dernière propriété que nous allons voir est la plus importante à mes yeux, puisque c'est elle qui va faire 95 % du travail d'impression. Je veux parler du Canvas. Le Canvas représente la surface d'impression de la page. Comme pour un composant TImage, ou le Canvas d'une TForm, l'objet Printer implémente un Canvas. Voici ce que dit l'aide C++ Builder sur l'objet TCanvas.
TCanvas propose des propriétés, événements et méthodes qui simplifient la création d'images pour : spécifier le type de pinceau, de crayon et de fonte à utiliser, dessiner et remplir diverses formes et lignes, écrire du texte, restituer des images graphiques, définir la réponse aux modifications de l'image en cours.
C'est donc sur ce Canvas que nous enverrons nos commandes. En fait, nous allons utiliser ce Canvas exactement comme le Canvas d'un composant TImage (ce qui nous sera très utile dans l'épisode 4 quand nous parlerons de l'aperçu avant impression).
Nous allons terminer ce premier épisode pour débutant en écrivant quelques lignes de code. Pour cela, nous allons ajouter à notre palette les méthodes TextWidth et TextHeight du Canvas. Elles renvoient respectivement la largeur et la hauteur du texte passé en paramètre.
Commencez par créer un nouveau projet et ajoutez Printers.hpp dans l'entête de votre code.
Placez ensuite sur votre feuille un TListBox que nous appellerons Imprimantes ainsi que deux boutons de commande Lister et Episode1.
Dans l'événement OnCLick du bouton Lister, écrivez le code suivant pour afficher la liste des imprimantes installées.
// Lister les imprimantes installées
ListBox1->
Items =
Printer()->
Printers;
// Sélectionner l'imprimante définie dans Windows
ListBox1->
ItemIndex =
Printer()->
PrinterIndex;
Dans l'événement OnClick d'Imprimantes, donnons-nous le moyen de choisir l'imprimante de sortie :
Printer()->
PrinterIndex =
ListBox1->
ItemIndex;
Enfin, dans l'événement OnClick du bouton Episode1, nous allons créer le travail d'impression :
AnsiString S;
// Démarrage de l'impression
Printer()->
BeginDoc();
// Tracé de la zone imprimable
TRect r =
Rect(0
, 0
,Printer()->
PageWidth, Printer()->
PageHeight);
// Dans chaque coin de la feuille, nous allons écrire le texte " C++ Builder c'est super"
S =
"C++ Builder c'est super"
;
//Augmentons la taille de la fonte pour une meilleure visibilité
Printer()->
Canvas->
Font->
Size =
12
;
// Écrivons en haut à gauche
Printer()->
Canvas->
TextOutA(0
, 0
, S);
// en haut à droite. La position X sera donc égale à 0 +
// Largeur_de_la_page - Largeur_du_texte_à_imprimer
Printer()->
Canvas->
TextOutA(Printer()->
PageWidth -
Printer()->
Canvas->
TextWidth(S), 0
, S);
// en bas à gauche
Printer()->
Canvas->
TextOutA(0
, Printer()->
PageHeight -
Printer()->
Canvas->
TextHeight(S), S);
// en bas à droite
Printer()->
Canvas->
TextOutA(Printer()->
PageWidth -
Printer()->
Canvas->
TextWidth(S),
Printer()->
PageHeight -
Printer()->
Canvas->
TextHeight(S), S);
// Enfin, au centre de la feuille
// Ici, on doit utiliser int car les coordonnées X,Y doivent être des integer
Printer()->
Canvas->
TextOutA(int
((Printer()->
PageWidth -
Printer()->
Canvas->
TextWidth(S))/
2
),
int
((Printer()->
PageHeight -
Printer()->
Canvas->
TextHeight(S))/
2
), S);
//Envoi des commandes à l'imprimante
Printer()->
EndDoc();
Vous n'avez plus qu'à tester ! Vous pouvez télécharger le code de cet exemple dans le zip en début et fin.
Dans le prochain chapitre, nous parlerons plus en détail des API GetDeviceCaps, DrawText, CreateFont et TabbedTextOut.