Printing

SWT offers developers a compact printing API. You can add the printing functionality to your existing programs easily. This chapter introduces you to basic printing mechanisms and then uses a real world example to guide you step by step through coding for printing and print preview. Finally, you learn about multiple-page printing and pagination.

Printing Fundamentals

In SWT, the org.eclipse.swt.printing package contains classes used for printing support. Currently, there are only three classes within this package:

  • PrintDialog
  • Printer
  • PrinterData

A print job is described by an instance of PrinterData. The PrinterData instance is a lightweight Java object that specifies the target printer and the scope and type of printing desired. For example, the number of pages and copies can be specified in PrinterData objects. In most of these cases, you bring up a print dialog (represented by the PrintDialog class) and let the user select the target printer and configure various settings. A PrinterData object, with all the information specified by the user in the print dialog, is returned when a print dialog is closed. To perform the printing operation, you have to initiate a Printer instance and create a GC on the printer and then draw on the printer GC using the usual graphics calls.

For example, the following code prints the text "Eclipse" on the selected printer:

 PrintDialog dialog = new PrintDialog(shell);

 // Opens a dialog and lets user select the
 // target printer and configure various settings.
 PrinterData printerData = dialog.open();
 if(printerData != null) { // If a printer is selected
 // Creates a printer.
 Printer printer = new Printer(printerData);

 // Starts the print job.
 if(printer.startJob("Text")) {
 GC gc = new GC(printer);

 // Starts a new page.
 if(printer.startPage()) {
 gc.drawString("Eclipse", 200, 200);

 // Finishes the page.
 printer.endPage();
 }

 gc.dispose();

 // Ends the job.
 printer.endJob();
 }

 // Disposes the printer object after use.
 printer.dispose();

 System.out.println("Print job done.");
 }

First, select the target printer and configure the print job settings in the print dialog. The print job is represented by the PrinterData object returned. A Printer instance is created with the PrinterData object. To start the print job, call the startJob method of the Printer class with the job name (a meaningful string) as the argument. If the job has been successfully started, a graphics context based on the printer is obtained. After that, you can start a new page by calling the startPage method. If the startPage method succeeds, draw the text on the printer. The endPage method is used to indicate that the current page is finished printing. To end the print job, invoke the endJob method of the Printer class. Finally, dispose of the Printer object because it employs native operating resources.

The preceding code prints only a single page. You can use the obtained Printer object to print multiple pages. The printing process is illustrated in Figure 17-1.

image from book
Figure 17-1

In the sample code, you use a printer dialog to let the user select the target printer. The following section discusses many other ways to select the target printer.

Selecting the Target Printer

As you have seen in the preceding sample code, instances of the Printer class are used to perform the printing job. The Printer class has two constructors:

 public Printer()
 public Printer(PrinterData data)

The default constructor creates an instance representing the default printer. If there is no printer available, the default constructor throws an exception. The other constructor allows you to select a specific printer by using a PrinterData object.

To obtain a PrinterData instance, you can create one using one of the constructors of the PrinterData object:

 public PrinterData()
 public PrinterData(String driver, String name)

The default constructor creates an instance representing the default constructor. Similar to the default constructor of the Printer class, this default constructor throws an exception if there is no printer available. If the driver and name of the printer are known, you can use the other constructor to create an instance representing the corresponding printer. As mentioned before, an instance of PrinterData also contains print job control information such as the number of pages and copies. You can set such control parameters through the fields of the PrinterData class:

  • public boolean collate: Specifies whether or not the printer should collate the printed paper
  • public int copyCount: Specifies the number of copies to print
  • public boolean printToFile; public String fileName: The printToFile field specifies whether or not the print job should go to a file. If the printToFile is set to true, you can use the fileName field to set the name of the file in which the job will be printed.
  • public in scope; public int startPage; public int endPage: The scope filed defines the scope of the print job, which may be expressed in one of the following values: PrinterData.ALL_PAGES (printing all pages in current document), PrinterData.SELECTION (printing the current selection only), or PrinterData.PAGE_RANGE (printing the range of pages specified by the startPage field and the endPage field).

