Расширенная графическая система Java 2D предлагает новые интерфейсы и классы для печати, собранные в пакет java.awt.print. Эти классы полностью перекрывают все стандартные возможности печати библиотеки AWT. Более того, они удобнее в работе и предлагают дополнительные возможности. Если этот пакет установлен в вычислительной системе, то, безусловно, нужно применять его, а не стандартные средства печати AWT.
Как и стандартные средства AWT, методы классов Java 2D выводят на печать содержимое графического контекста, заполненного методами класса Graphics или класса Graphics2D.
Всякий класс Java 2D, собирающийся печатать хотя бы одну страницу текста, графики или изображения называется классом, рисующим страницы (page painter). Такой класс должен реализовать интерфейс Printable. В этом интерфейсе описаны две константы и только один метод print(). Класс, рисующий страницы, должен реализовать этот метод. Метод print() возвращает целое типа int и имеет три аргумента:
print(Graphics g, PageFormat pf, int ind);
Первый аргумент g — это графический контекст, выводимый на лист бумаги, второй аргумент pf — экземпляр класса PageFormat, определяющий размер и ориентацию страницы, третий аргумент ind — порядковый номер страницы, начинающийся с нуля.
Метод print () класса, рисующего страницы, заменяет собой метод paint (), использовавшийся стандартными средствами печати AWT. Класс, рисующий страницы, не обязан расширять класс Frame и переопределять метод paint (). Все заполнение графического контекста методами класса Graphics или Graphics2D теперь выполняется в методе print ().
Когда печать страницы будет закончена, метод print () должен возвратить целое значение, заданное константой PAGE_EXISTS. Будет сделано повторное обращение к методу print () для печати следующей страницы. Аргумент ind при этом возрастет на 1. Когда ind превысит количество страниц, метод print() должен возвратить значение NO_SUCH_PAGE, что служит сигналом окончания печати.
|
Следует помнить, что система печати может несколько раз обратиться к методу paint () для печати одной и той же страницы. При этом аргумент ind не меняется, а метод print () должен создать тот же графический контекст.
Класс PageFormat определяет параметры страницы. На странице вводится система координат с единицей длины 1/72 дюйма, начало которой и направление осей определяется одной из трех констант:
• PORTRAIT — начало координат расположено в левом верхнем углу страницы, ось Ох направлена вправо, ось Оу — вниз;
• LANDSCAPE — начало координат в левом нижнем углу, ось Ох идет вверх, ось Оу — вправо;
• REVERSE_LANDSCAPE — начало координат в правом верхнем углу, ось Ох идет вниз, ось Оу — влево.
Большинство принтеров не может печатать без полей, на всей странице, а осуществляет вывод только в некоторой области печати (imageable area), координаты левого верхнего угла которой возвращаются методами getImageableX() и getImageableY(), а ширина и высота — методами getImageableWidth() и getImageableHeight().
Эти значения надо учитывать при расположении элементов в графическом контексте, например, при размещении строк текста методом drawString ().
В классе только один конструктор по умолчанию PageFormat(), задающий стандартные параметры страницы, определенные для принтера по умолчанию вычислительной системы.
Метод pageDialog(PageDiaiog pd) открывает на экране стандартное окно Параметры страницы (Page Setup) операционной системы, в котором уже заданы параметры, определенные в объекте pd. Если пользователь выбрал в этом окне кнопку Отмена, то возвращается ссылка на объект pd, если кнопку ОК, то создается и возвращается ссылка на новый объект. Объект pd в любом случае не меняется. Он обычно создается конструктором.
|
Можно задать параметры страницы и из программы, но тогда следует сначала определить объект класса Paper конструктором по умолчанию:
Paper р = new Paper()
Затем методами
p.setSize(double width, double height)
p.setlmageableArea(double x, double y, double width, double height)
задать размер страницы и области печати.
Потом определить объект класса pageFormat с параметрами по умолчанию:
PageFormat pf = new PageFormat()
и задать новые параметры методом
pf.setPaper(p)
Теперь вызывать на экран окно "Параметры страницы" методом pageDialog() уже не обязательно. Так делается в тех случаях, когда печать выполняется на фоне отдельным подпроцессом.
Итак, параметры страницы определены, метод print () — тоже. Теперь надо дать задание на печать (print job) — указать количество страниц, их номера, порядок печати страниц, количество копий. Все эти сведения собираются в классе PrinterJob.
Система печати Java 2D различает два вида заданий. В более простых заданиях — Printable Job — есть только один класс, рисующий страницы, поэтому у всех страниц одни и те же параметры, страницы печатаются последовательно с первой по последнюю или с последней страницы по первую, это зависит от системы печати.
Второй, более сложный вид заданий — Pageable Job — определяет для печати каждой страницы свой класс, рисующий страницы, поэтому у каждой страницы могут быть собственные параметры. Кроме того, можно печатать не все, а только выбранные страницы, выводить их в обратном порядке, печатать на обеих сторонах листа. Для осуществления этих возможностей определяется экземпляр класса Book или создается класс, реализующий интерфейс Pageable.
|
В классе Book, опять-таки, один конструктор, создающий пустой объект:
Book b = new Book()
После создания в данный объект добавляются классы, рисующие страницы. Для этого в классе Book есть два метода:
append (Printable p, PageFormat pf) —добавляет объект р в конец;
append(Printable p, PageFormat pf, int numPages) — добавляет numPages экземпляров р в конец; если число страниц заранее неизвестно, то задается константа UNKNOWN_NUMBER_OF_PAGES.
При составлении задания на печать, т. е. после создания экземпляра класса PrinterJob, надо указать вид задания одним и только одним из трех методов этого класса setPrintable(Printable pr), setPrintable(Printable pr, PageFormat pf) или setPageble (Pageable pg). Заодно задаются один или несколько классов рг, рисующих страницы в этом задании.
Остальные параметры задания можно задать в стандартном диалоговом окне Печать (Print) операционной системы, которое открывается на экране при выполнении логического метода printoiaiog (). Указанный метод не имеет аргументов. Он возвратит true, когда пользователь щелкнет по кнопке ОК, и false после нажатия кнопки Отмена.
Остается задать число копий, если оно больше 1, методом setCopies(int n) и задание сформировано.
Еще один полезный метод defaultPage() класса PrinterJob возвращает объект класса PageFormat по умолчанию. Этот метод можно использовать вместо конструктора класса PageFormat.
Осталось сказать, как создается экземпляр класса PrinterJob. Поскольку этот класс тесно связан с системой печати компьютера, его объекты создаются не конструктором, а статическим методом getPrinterJob(), Имеющимся в том же самом классе Printer Job.
Начало печати задается методом print () класса PrinterJob. Этот метод не имеет аргументов. Он.последбвательно вызывает методы print (g, pf, ind) классов, рисующих страницы, для каждой страницы.
Пример:
import java.awt.*;
import java.awt.geom.*;
import java.awt.print.*;
class Print2Test implements Printable{
public int print(Graphics g, PageFormat pf, int ind) throws PrinterException
{ // Печатаемнеболее 5 страниц
if (ind > 4) return Printable. NO_SUCH_PAGE;
Graphics2D g2 = (Graphics2D)g;
g2.setFont(new Font("Serif", Font. ITALIC, 30));
g2.setColor (Color. black);
g2.drawString("Page " + (ind + 1), 100, 100);
g2.draw(new Ellipse2D.Double(100, 100, 200, 200));
return Printable. PAGE_EXISTS;
}
public static void main(String[] args){
// 1. Создаемэкземплярзадания
PrinterJob pj = PrinterJob. getPrinterJob ();
// 2, ОткрываемдиалоговоеокноПараметрыстраницы
PageFormat pf = pj.pageDialog (pj.defaultPage());
// 3. Задаемвидзадания, объекткласса, рисующегостраницу,
// и выбранныепараметрыстраницы
pj.setPrintable(new Print2Test(), pf);
// 4. Еслинужнонапечататьнесколькокопий, то:
pj.setCopies(2); // Поумолчаниюпечатаетсяоднакопия
// 5. ОткрываемдиалоговоеокноПечать (необязательно)
if (pj.printDialog()){ // Если OK...
try {
pj.print(); // Обращается к print(g, pf, ind)
}
catch (Exception e)
{
System. err. println(e);
}
}
// 6. Завершаемзадание
System. exit (0);
}
}
Печать файла
Печать текстового файла заключается в размещении его строк в графическом контексте методом drawString (). При этом необходимо проследить за правильным размещением строк в области печати и разбиением файла на страницы.
Пример печати текстового файла, имя которого задается в командной строке. Из файла читаются готовые строки, программа не сравнивает их длину с шириной области печати, не выделяет абзацы. Вывод производится в локальной кодировке.
import java.awt.*;
import java.awt.print.*;
import java.io.*;
public class Print2File{
public static void main(String[] args)
{
if (args.length < 1){
System.err.println("Usage: Print2File path");
System.exit(0);
}
PrinterJob pj = PrinterJob.getPrinterJob();
PageFormat pf = pj.pageDialog(pj.defaultPage());
pj.setPrintable(new FilePagePainter(args[0]), pf);
if (pj.printDialog()){
try{
pj.print();
}
catch(PrinterException e){}
}
System.exit(0);
}
}
class FilePagePainter implements Printable{
private BufferedReader br;
private String file;
private int page = -1;
private boolean eof;
private String[] line;
private int numLines;
public FilePagePainter(String file){
this.file = file;
try{
br = new BufferedReader(new FileReader(file));
}
catch(IOException e){ eof = true; }
}
public int print(Graphics g, PageFormat pf, int ind)throws PrinterException{
g.setColor(Color.black);
g.setFont(new Font("Serif", Font.PLAIN, 10));
int h = (int)pf.getImageableHeight();
int x = (int)pf.getImageableX() + 10;
int y = (int)pf.getImageableY() + 12;
try{
// Если система печати запросила эту страницу первый раз
if (ind!= page){
if (eof) return Printable.NO_SUCH_PAGE;
page = ind;
line = new String[h/12]; // Массив строк на странице
numLines =0; // Число строк на странице
// Читаем строки из файла и формируем массив строк
while (y + 48 < pf.getImageableY() + h)
{
line[numLines] = br.readLine();
if (line[numLines] == null){eof = true; break; }
numLines++;
y += 12;
}
}
// Размещаем колонтитул
y = (int)pf.getImageableY() + 12;
g.drawString("Файл: " + file + ", страница " + (ind + 1), x, y);
// Оставляем две пустые строки
y += 36;
// Размещаем строки текста текущей страницы
for (int i = 0; i < numLines; i++){
g.drawString(line[i], x, y);
y += 12;
}
return Printable.PAGE_EXISTS;
}catch(IOException e){
return Printable.NO_SUCH_PAGE;
}
}
}