Печать на Java, часть 1

Назад 1 2 Страница 2 Страница 2 из 2

Модели рендеринга

В Java есть две модели печати: Printableзадания и Pageableзадания.

Печатные издания

Printableзадания являются более простыми из двух моделей печати. В этой модели используется только один PagePainterдля всего документа. Страницы отображаются последовательно, начиная с нулевой страницы. Когда будет напечатана последняя страница, вы PagePainterдолжны вернуть NO_SUCH_PAGEзначение. Подсистема печати всегда запрашивает, чтобы приложение отображало страницы последовательно. Например, если вашему приложению предлагается отобразить страницы с пятой по седьмую, подсистема печати запросит все страницы до седьмой страницы, но распечатает только страницы пятую, шестую и седьмую. Если ваше приложение отображает диалоговое окно печати, общее количество страниц, которые нужно напечатать, не будет отображаться, поскольку с помощью этой модели невозможно узнать заранее количество страниц в документе.

Таблицы страниц

PageableЗадания предлагают большую гибкость, чем Printableзадания, поскольку каждая страница Pageableзадания может иметь разный макет. Pageablejobs чаще всего используются с Books, набором страниц, которые могут иметь разные форматы. Я объясню Bookкласс через мгновение.

PageableРабота имеет следующие характеристики:

  • У каждой страницы может быть свой художник. Например, у вас может быть реализовано средство рисования для печати титульной страницы, другое средство рисования для печати оглавления и третье средство для печати всего документа.
  • Вы можете установить разный формат для каждой страницы в книге. В Pageableработе вы можете смешивать книжные и альбомные страницы.
  • Подсистема печати может попросить ваше приложение распечатать страницы не по порядку, и при необходимости некоторые страницы могут быть пропущены. Опять же, вам не нужно беспокоиться об этом, если вы можете предоставить любую страницу в своем документе по запросу.
  • PageableРабота не нужно знать , сколько страниц в документе.

Книги

Также новым, начиная с версии 1.2, является Bookкласс. Этот класс позволяет создавать многостраничные документы. Каждая страница может иметь свой собственный формат и свой собственный художник, что дает вам гибкость при создании сложных документов. Поскольку Bookкласс реализует Pageableинтерфейс, вы можете реализовать свой собственный Bookкласс, если в предоставленном Bookклассе отсутствуют необходимые вам функции.

BookКласс представляет собой набор страниц. При первом создании Bookобъект пуст. Чтобы добавить страницы, вы просто используете один из двух append()методов (подробнее см. Мое объяснение этого класса в разделе API). Параметрами этого метода являются PageFormatобъект, определяющий физические характеристики страницы, и PagePainterобъект, реализующий Printableинтерфейс. Если вы не знаете количество страниц в документе, просто передайте UNKNOWN_NUMBER_OF_PAGESзначение append()методу. Система печати автоматически найдет количество страниц, вызывая всех художников страницы в книге, пока не получит NO_SUCH_PAGEзначение.

Определение API

В этом разделе встретятся теория и практика. В предыдущих разделах мы узнали о структуре страницы, единицах измерения и моделях визуализации. В этом разделе мы рассмотрим API печати Java.

Все классы, необходимые для печати, находятся в java.awt.printпакете, который состоит из трех интерфейсов и четырех классов. В следующих таблицах определены классы и интерфейсы пакета печати.

имя Тип Описание
Paper Класс Этот класс определяет физические характеристики страницы.
PageFormat Класс PageFormatопределяет размер и ориентацию страницы. Он также определяет, что Paperиспользовать при рендеринге страницы.
PrinterJob Класс

Этот класс управляет заданием на печать. В его обязанности входит создание задания на печать, отображение диалогового окна печати при необходимости и печать документа.

Book Класс

Bookпредставляет собой документ. BookОбъект действует как набор страниц. Страницы, включенные в, Bookмогут иметь одинаковые или разные форматы и использовать разные рисовальщики.

Pageable Интерфейс PageableРеализация представляет собой набор страниц , которые должны быть напечатаны. PageableОбъект возвращает общее количество страниц в наборе, а также PageFormatи Printableдля заданной страницы. BookКласс реализует этот интерфейс.
Printable Интерфейс Художник страницы должен реализовать Printableинтерфейс. В этом интерфейсе есть только один метод print().
PrinterGraphics Интерфейс GraphicsОбъект реализует этот интерфейс. PrinterGraphicsпредоставляет getPrinterJob()метод получения задания на печать, которое инициировало процесс печати.

Страничный интерфейс