During printing, you can access the associated PrinterData instance of the printer by calling the getPrinterData method of the Printer class:

 public PrinterData getPrinterData()

Besides constructing a PrinterData object by calling the constructors of the PrinterData class directly, you can use a print dialog to get an instance of PrinterData representing the user selection. For example, the following code brings up a print dialog (in Windows), as shown in Figure 17-2.

image from book
Figure 17-2

 PrintDialog dialog = new PrintDialog(shell);
 PrinterData printerData = dialog.open();

 if(printerData != null) { // If a printer is selected
 Printer printer = new Printer(printerData);
 ...
 }

The user may select the target printer and configure the print settings in the print dialog. After the user hits the Print button (or equivalent buttons on other platforms), the open method of the PrintDialog class returns a PrinterData object containing all the information about the selected printer and print control settings. You can then use the PrinterData object to construct a Printer instance. On the other hand, if the user hits the Cancel button, a null object is returned by the open method. So you must make sure the returned PrinterData object is not null in order to initiate a proper Printer object.

To get all the printers on the system as an array of PrinterData object, you can use the getPrinterList method of the Printer class:

 public static PrinterData getDefaultPrinterData()

You can iterate the array and select the desired PrinterData object to create the Printer instance.

After a Printer object is obtained, you can perform various printing operations on it.

Basic Printing

With a valid Printer object, you can create a graphics context on it and then draw on the graphics context using the various graphics calls introduced in Chapter 15.

The Image Viewer Application

In the first section, you saw a very simple example that prints a word on a selected printer. In practical printing, you have to consider many issues such as margin settings and DPI effects. In this section, you learn how to perform proper printing with an image viewer application, as shown in Figure 17-3.

image from book
Figure 17-3

The user can load an image using the Open tool item. The image is displayed on a canvas at the center of the shell. Our task here is to implement a print behavior so that when the user presses the Print tool item, the image currently being displayed is printed on the selected printer properly:

 ToolItem itemPrint = new ToolItem(toolBar, SWT.PUSH);
 itemPrint.setText("Print");
 itemPrint.addListener(SWT.Selection, new Listener() {
 public void handleEvent(Event event) {
 print();
 }
 });

 /**
 * Lets the user select a printer and prints the image on it.
 *
 */
 void print() {
 PrintDialog dialog = new PrintDialog(shell);
 // Prompts the printer dialog to let the user select a printer.
 PrinterData printerData = dialog.open();

 if (printerData == null) // the user cancels the dialog
 return;
 // Loads the printer.
 Printer printer = new Printer(printerData);

 ...

 }

When the Print tool item is selected, the print method is invoked. The printer selection part is very straightforward. You need to insert the actual printing procedure at the point marked by the ellipsis. To print the image properly on the printer, you first calculate the page margins. Then, you need to properly resize the image so that the image can be printed on the printer with the correct size.

Setting the Page Margins

Without proper page margins, objects may be printed close to the edges of the page, which can look ugly and unprofessional. In order to position and align objects correctly on the page, you have to set the page margins before performing the actual printing.

For the image viewer application, you want to print the image on the page with margins equal to 1 inch for each side (see Figure 17-4).

image from book
Figure 17-4

Before setting the page margins, you need to know the size of the page.

The getBounds method of the Printer class returns the physical size of the page in pixels:

 public Rectangle getBounds()

However, not every part of the physical page can be printed on. The printable area of the page can be determined by using the getClientArea method:

 public Rectangle getClientArea()

Additionally, you can use the computeTrim method to determine the physical horizontal and vertical offsets for the printable area:

 Rectangle trim = printer.computeTrim(0, 0, 0, 0);

The horizontal offset is trim.x and trim.y is the vertical offset relative to the upper-left corner of the physical page.

