Stampare in Java
Date le pressanti richieste, ho deciso di scrivere un piccolo tutorial su come stampare in Java. La stampa è, da sempre, il fine ultimo delle applicazioni WYSIWYG per sistemi operativi visuali. Java però ha incluso i metodi per supportarla solo dalla release 1.1 del JDK, formalizzandola nella 1.2.
Sommario
La via di Java per la stampa
Indice
Metodo print(...)
Il metodo print, definito nell'interfaccia java.awt.print.Printable ha questa firma:
public int print(Graphics graphics,
PageFormat pageFormat,
int pageIndex)
throws PrinterException
Questo è un metodo, come detto, callback, nel senso che verrà chiamato dal sistema. Ma come fare a dire quante pagine bisogna stampare? Tramite il valore di ritorno della nostra funzione. Finchè ritorneremo PAGE_EXISTS il sistema stamperà la pagina e, successivamente, richiamerà la nostra funzione incrementando il contatore int pageIndex. Quando avremo finito restiuiremo NO_SUCH_PAGE.
Diamo un occhiata ai parametri che, ricordiamolo, ci vengono passati dall'ambiente (nella fattispecie da java.awt.print.PrinterJob):
Graphics graphics
| Il contesto grafico su cui disegnare.
|
PageFormat pageFormat
| Il formato della pagina (in che modo è messa la carta? quanto è grande? etc...)
|
int pageIndex
| Il numero di pagina che l'ambiente chiede sia preparata.
|
Il significato di questi parametri dovrebbe essere ovvio, eccetto per PageFormat che vedremo brevemente in seguito.
Ultima cosa da notare è che siamo in grado di generare l'eccezione java.awt.print.PrinterException in caso si verifichi un errore. L'eccezione, come sempre, sarà catturata dal codice che chiama java.awt.print.PrinterJob.print().
Perfetto! Ora sappiamo che il sistema chiamerà il nostro metodo print in continuazione fino a quando noi diremo basta (restituendo NO_SUCH_PAGE). Resta da capire come utilizzare il parametro PageFormat che sembra un pò intimidante...
Indice
PageFormat
Se credevate di poter lavorare nello stesso modo che utilizzate per lo schermo rimarrete delusi. Per iniziare a odiare i progettisti pensate che:
- Non sapete a priori dove inizi la parte stampabile (dimenticate lo 0,0 degli assi cartesiani tanto caro all'AWT!)
- Non sapete a priori dove finisca la parte stampabile.
Tuttavia Java vi fornisce tutti gli elementi necessari per essere a conoscenza del formato della pagina. I metodi più importanti sono:
double
| getImageableHeight()
| Restituisce l'altezza della pagina. In 1/72 di pollice.
|
double
| getImageableWidth()
| Restituisce la larghezza della pagina. In 1/72 di pollice.
|
double
| getImageableX()
| Restituisce la coordinata X iniziale della pagina. In 1/72 di pollice.
|
double
| getImageableY()
| Restituisce la coordinata Y iniziale della pagina. In 1/72 di pollice.
|
int (orientamento)
| getOrientation()
| Restituisce l'orientamento della pagina. E' una costante fra java.awt.print.PageFormat.LANDSCAPE, java.awt.print.PageFormat.PORTRAIT e java.awt.print.PageFormat.REVERSE_LANDSCAPE.
|
Grazie a questi metodi è possibile conoscere i limiti in cui disegnare. Da notare è che Java (o meglio la classe java.awt.Graphics) esegue il clipping. Ciò vuol dire che se disegnate all'esterno del rettangolo specificato da java.awt.print.PageFormat i pixel verranno automaticamente eliminati.
Indice
PrinterJob
Ora che sappiamo come creare le pagine da stampare ci manca un modo per iniziare la stampa. Java mette a disposizione la classe java.awt.print.PrinterJob per questo. Notiamo subito che il costruttore è pubblico però ci viene consigliato dall'help di usare il metodo statico java.awt.print.PrinterJob.getPrinterJob() che restituisce il PrinterJob di sistema. Questa prassi è necessaria per serializzare le formattazioni di pagina. Dopo questo notiamo che ci sono due categorie di metodi: quelli prestampa e quelli atti a controllare una stampa in corso. Vediamo brevemente i più comuni dei due:
Metodi prestampa
String
| getUserName()
| Restituisce il nome dell'utente che inizia la stampa (cioè chi ha fatto il logon di sistema).
|
void
| setJobName(String jobName)
| Imposta il nome del processo di stampa (in Windows è quello che appare in gestione stampanti).
|
String
| getJobName()
| Rileva il nome del processo di stampa (in Windows è quello che appare in gestione stampanti).
|
void
| setPrintable(Printable painter)
| Imposta la classe (che implementa l'interfaccia java.awt.print.Printable) responsabile della creazione delle pagine di stampa.
|
PageFormat
| validatePage(PageFormat page)
| Questo metodo, utilissimo, riceve un PageFormat e ne ritorna uno compatibile con la stampante selezionata il più possibile simile.
|
PageFormat
| pageDialog(PageFormat page)
| Questo metodo invoca la finestra di dialogo di selezione del formato della pagina. In caso di ritorno di null l'utente ha annullato la selezione.
|
void
| setCopies(int copies)
| Imposta il numero di copie da stampare.
|
Stampa in corso
void
| cancel()
| Questo metodo interrompe il processo di stampa in corso. Nota: è un metodo serializzato. Ciò vuol dire che ritornerà immediatamente anche se non è detto che la stampa venga interrotta subito. Assicura comunque che la stampa venga interrotta alla prima occasione.
|
boolean
| isCancelled()
| Ritorna true se e solo se il processo di stampa sarà interrotto alla prima occasione. In tutti gli altri casi ritorna false.
|
Indice
Un esempio funzionante
Se siete arrivati fino a qui vuol dire che tutto vi è chiaro (e che il mio italiano non è poi così orribile... :) . Adesso vedremo come mettere tutto insieme per un programmino che stampa. Nulla di più e nulla di meno.
Prima però ripetete con me i passi per arrivare allo scopo:
- Implementare java.awt.print.Printable e nello specifico il metodo java.awt.print.Printable.print(...).
- Ottenere un oggetto java.awt.print.PrinterJob.
- Passare al PrinterJob la nostra classe con java.awt.print.Printable.Print().
- Chiamare java.awt.print.PrinterJob.print() e aspettare.
Nota bene: Per risparmiarvi lo sbattimento di copiare il codice (ahhh! Io lo facevo ai gloriosi tempi dello Speccy! :-) scaricatevi il codice completo.
Passo 1: Implementare Printable
Creiamo una nuova classe e procediamo (il codice di riferimento è qui):
import java.awt.print.*;
import java.awt.*;
public class MindPrint implements Printable
{
public int print(Graphics grap,
PageFormat pageFormat, int pageIndex) throws PrinterException
{
Vogliamo stampare una sola pagina: quindi controlliamo pageIndex e restituiamo NO_SUCH_PAGE se è maggiore di zero.
if(pageIndex > 0)
return NO_SUCH_PAGE;
Scriviamo qualcosa. Notate come non possiamo assumere l'origine degli assi a (0,0) ma dobbiamo avvalerci dei metodi della classe PageFormat.
grap.drawString("Ready to roll out!", (int)pageFormat.getImageableX(),
(int)pageFormat.getImageableY()+5);
grap.setColor(Color.blue);
grap.drawLine((int)pageFormat.getImageableX(), (int)pageFormat.getImageableY(),
(int)pageFormat.getImageableWidth(), (int)pageFormat.getImageableHeight());
Ora che abbiamo creato questa bellissima pagina diciamo al sistema che è pronta per essere stampata.
return PAGE_EXISTS;
}
Passi 2,3 e 4: Stampiamo!
Creiamo una classe consolle (anche se non è ovviamente necessario). Se volete il codice di riferimento cliccate qui.
import java.awt.print.*;
public class TestPrint
{
public static void main(String ag[]) throws Exception
{
Passo 2!
PrinterJob pj = PrinterJob.getPrinterJob();
Passi opzionali...
pj.setJobName("MindFlavor's Java test.");
System.out.println("Job name == " + pj.getJobName());
System.out.println("User name == " + pj.getUserName());
pj.printDialog();
Passo 3!
pj.setPrintable(new MindPrint());
Passo 4 e incrociamo le dita! ;-)
pj.print();
System.exit(-1);
}
}
Indice
|