PageableИнтерфейс включает в себя три метода:

Название метода Описание
int getNumberOfPages() Возвращает количество страниц в документе.
PageFormat getPageFormat(int pageIndex) Возвращает страницу, PageFormatуказанную в pageIndex.
Printable getPrintable(int pageIndex) Возвращает Printableэкземпляр, ответственный за отображение страницы, указанной в pageIndex.

Версия для печати

PrintableИнтерфейс имеет один метод и два значения:

имя Тип Описание
int print(Graphics graphics, PageFormat pageFormat, int pageIndex) Метод

Запрашивает, чтобы графический дескриптор с использованием заданного формата страницы отображал указанную страницу.

NO_SUCH_PAGE Значение Это постоянная величина. Верните это значение, чтобы указать, что больше нет страниц для печати.
PAGE_EXISTS Значение В print()метод возвращает PAGE_EXISTS. Это указывает на то, что страница, переданная в качестве параметра print(), была отрисована и существует.

Every page painter must implement the Printable interface. Since there is only one method to implement, creating page painters may seem easy. However, remember that your code must be able to render any page in or out of sequence.

There are three parameters to print(), including Graphics, which is the same class used to draw on the screen. Since the Graphics class implements the PrinterGraphic interface, you can obtain the PrinterJob that instantiated this print job. If your page layout is complex and requires some advanced drawing features, you can cast the Graphics parameter to a Graphics2D object. You will then have access to the full Java 2D API.

Before you start using the Graphics object, note that the coordinates are not translated to the top left corner of the printable area. Refer to Figure 3 to find the location of the default origin.

(0, 0) appears at the top left corner of the printer margins. To print a 1-by-1-inch rectangle, 1 inch from both top and left margins, you would use the following code:

1: public int print (Graphics graphics, PageFormat pageFormat, int pageIndex) { 2: Graphics2D graphics2D = (Graphics2D) graphics; 3: Rectangle2D.Double rectangle = new Rectangle2D.Double (); 4: rectangle.setRect (pageFormat.getImageableX () + 72, 5: pageFormat.getImageableY () + 72, 6: 72, 7: 72); 8: graphics2D.draw (rectangle); 9: return (PAGE_EXISTS); }

From the previous example, we see that we must manually translate the origin of the rectangle so that it prints at the top of the printable area as in Figure 1. To simplify the code, we could translate the coordinates once and use (0, 0) as the origin of the printable area. By modifying the previous example, we get:

1: public int print (Graphics graphics, PageFormat pageFormat, int pageIndex) { 2: Graphics2D graphics2D = (Graphics2D) graphics; 3: graphics2D.translate (pageFormat.getImageableX (), pageFormat.getImageableY ()); 4: Rectangle2D.Double rectangle = new Rectangle2D.Double (); 5: rectangle.setRect (72, 72, 72, 72); 6: graphics2D.draw (rectangle); 7: return (PAGE_EXISTS); 8: }

Using the translate() method in line 3, we can translate the coordinates and set our origin (0, 0) at the top of the printable area. From this point on, our code will be simplified.

PrinterGraphics interface

The PrinterGraphics interface consists of one method:

Method name Description
PrinterJob getPrinterJob() Returns the PrinterJob for this rendering request and is implemented by the Graphics class

Paper class

Eight methods make up the Paper class:

Method name Description
double getHeight() This method returns the page's physical height in points (1 inch = 72 points). For example, if you are printing on a letter-size page, the return value will be 792 points, or 11 inches.
double getImageableHeight() This method returns the page's imageable height. The imageable height is the height of the print area that you may draw on. See Figure 1 for a graphical view of the imageable area.
double getImageableWidth() This method returns a page's imageable width (the width of the print area that you may draw on). See Figure 1 for a graphical view of the imageable area.
double getImageableX() This method returns the x origin of the imageable area. Since there is no support for margins, the return value represents the left margin.
double getImageableY() This method returns the y origin of the imageable area. The value returned from this method is equivalent to the top margin.
double getWidth() This method returns the page's physical width in points. If you print on a letter-size paper, the width is 8.5 inches, or 612 points.
void setImageableArea(double x, double y, double width, double height) This method sets the imageable area and specifies the margins on the page. Actually, the API provides no method to set the margins explicitly; you have to calculate them yourself.
void setSize(double width, double height) This method sets the physical page size. To define an 8.5-by-11-inch sheet, you would supply 612 and 792 points. Note that the default size is LETTER.