Suppose 1 inch of margin at each side is desired; the positions of those margins can be calculated as follows:

 double marginLeft = 1.0; // in inches
 double marginRight = 1.0;
 double marginTop = 1.0;
 double marginBottom = 1.0;

 Rectangle clientArea = printer.getClientArea();
 Rectangle trim = printer.computeTrim(0, 0, 0, 0);

 Point dpi = printer.getDPI();

 // The origin of the coordinate is the upper left corner of the client area.
 int leftMargin = (int) (marginLeft * dpi.x) - trim.x;
 int rightMargin = clientArea.width + trim.width - (int) (marginRight * dpi.x) -
 trim.x;
 int topMargin = (int) (marginTop * dpi.y) - trim.y;
 int bottomMargin = clientArea.height + trim.height - (int) (marginBottom * dpi.y) -
 trim.y;

Because setting margins is necessary in almost every application with printing support, it is a good idea to create a utility class so that you can reuse it later. Here is the PrintMargin class:

 /*******************************************************************************
 * All Right Reserved. Copyright (c) 1998, 2004 Jackwind Li Guojie
 *
 * Created on 2004-5-2 18:55:02 by JACK $Id$
 *
 ******************************************************************************/

 package com.asprise.books.javaui.ch17;

 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.printing.Printer;

 /**
 * Contains margin information (in pixels) for a print job.
 *
 */
 public class PrintMargin {
 // Margin to the left side, in pixels
 public int left;
 // Margins to the right side, in pixels
 public int right;
 // Margins to the top side, in pixels
 public int top;
 // Margins to the bottom side, in pixels
 public int bottom;

 private PrintMargin(int left, int right, int top, int bottom) {
 this.left = left;
 this.right = right;
 this.top = top;
 this.bottom = bottom;
 }

 /**
 * Returns a PrintMargin object containing the true border margins for the
 * specified printer with the given margin in inches.
 * Note: all four sides share the same margin width.
 * @param printer
 * @param margin
 * @return
 */
 static PrintMargin getPrintMargin(Printer printer, double margin) {
 return getPrintMargin(printer, margin, margin, margin, margin);
 }

 /**
 * Returns a PrintMargin object containing the true border margins for the
 * specified printer with the given margin width (in inches) for each side.
 */
 static PrintMargin getPrintMargin(
 Printer printer,
 double marginLeft,
 double marginRight,
 double marginTop,
 double marginBottom) {
 Rectangle clientArea = printer.getClientArea();
 Rectangle trim = printer.computeTrim(0, 0, 0, 0);

 //System.out.println(printer.getBounds() + " - " + clientArea + "" +
 // trim);
 Point dpi = printer.getDPI();

 int leftMargin = (int) (marginLeft * dpi.x) - trim.x;
 int rightMargin =
 clientArea.width
 + trim.width
 - (int) (marginRight * dpi.x)
 - trim.x;
 int topMargin = (int) (marginTop * dpi.y) - trim.y;
 int bottomMargin =
 clientArea.height
 + trim.height
 - (int) (marginBottom * dpi.y)
 - trim.y;

 return new PrintMargin(
 leftMargin,
 rightMargin,
 topMargin,
 bottomMargin);
 }

 public String toString() {
 return "Margin { "
 + left
 + ", "
 + right
 + "; "
 + top
 + ", "
 + bottom
 + " }";
 }
 }

With the PrintMargin class, you can easily get the page margins with the following code:

 PrintMargin margin = PrintMargin.getPrintMargin(printer, 1.0);

Now that the page margins have been calculated, you are ready to print the image on the page.

Printing the Image

