I. TCanvas et Printer (épisode 1)▲
La première chose à dire sur le sujet est que l'impression avec Delphi est des plus simple. Tout passe par une instance unique de la classeTPrinter 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 !
function
Printer: TPrinter;
begin
if
FPrinter = nil
then
FPrinter := TPrinter.Create;
Result := FPrinter;
end
;
finalization
FPrinter.free; {libération automatique dans la partie finalization}
end
;
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 ajoût de l'unité Printers dans la clause uses 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.TextOut(50
, 50
, 'Ce que je veux imprimer'
);
// .....
Printer.EndDoc;
Vous connaissez plus simple ? Moi non ! Bien sur, 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 Delphi, rien de tout ça! 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! »
A 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 de d'écrire:
ImprimanteParDefaut := Printer.Printers[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 renvoie 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 pouce ! 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}
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 Delphi sur l'objet TCanvas.
TCanvas propose des propriétés, événements et méthodes qui simplifient la création d'image pour :
Spécifier le type de pinceau, de crayon et de fonte à utiliser
Dessiner et remplir diverses formes et lignes
Ecrire 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 codes. 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 ajouter l'unité Printers à la clause uses de votre code.
Placer ensuite sur votre feuille un TListBox que nous appelerons Imprimantes ainsi que 2 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
Imprimantes.Items := Printer.Printers;
// Sélectionner l'imprimante définie dans Windows
Imprimantes.ItemIndex := Printer.PrinterIndex;
Dans l'événement OnClick d'Imprimantes, donnons nous le moyen de choisir l'imprimante de sortie :
Printer.PrinterIndex := Imprimantes.ItemIndex;
Enfin, dans l'événement OnClick du bouton Episode1, nous allons créer le travail d'impression:
var
S: String
;
begin
With
Printer do
begin
{Démarrage de l'impression}
BeginDoc;
{Tracé de la zone imprimable}
Canvas.Rectangle(0
, 0
, PageWidth, PageHeight);
{Dans chaque coin de la feuille, nous allons écrire le texte 'Delphi c'est super'}
S := 'Delphi c''est super'
;
//Augmentons la taille de la fonte pour une meilleure visibilité
Canvas.font.Size := 12
;
// Ecrivons en haut à gauche
Canvas.TextOut(0
, 0
, S);
// en haut à droite. La position X sera donc égale à 0 + Largeur_de_la_page - Largeur_du_texte_à_imprimer
Canvas.TextOut(PageWidth - Canvas.TextWidth(S), 0
, S);
// en bas à gauche
Canvas.TextOut(0
, PageHeight - Canvas.TextHeight(S), S);
// en bas à droite
Canvas.TextOut(PageWidth - Canvas.TextWidth(S), PageHeight - Canvas.TextHeight(S), S);
// Enfin, au centre de la feuille
{Ici, on doit utiliser Round car les coordonnées X,Y doivent être des integer}
Canvas.TextOut(round((PageWidth - Canvas.TextWidth(S)) / 2
),
round((PageHeight - Canvas.TextHeight(S)) / 2
),
S);
{Envoi des commandes à l'imprimante}
EndDoc;
end
;
Vous n'avez plus qu'à tester! Vous pouvez téléchargé le code de cet exemple ICI.
La prochaine fois, nous parlerons plus en détail des API GetDeviceCaps, DrawText, CreateFont et TabbedTextOut.