Before we move on to the next section, remember that the Paper class defines the page's physical characteristics. The PageFormat class represents all the page's characteristics, such as page orientation, size, and the paper type. This class is always passed as a parameter to the Printable interface's print() method. Use Paper to obtain the imageable area location, size, and page orientation along with a transformation matrix.

PageFormat class

The PageFormat consists of 12 methods:

Method name Description
double getHeight() This method returns the page's physical height in points (1 inch = 72 points). If your page measures 8.5 by 11 inches, then the return value will be 792 points, or 11 inches.
double getImageableHeight() This method returns the page's imageable height, which is the height of the print area on which you may draw. See Figure 1 for a graphical view of the imageable area.
double getImageableWidth() This method returns the page's imageable width -- the width of the print area on which you may draw. Figure 1 illustrates a graphical view of the imageable area.
double getImageableX() This method returns the x origin of the imageable area.
double getImageableY() This method returns the imageable area's y origin.
double getWidth() This method returns the page's physical width in points. If you print on letter-sized paper, the width is 8.5 inches, or 612 points.
double getHeight() This method returns the page's physical height in points. For example, letter-sized paper is 11 inches in height, or 792 points.
double[] getMatrix() This method returns a transformation matrix that translates user space into the requested page orientation. The return value is in the format required by the AffineTransform constructor.
int getOrientation() This method returns the orientation of the page as either PORTRAIT or LANDSCAPE.
void setOrientation(int orientation) This method sets the orientation of the page, using the constants PORTRAIT and LANDSCAPE.
Paper getPaper() This method returns the Paper object associated with the page format. Refer to the previous section for a description of the Paper class.
void setPaper(Paper paper) This method sets the Paper object that will be used by the PageFormat class. PageFormat must have access to the physical page characteristics to complete this task.

This concludes the description of the page classes. The next class that we will study is the PrinterJob.

PrinterJob class

The PrinterJob class controls the printing process. It can both instantiate and control a print job. Below you will find a definition of the class:

Method name Description
abstract void cancel() This method cancels the current print job. You can validate the cancellation with the isCancel() method.
abstract boolean isCancelled() This method returns true if the job is cancelled.
PageFormat defaultPage() This method returns the default page format for the PrinterJob.
abstract PageFormat defaultPage(PageFormat page) This method clones the PageFormat passed in parameters and modifies the clone to create the default PageFormat.
abstract int getCopies() This method returns the number of copies that the print job will print.
abstract void setCopies(int copies) This method sets the number of copies that the job will print. Note that if you show a print dialog box, users can alter the number of copies (see the pageDialog method).
abstract String getJobName() This method returns the job name.
static PrinterJob getPrinterJob() This method creates and returns a new PrinterJob.
abstract String getUserName() This method returns the user name associated with the print job.
abstract PageFormat pageDialog(PageFormat page) This method displays a dialog that allows the user to modify the PageFormat. The PageFormat, passed in parameters, sets the fields of the dialog. If the user cancels the dialog, then the original PageFormat will be returned. But if the user accepts the parameters, then a new PageFormat will be created and returned. Since it will not show the same parameters on all operating systems, you must be careful when using the pageDialog.
abstract void setPageable(Pageable document) This method queries the document to obtain the total number of pages. The Pageable will also return the PageFormat and the Printable object for each page. See the definition of the Pageable interface for more information.
abstract void setPrintable(Printable painter) This method sets the Painter object that will render the pages to be printed. A Painter object is an object that implements the Printable class and its print() method.
abstract void setPrintable(Printable painter, PageFormat format) This method completes the same tasks as abstract void setPrintable(Printable painter), except that you supply the PageFormat that the Painter will use. As indicated in the definition of the Printable interface, the print() method passes a PageFormat object as the first parameter.
abstract void print() This method prints the document. It actually calls the print() method of the Painter previously assigned to this print job.
abstract void setJobName(String jobName) This method sets the name of the print job.
abstract boolean printDialog() This method displays a print dialog box that allows the user to change the print parameters. Note that this interaction's result will not be returned to your program. Instead, it will be passed to the peer operating system.
abstract PageFormat validatePage(PageFormat page) This method will validate the PageFormat passed in parameters. If the printer cannot use the PageFormat that you supplied, then a new one that conforms to the printer will be returned.

Book class

Seven methods make up the Book class:

>