Here is the code to print the image:

 if (image == null) // If no image is loaded, do not print.
 return;

 final Point printerDPI = printer.getDPI();
 final Point displayDPI = display.getDPI();

 final PrintMargin margin = PrintMargin.getPrintMargin(printer, 1.0);

 Thread printThread = new Thread() {
 public void run() {
 if (!printer.startJob(fileName)) {
 System.err.println("Failed to start print job!");
 printer.dispose();
 return;
 }

 GC gc = new GC(printer);

 if (!printer.startPage()) {
 System.err.println("Failed to start a new page!");
 gc.dispose();
 return;
 } else {
 int imageWidth = image.getBounds().width;
 int imageHeight = image.getBounds().height;

 // Handles DPI conversion.
 // '1.0' is used to make the
 // to achieve better precision.
 double dpiScaleFactorX = printerDPI.x * 1.0 / displayDPI.x;
 double dpiScaleFactorY = printerDPI.y * 1.0 / displayDPI.y;

 // If the image is too large to draw on a page, reduces its
 // width and height proportionally.
 double imageSizeFactor =
 Math.min(1, (margin.right - margin.left) * 1.0 /
 (dpiScaleFactorX * imageWidth));
 imageSizeFactor = Math.min(imageSizeFactor,
 (margin.bottom - margin.top) * 1.0 /
 (dpiScaleFactorY * imageHeight));

 // Draws the image to the printer.
 gc.drawImage(
 image,
 0,
 0,
 imageWidth,
 imageHeight,
 margin.left,
 margin.top,
 (int) (dpiScaleFactorX * imageSizeFactor * imageWidth),
 (int) (dpiScaleFactorY * imageSizeFactor * imageHeight));
 gc.dispose();
 }

 printer.endPage();
 printer.endJob();

 printer.dispose();
 System.out.println("Printing job done!");
 }
 };
 printThread.start();

A new thread is used to execute the print job because the print task may take considerable time. You learned about printing fundamentals in the first section. In the next section, you learn about image drawing. In order to better understand the code in the preceding section, you need to know about measuring the resolution of the output device, better known as dpi.

DPI Conversion

The measurement of dots per inch (dpi) specifies the number of dots (pixels) per linear inch. Different devices may have different dpi values. For example, my laptop screen has a dpi value of 96 ´ 96 (horizontally and vertically), whereas my high-resolution printer has 1200 ´ 1200 dpi. Let's say an image is 96 pixels wide. The image appears 1 inch wide on my screen, although it is only 0.08 inch wide when it is output on the printer! In order to print the image properly, you would have to scale the image using the following formula:

 imageOnPrinterWidth = imageWidth * printer.getDPI().x / display.getDPI().x;
 imageOnPrinterHeight = imageHeight * printer.getDPI().y / display.getDPI().y;

Note that the getDPI methods of the Printer class and the Display class return the dpi values of the printer and the screen, respectively.

Sometimes, the image is too large to be displayed on the page. In this case, you need to scale it to fit the print page.

After the new image size has been determined, the image can be printed to the page easily with the drawImage method of the GC class.

Finally, you can end the print job and dispose of the printer object.

Providing the Print Preview

The print preview feature allows the user to select the target printer, configure various parameters such as page margins, and preview the print layout, as shown in Figure 17-5.

image from book
Figure 17-5

There are many ways to implement the print preview. The most straightforward technique is to create the print preview as an image with the size equal to that of the print page and print the objects on the image. However, this approach may cause performance problems, especially when the print page is large and the printer resolution is high.

