III. L'API java existante▲
Le but de ce chapitre est de présenter succinctement l'API mise à la disposition d'un développeur voulant réaliser une impression en Java. Ce n'est en aucun cas une documentation complète.
III-A. Quoi imprimer ?▲
Pour l'impression, il faut tout d'abord un contenu. Pour cela, Java propose plusieurs interfaces dont Printable.
III-A-1. L'interface Printable▲
Cette interface ne définit qu'une seule méthode :
Méthode de rendu d'une page à imprimer.
int
print
(
Graphics graphics, PageFormat pageFormat, int
pageIndex) throws
PrinterException
- graphics: Contexte graphique pour le rendu de la page à imprimer.
- pageFormat: Informations sur le format de la page à imprimer comme la taille et l'orientation.
- pageIndex: Index de la page à imprimer
- Retourne Printable.PAGE_EXISTS si le rendu de la page s'est bien déroulée et Printable.NO_SUCH_PAGE si pageIndex spécifie une page non existante.
- PrinterException : Lancée quand l'impression est interrompue.
Ainsi pour vouloir imprimer une page contenant un simple rectangle entourant la page, suivie d'une page contenant une ellipse de même dimension, il suffit d'implémenter cette interface comme ceci :
import
java.awt.Color;
import
java.awt.Graphics;
import
java.awt.print.PageFormat;
import
java.awt.print.Printable;
import
java.awt.print.PrinterException;
public
class
PrintRectangle implements
Printable {
/** Constructeur par défaut de PrintRectangle */
public
PrintRectangle
(
) {
}
public
int
print
(
Graphics graphics, PageFormat pageFormat, int
pageIndex) throws
PrinterException {
// Par défaut, retourne NO_SUCH_PAGE => la page n'existe pas
int
retValue =
Printable.NO_SUCH_PAGE;
switch
(
pageIndex){
case
0
: {
// Dessin de la première page
// Récupère la dimension de la zone imprimable
double
xLeft =
pageFormat.getImageableX
(
);
double
yTop =
pageFormat.getImageableY
(
);
double
width =
pageFormat.getImageableWidth
(
);
double
height =
pageFormat.getImageableHeight
(
);
// Dessine le rectangle
graphics.setColor
(
Color.BLACK);
graphics.drawRect
((
int
)xLeft,
(
int
)yTop,
(
int
)width,
(
int
)height);
// La page est valide
retValue =
Printable.PAGE_EXISTS;
break
;
}
case
1
: {
// Dessin de la seconde page
// Récupère la dimension de la zone imprimable
double
xLeft =
pageFormat.getImageableX
(
);
double
yTop =
pageFormat.getImageableY
(
);
double
width =
pageFormat.getImageableWidth
(
);
double
height =
pageFormat.getImageableHeight
(
);
// Dessine l'ellipse
graphics.setColor
(
Color.BLACK);
graphics.drawOval
((
int
)xLeft,
(
int
)yTop,
(
int
)width,
(
int
)height);
// La page est valide
retValue =
Printable.PAGE_EXISTS;
break
;
}
}
return
retValue;
}
}
Cette implémentation teste d'abord l'index de la page à imprimer transmis à la méthode print.
Pour la première page (pageIndex = 0), les informations sur la zone imprimable de la page sont récupérées à l'aide du paramètre pageFormat, puis un rectangle est dessiné à l'aide du contexte graphique transmis.
La seconde page fait la même opération en remplaçant le rectangle par une ellipse.
Après chaque page rendue, la méthode retourne la constante Printable.PAGE_EXISTS pour indiquer le bon déroulement de l'impression. Dans le cas où l'index de page est invalide, il suffit de retourner Printable.NO_SUCH_PAGE.
II-A-2. L'interface Pageable▲
Dans l'exemple précédent, nous avons défini un Printable gérant 2 pages. Dans ce cas à plusieurs pages, il est préférable d'utiliser l'interface Pageable
qui représente un conteneur de Printable où chaque page peut choisir son format d'impression.
Cette interface définit 3 méthodes.
Méthode qui retourne le nombre de pages à imprimer.
int
getNumberOfPages
(
)
- Retourne le nombre de pages à imprimer ou Pageable.UNKOWN_NUMBER_OF_PAGES si ce nombre est indéterminé.
Méthode qui retourne le format de page pour une page donnée.
PageFormat getPageFormat
(
int
pageIndex) throws
IndexOutOfBoundsException
- pageIndex : Index de la page.
- Retourne les informations sur la taille et l'orientation de la page souhaitée pour cette page.
- IndexOutOfBoundsException : Lancée si pageIndex est erroné..
Méthode qui retourne l'objet de rendu pour une page donnée.
Printable getPrintable
(
int
pageIndex) throws
IndexOutOfBoundsException
- pageIndex : Index de la page.
- Retourne l'objet de rendu pour cette page.
- IndexOutOfBoundsException : Lancée si pageIndex est erroné..
III-B. Comment imprimer ?▲
III-B-1. La classe PrinterJob▲
Une fois défini le contenu à imprimer, il faut envoyer un travail d'impression à un service d'impression. Cette tâche est réalisée par la classe PrinterJob.
import
java.awt.print.PrinterException;
import
java.awt.print.PrinterJob;
public
class
Main {
/** Creates a new instance of Main */
public
Main
(
) {
}
/**
*
@param
args
the command line arguments
*/
public
static
void
main
(
String[] args) {
// Récupère un PrinterJob
PrinterJob job =
PrinterJob.getPrinterJob
(
);
// Définit son contenu à imprimer
job.setPrintable
(
new
PrintRectangle
(
));
// Affiche une boîte de choix d'imprimante
if
(
job.printDialog
(
)){
try
{
// Effectue l'impression
job.print
(
);
}
catch
(
PrinterException ex) {
ex.printStackTrace
(
);
}
}
}
}
La classe PrinterJob n'a pas de constructeur accessible. De ce fait, une instance de cette classe est obtenue en appelant sa méthode statique getPrinterJob(). Une fois, cette instance obtenue il est possible :
- de lui affecter un contenu à imprimer (setPrintable, setPageable,...).
- de demander à l'utilisateur de choisir l'imprimante où imprimer (printDialog,...).
- d'effectuer l'impression par la méthode print.
En exécutant, ce petit programme, vous devez voir apparaître cette boîte de dialogue :
Cette boîte est la boîte standard de configuration d'impression de l'OS (ici Windows). Vous pouvez sélectionner et configurer l'imprimante.
En appuyant sur Ok, vous imprimez 2 pages (l'une avec un rectangle et l'autre avec une ellipse) sur l'imprimante. L'appui sur Annuler, annule évidemment l'impression.
Et voilà, en quelques lignes de code, nous avons réussi à imprimer deux pages. Toutefois, toute la configuration de l'imprimante a été laissée au choix de l'utilisateur et c'est au rendu d'impression (l'implémentation de l'interface Printable) de s'adapter. Mais comment spécifier des préférences pour l'impression ? La solution est d'utiliser les requêtes d'impression ou PrintRequestAttribute.
III-B-1-a. Les PrintRequestAttribute ou requêtes d'impression▲
Basées sur la notion d'Attribute, les requêtes d'impression permettent aux développeurs de contrôler la configuration de l'impression.
L'interface javax.print.attribute.Attribute définit deux méthodes :
Méthode qui retourne la catégorie de cet attribut.
Class<
? extends
Attribute>
getCategory
(
)
- Retourne la classe de la catégorie de cet attribut.
Méthode qui retourne le nom de la catégorie de cet attribut.
String getName
(
)
- Retourne le nom de la catégorie de cet attribut.
Ces attributs peuvent être rangés dans un javax.print.attribute.AttributeSet où il ne peut y avoir au même instant qu'une seule (ou zéro) valeur d'une catégorie donnée. Par exemple, si on prend la catégorie javax.print.attribute.standard.Chromacity qui est la catégorie pour le choix entre l'impression noir & blanc et l'impression couleur. Cette catégorie ne contient que deux instances possibles : Chromacity.MONOCHROM et Chromacity.COLOR. Alors ces deux choix ne peuvent cohabiter dans un même set d'attributs ; c'est l'un ou l'autre ou aucun.
Cette notion étant utilisée à plusieurs endroits dans l'API d'impression de java, des familles d'attributs permettent de spécialiser les attributs pour des fonctions spécifiques. Ces familles sont matérialisées par un héritage de l'interface Attribute :
- DocAttribute : Catégorie d'attributs de configuration d'un document (notion non abordée ici)
- PrintJobAttribute : Catégorie d'attributs pour obtenir le statut ou d'autres caractéristiques d'un travail d'impression.
- PrintRequestAttribute : Catégorie d'attributs pour configurer une impression.
- PrintServiceAttribute : Catégorie d'attributs pour obtenir un statut ou d'autres caractéristiques d'un service d'impression (Un service d'impression peut être assimilé à une imprimante)
- SupportedValuesAttribute : Catégorie d'attributs pour récupérer les valeurs supportées par une autre catégorie d'attributs. Par exemple, il est possible de connaître les résolutions supportées par une imprimante.
Modifions l'exemple précédent :
import
java.awt.print.PrinterException;
import
java.awt.print.PrinterJob;
import
javax.print.attribute.HashPrintRequestAttributeSet;
import
javax.print.attribute.standard.OrientationRequested;
/**
*
*
*/
public
class
Main2 {
/** Constructeur par défaut de Main2 */
public
Main2
(
) {
}
/**
*
@param
args
the command line arguments
*/
public
static
void
main
(
String[] args) {
// TODO code application logic here
PrinterJob job =
PrinterJob.getPrinterJob
(
);
HashPrintRequestAttributeSet printRequestSet =
new
HashPrintRequestAttributeSet
(
);
printRequestSet.add
(
OrientationRequested.LANDSCAPE);
job.setPrintable
(
new
PrintRectangle
(
));
if
(
job.printDialog
(
printRequestSet)){
try
{
job.print
(
);
}
catch
(
PrinterException ex) {
ex.printStackTrace
(
);
}
}
}
}
Exécutons-le. La boîte suivante s'affiche :
Ce n'est plus du tout la boîte de dialogue native du système mais au contraire une boîte spécifique à Java. Si on peut encore choisir l'imprimante, le bouton propriétés est grisé. Par contre, on peut voir dans l'onglet « Mise en page » que la demande d'impression en paysage a bien été prise en compte.
De plus quand l'utilisateur clique sur imprimer, le set de requêtes transmis à la méthode printDialog est mis à jour automatiquement pour refléter les choix de l'utilisateur. Il est donc possible à ce stade de connaître ces choix pour, par exemple, afficher un aperçu avant impression. Par contre, cette boîte ne permet plus de configurer les attributs spécifiques à une imprimante comme la sortie d'une page de garde, de l'agrafage des pages, etc...