Method name Description
void append(Printable painter, PageFormat page) This method appends a page to the Book. The painter and the PageFormat for that page are passed in parameters.
void append(Printable painter, PageFormat page, int numPages) This method completes the same tasks as void append(Printable painter, PageFormat page), except that you specify the number of pages.
int getNumberOfPages() This method returns the number of pages currently in the Book.
PageFormat getPageFormat(int pageIndex) This method returns the PageFormat object for a given page.
Printable getPrintable(int pageIndex) This method returns the painter for a given page.
void setPage(int pageIndex, Printable painter, PageFormat page) This method sets the painter and the PageFormat for a given page already in the book.

The printing recipe

The recipe for printing is very simple. First, create a PrinterJob object:

PrinterJob printJob = PrinterJob.getPrinterJob ();

Next, using the setPrintable() method of the PrinterJob, assign the Painter object to the PrinterJob. Note that a Painter object is one that implements the Printable interface.

printJob.setPrintable (Painter);

Or you could set the PageFormat along with the Painter :

printJob.setPrintable (Painter, pageFormat);

Finally, the Painter object must implement the print() method:

public int print (Graphics g, PageFormat pageFormat, int page)

Here the first parameter is the graphics handle that you will use to render the page, the pageFormat is the format that will be used for the current page, and the last parameter is the page number that must be rendered.

That's all there is to it -- for simple printing, that is.

Introduction to the framework

The print framework that we will build in this series will be completely independent of the Java printing API. It will allow for greater flexibility in producing different outputs. Its structure will allow you to create documents, pages, and print objects. You will be able to add print objects to a page while adding pages to a document. By using this structure, you will be able to easily implement export features to PDF or HTML files, or print directly to the printer using the print API. But the main goal of the framework is to simplify the creation of printed documents. When you print using the print API, you only end up with a graphic canvas to draw on. It fails to address the concepts of paragraphs, images, drawings, graphics, tables, or running headers and footers. Because you must compute the (x, y) origin, the width and height of the printable area, setting margins is a chore. Our print framework will address all of these weaknesses.

Conclusion

We covered a lot of ground in this first part. We looked at measurement units, the structure of page, the two rendering models (Pageable and Printable), and Books, and we concluded with a detailed explanation of the printing API. Next month, we'll focus primarily on code, as we will be putting everything into practice. We will also look at the issues that arise when printing on multiple platforms. Looking ahead to Part 3, I will explain in detail the design and implementation of the framework.

Жан-Пьер Дюбе - независимый консультант по Java. Он основал Infocom в 1988 году. С тех пор Infocom разработал специальные приложения в таких областях, как производство, управление документами и крупномасштабное управление линиями электропередач. Жан-Пьер имеет обширный опыт программирования на C, Visual Basic и Java; последний теперь является основным языком для всех новых проектов. Он посвящает эту серию своей матери, которая скончалась, когда он писал эту статью.

Узнать больше по этой теме

  • «Печать на Java», Жан-Пьер Дюбе ( JavaWorld ).
  • Часть 1. Познакомьтесь с моделью печати Java (20 октября 2000 г.)
  • Часть 2. Распечатайте первую страницу и визуализируйте сложные документы (1 декабря 2000 г.)
  • Часть 3: Жан-Пьер Дюбе представляет структуру печати, которая работает поверх Java Print API (5 января 2001 г.)
  • Part 4: Code the print framework
  • (February 2, 2001)
  • Part 5: Discover the print framework's support classes
  • (March 2, 2001)
  • You will find tons of books covering Java AWT, but none will cover this subject to the extent of this book. If you're writing GUIs, you must have this book next to your computer: Graphic Java 2, Mastering The JFCAWT, Volume 1, David M. Geary (Prentice Hall, 1998)

    //www.amazon.com/exec/obidos/ASIN/0130796662/javaworld

  • This book was helpful when Java 1.1 came out, and was the first to talk about printing in Java: Migrating from Java 1.0 to Java 1.1, Daniel I. Joshi and Pavel A. Vorobiev (Ventana Communications Group, 1997)

    //www.amazon.com/exec/obidos/ASIN/1566046866/javaworld

  • Вероятно, лучшая книга по Java 2D, эта книга охватывает все аспекты 2D API, а также предоставляет Graphicsструктуру для продвинутых 2D-композиций: Java 2D API Graphics, Винсент Дж. Харди (Prentice Hall, 1999)

    //www.amazon.com/exec/obidos/ASIN/0130142662/javaworld

  • Отличное введение в Java 2D API «Начало работы с Java 2D», Билл Дэй ( JavaWorld, июль 1998 г.)

    //www.javaworld.com/javaworld/jw-07-1998/jw-07-media.html

Этот рассказ «Печать на Java, часть 1» был первоначально опубликован JavaWorld.