With the knowledge gained in previous sections, you can easily provide the print preview in a canvas with proper image scaling and drawing operations. Here is the implementation of the print preview dialog:

 public class ImagePrintPreviewDialog extends Dialog {
 ImageViewer viewer;
 Shell shell;
 Canvas canvas;
 Printer printer;
 PrintMargin margin;
 Combo combo;

 public ImagePrintPreviewDialog(ImageViewer viewer) {
 super(viewer.shell);
 this.viewer = viewer;
 }

 public void open() {
 shell =
 new Shell(
 viewer.shell,
 SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.RESIZE);
 shell.setText("Print preview");
 shell.setLayout(new GridLayout(4, false));

 final Button buttonSelectPrinter = new Button(shell, SWT.PUSH);
 buttonSelectPrinter.setText("Select a printer");
 buttonSelectPrinter.addListener(SWT.Selection, new Listener() {
 public void handleEvent(Event event) {
 PrintDialog dialog = new PrintDialog(shell);
 // Prompts the printer dialog to let the user select a printer.
 PrinterData printerData = dialog.open();

 if (printerData == null) // the user cancels the dialog
 return;
 // Loads the printer.
 final Printer printer = new Printer(printerData);
 setPrinter(
 printer,
 Double.parseDouble(
 combo.getItem(combo.getSelectionIndex())));
 }
 });

 new Label(shell, SWT.NULL).setText("Margin in inches: ");
 combo = new Combo(shell, SWT.READ_ONLY);
 combo.add("0.5");
 combo.add("1.0");
 combo.add("1.5");
 combo.add("2.0");
 combo.add("2.5");
 combo.add("3.0");
 combo.select(1);
 combo.addListener(SWT.Selection, new Listener() {
 public void handleEvent(Event event) {
 double value =
 Double.parseDouble(
 combo.getItem(combo.getSelectionIndex()));
 setPrinter(printer, value);
 }
 });

 final Button buttonPrint = new Button(shell, SWT.PUSH);
 buttonPrint.setText("Print");
 buttonPrint.addListener(SWT.Selection, new Listener() {
 public void handleEvent(Event event) {
 if (printer == null)
 viewer.print();
 else
 viewer.print(printer, margin);
 shell.dispose();
 }
 });

 canvas = new Canvas(shell, SWT.BORDER);
 GridData gridData = new GridData(GridData.FILL_BOTH);
 gridData.horizontalSpan = 4;
 canvas.setLayoutData(gridData);
 canvas.addPaintListener(new PaintListener() {
 public void paintControl(PaintEvent e) {
 int canvasBorder = 20;

 if (printer == null || printer.isDisposed())
 return;
 Rectangle rectangle = printer.getBounds();
 Point canvasSize = canvas.getSize();

 double viewScaleFactor =
 (canvasSize.x - canvasBorder * 2) * 1.0 / rectangle.width;
 viewScaleFactor =
 Math.min(
 viewScaleFactor,
 (canvasSize.y - canvasBorder * 2)
 * 1.0
 / rectangle.height);

 int offsetX =
 (canvasSize.x - (int) (viewScaleFactor * rectangle.width))
 / 2;
 int offsetY =
 (canvasSize.y - (int) (viewScaleFactor * rectangle.height))
 / 2;

 e.gc.setBackground(
 shell.getDisplay().getSystemColor(SWT.COLOR_WHITE));
 // draws the page layout
 e.gc.fillRectangle(
 offsetX,
 offsetY,
 (int) (viewScaleFactor * rectangle.width),
 (int) (viewScaleFactor * rectangle.height));

 // draws the margin.
 e.gc.setLineStyle(SWT.LINE_DASH);
 e.gc.setForeground(
 shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));

 int marginOffsetX =
 offsetX + (int) (viewScaleFactor * margin.left);
 int marginOffsetY =
 offsetY + (int) (viewScaleFactor * margin.top);
 e.gc.drawRectangle(
 marginOffsetX,
 marginOffsetY,
 (int) (viewScaleFactor * (margin.right - margin.left)),
 (int) (viewScaleFactor * (margin.bottom - margin.top)));

 if (viewer.image != null) {
 int imageWidth = viewer.image.getBounds().width;
 int imageHeight = viewer.image.getBounds().height;

 double dpiScaleFactorX =
 printer.getDPI().x
 * 1.0
 / shell.getDisplay().getDPI().x;
 double dpiScaleFactorY =
 printer.getDPI().y
 * 1.0
 / shell.getDisplay().getDPI().y;

 double imageSizeFactor =
 Math.min(
 1,
 (margin.right - margin.left)
 * 1.0
 / (dpiScaleFactorX * imageWidth));
 imageSizeFactor =
 Math.min(
 imageSizeFactor,
 (margin.bottom - margin.top)
 * 1.0
 / (dpiScaleFactorY * imageHeight));

 e.gc.drawImage(
 viewer.image,
 0,
 0,
 imageWidth,
 imageHeight,
 marginOffsetX,
 marginOffsetY,
 (int) (dpiScaleFactorX
 * imageSizeFactor
 * imageWidth
 * viewScaleFactor),
 (int) (dpiScaleFactorY
 * imageSizeFactor
 * imageHeight
 * viewScaleFactor));

 }

 }
 });

 shell.setSize(400, 400);
 shell.open();
 setPrinter(null, 1.0);

 // Set up the event loop.
 while (!shell.isDisposed()) {
 if (!shell.getDisplay().readAndDispatch()) {
 // If no more entries in event queue
 shell.getDisplay().sleep();
 }
 }
 }

 /**
 * Sets target printer.
 *
 * @param printer
 */
 void setPrinter(Printer printer, double marginSize) {
 if (printer == null) {
 printer = new Printer(Printer.getDefaultPrinterData());
 }
 this.printer = printer;
 margin = PrintMargin.getPrintMargin(printer, marginSize);
 canvas.redraw();
 }

 }

A canvas is used to display the print preview. When the target printer or print parameters are changed, the canvas is forced to update.

In the image view application, you add the following code to bring up the print preview dialog:

 ToolItem itemPrintPreview = new ToolItem(toolBar, SWT.PUSH);

 itemPrintPreview.setText("Preview");
 itemPrintPreview.addListener(SWT.Selection, new Listener() {
 public void handleEvent(Event event) {
 ImagePrintPreviewDialog dialog =
 new ImagePrintPreviewDialog(ImageViewer.this);
 dialog.open();
 }
 });

Text Printing and Pagination

In Chapter 9, you learned how to create a simple text editor that's based on the StyledText control. The text editor enables the user to load text from a file, edit the text, and save the text into a file. Here, you add the print feature to the editor (see Figure 17-6).

image from book
Figure 17-6

When the Print toolbar item is pressed, the application prints the content of the text box to a selected printer. You can either implement the printing feature by yourself or you can simply invoke the print methods of the StyledText class. Here, you learn how to implement text printing from scratch and then how to use existing print methods in the StyledText class.

First, create an Action object and add it to the toolbar:

 Action actionPrint = new Action("&Print@Ctrl+P") {
 public void run() {
 printText(text.getText());
 }
 };

 ...

 toolBarManager.add(new Separator());
 toolBarManager.add(actionPrint);

When the toolbar item is hit, the printText function is invoked. The following is the implementation of the printText method:

 int x;
 int y;
 int lineHeight; // The height of each line.
 PrintMargin margins; // Page margins
 int pageNumber = 1;
 int lineNumber = 1;

 void printText(String text) {
 PrintDialog dialog = new PrintDialog(shell);
 PrinterData printerData = dialog.open();
 if(printerData == null)
 return;
 Printer printer = new Printer(printerData);
 if(! printer.startJob("text"))
 return;

 GC gc = new GC(printer);

 margins = PrintMargin.getPrintMargin(printer, 1.0);
 x = margins.left;
 y = margins.top;

 StringBuffer buffer = new StringBuffer();

 Font font = new Font(printer, "Arial", 12, SWT.NORMAL);
 gc.setFont(font);
 lineHeight = gc.getFontMetrics().getHeight();

 printer.startPage();
 // prints page number at the bottom margin.
 String page = "- " + pageNumber + " -";
 gc.drawString(page, (margins.right - margins.left - gc.textExtent(page).x) / 2
 + margins.left, margins.bottom + gc.textExtent(page).y);

 for(int index = 0; index  margins.right -
 margins.left) {
 printNewLine(printer, gc, buffer.toString());
 buffer.setLength(0);
 }
 buffer.append(c);

 if(index < text.length() - 1 &&
 (!Character.isWhitespace(text.charAt(index + 1)))) {
 // Looks ahead a word to see whether the line should wrap here.
 String word = readWord(text, index + 1);
 if(gc.textExtent(buffer.toString() + word).x >
 margins.right - margins.left) {
 printNewLine(printer, gc, buffer.toString());
 buffer.setLength(0);
 }
 }
 index += 1;
 break;

 default:
 buffer.append(c);
 index += 1;
 }
 }

 if(buffer.length() > 0)
 printNewLine(printer, gc, buffer.toString());

 if(y + lineHeight <= margins.bottom)
 printer.endPage();
 printer.endJob();

 gc.dispose();
 font.dispose();
 printer.dispose();
 }

 /**
 * Prints the new line to page. If there is not enough vertical space,
 * a new page is started.
 * @param printer
 * @param line
 * @param x
 * @param y
 */
 void printNewLine(Printer printer, GC gc, String line) {
 System.out.println("Line: " + line);
 if(y + lineHeight > margins.bottom) {
 printer.endPage();
 x = margins.left;
 y = margins.top;

 pageNumber ++;
 lineNumber = 1;

 // prints page number at the bottom margin.
 String page = "- " + pageNumber + " -";
 gc.drawString(page,
 (margins.right - margins.left - gc.textExtent(page).x) / 2 +
 margins.left, margins.bottom + gc.textExtent(page).y);
 }
 gc.drawString(line, x, y);
 y += lineHeight;
 }

 /**
 * Reads a word from the given text starting from the offset.
 * @param text
 * @param offset
 * @return
 */
 String readWord(String text, int offset) {
 StringBuffer sb = new StringBuffer();
 int index = offset;
 char c = 0;

 while(index < text.length()) {
 c = text.charAt(index);
 if(Character.isWhitespace(c))
 break;

 sb.append(c);
 index += 1;
 }

 return sb.toString();
 }

When the printText method is invoked, it first prompts the print dialog. If a printer is selected by the user, the GC object for the printer is created and the page margins are set. You might notice that a font is set as the font of the graphics context:

 Font font = new Font(printer, "Arial", 12, SWT.NORMAL);
 gc.setFont(font);

The font is created on the printer device instead of the display object (i.e., the computer screen). If you use a font created on the display, the final text output might look strange because the dpi value for the printer is usually different from that of the display.

After the font has been set properly, you iterate each character in the text. If a line is too long to be displayed, it should be wrapped or broken into multiple lines. You use a very simple line-breaking algorithm — if the word next to a white space does not fit into the space that's provided, the line should be broken.

The printNewLine function is used to print out lines on the printer. This function first checks whether there is enough space for a new line. If there is not enough room for a new line, a new page is started. Subsequent lines are then printed on the new page. The page number is printed at the bottom margin of each page. The final printed work is shown in Figure 17-7.

image from book
Figure 17-7

In addition to implementing your own print procedure, you can simply call one of the print methods of the StyledText class:

 public Runnable print(Printer printer)
 public void print()
 public Runnable print(Printer printer, StyledTextPrintOptions options)

The first method creates a Runnable object that can be executed to perform the print task on the specified printer. The second method prints the text content on the default printer within the UI thread. The last print method allows you to control the print job with a StyledTextPrintOptions object. For example, you can use the following code to print the text content with "SWT" as the page header and the page number as the page footer:

 StyledTextPrintOptions options = new StyledTextPrintOptions();
 options.header = "SWT";
 options.footer = "-  -";
 options.jobName = "Text";

 Runnable runnable = text.print(new Printer(), options);
 runnable.run();

Note that the tag in the footer will be replaced by the page number during printing.

If you need advanced control over the printing from a StyledText control, you can use the printText method as a starting point to create your own custom printing.

Summary

Printing is a convenient way to generate a permanent copy of your work. This chapter showed you how to equip your applications with printing support. Beginning with the fundamental process of printing, this chapter covered comprehensive SWT printing topics. You can print images, shapes, and text on the printer through the graphics context object of the printer. Because the screen may have a dpi value that is different from the printer, you should take this issue into consideration when printing objects on the printer. The task of setting page margins is greatly simplified with the utility class that was discussed. Finally, the chapter introduced text printing and pagination.



Professional Java Native Interfaces with SWT. JFace
Professional Java Native Interfaces with SWT/JFace (Programmer to Programmer)
ISBN: 0470094591
EAN: 2147483647
Year: 2003
Pages: 147

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net