|
J2TextPrinter |
|
J2TextPrinter is a Java 2 component for printing multi-page JTextPane documents. J2TextPrinter converts any JTextPane, JEditorPane, or JTextArea or subclass thereof into a Java Pageable, suitable for printing by the J2Printer class (or any Java PrinterJob). It also implements Flowable for any JTextPane, JEditorPane, or JTextArea, so that it may be used with J2FlowPrinter as part of a series of Flowables printed back-to-back.
JTextPane, JEditorPane, and JTextArea are all subclasses of
JTextComponent. JTextArea is used in Java to represent simple,
multiple-line text in a single font. JEditorPane and.JTextPane
are used in Java to represent rich text documents,
including multiple fonts, sizes, styles, colors, alignment, spacing,
tabs, indentation, etc. In addition, JTextPane is also capable of
including embedded
graphics and embedded components into the middle of a rich text
document.
Since JTextPane is the most general JTextComponent supported by
J2TextPrinter, we focus on it as the primary Java component used for
forming and printing text documents. The underlying
model (data) for a JTextPane is an instance of the class
StyledDocument. It can be formed programmatically by calling
JTextPane methods, or by reading in HTML or RTF formatted data (subject
to the limits of Java's support
for these standards).
J2TextPrinter
Pagination
When J2TextPrinter paginates the JTextPane, it breaks pages vertically on line boundaries. J2TextPrinter will reflow (rewrap) the contents of the JTextPane to fit the width of the page, taking the current page size and margins into account. Alternatively, you can turn on "WYSIWYG" mode to cause the printed pages to retain the exact line layout of the specified JTextPane. J2TextPrinter then calculates the maximum number of lines that will fit in the remaining space on each page. If a \f (form feed) character is encountered before this point, then a page break is inserted and the entire line containing the form feed character is omitted. If the calculated page break occurs in the middle of an HTML table, the exact boundary between HTML table rows is determined for the actual page break.
J2TextPrinter never paginates horizontally. If the JTextPane contains content that is too wide for the page (such as a wide image, a wide row of an HTML table, or too much text on a line in WYSIWYG mode), it will automatically shrink-to-fit the entire JTextPane so that the widest content fits the available page width.
If an embedded graphic (e.g.
image), embedded component, HTML table
row, or very large font character is encountered that does not fit in
the remaining space on the page, special fallback heuristics are
used to determine where to break the page. First, J2TextPrinter
reads the value of
getMaximumPaginationGap()
, default is 0.2 or 20%. If
the
remaining space
on the page is less than that percentage of the full page height,
then printing skips to the top of the next page (this controls the
largest amount of space that will be wasted in order to keep content
intact). If this occurs within an HTML table row, the characters
are
examined one at a time to find a possible break between text
lines that does fit (this handles the case of many lines of text within
a single HTML table cell). Otherwise, the
graphic, component, HTML table row, or large character is sliced like
an image ("tiled") at the exact pixel boundary that exactly fits the
remaining space on
the page.
You will find it useful to begin your program with:
import com.wildcrest.j2printerworks.*;
rather than spell out the full package name for all J2PrinterWorks classes.
J2TextPrinter can instantiated with a zero-argument constructor:
J2TextPrinter textPrinter = new J2TextPrinter();
J2TextPrinter textPrinter = new J2TextPrinter(yourJTextPane);
Note: if you change the contents of your JTextPane after printing, you need to call setPane (or instantiate a new J2TextPrinter) again before the next time you print for these changes to be recognized.
The following is a simple but complete Java program (J2TextPrinterSimplestTest.java ) that displays and prints a JTextPane using J2TextPrinter:
import javax.swing.*;
import com.wildcrest.j2printerworks.*;
class J2TextPrinterSimplestTest{
static public void main(String args[]){
JTextPane pane
= new JTextPane();
pane.setContentType("text/html");
pane.setText("<html>Here are two lines of <b>HTML
text</b>"
+ "<br>that <i>will</i> be printed</html>");
JFrame frame = new
JFrame("J2TextPrinter test");
frame.getContentPane().add(pane);
frame.setSize(300,200);
frame.setVisible(true);
J2Printer printer =
new J2Printer();
printer.setSeparatePrintThread(false);
J2TextPrinter
textPrinter = new J2TextPrinter(pane);
printer.addPageable(textPrinter);
printer.print();
System.exit(0);
}
}
Most of the methods of J2TextPrinter are set and get methods for
controlling its property values. The full list of J2TextPrinter
methods, what they do, and their default values are given in the
J2TextPrinter Javadoc documentation .
Whether J2TextPrinter is used as a Pageable or a Flowable, you can
control whether it is left, right, or center justified horizontally on
a page, top, bottom, or center justified within the remaing space on a
page, whether
the JTextPane reflows (rewraps) into the available page width or
maintains
its current layout ("WYSIWYG"), and how copying (cloning) of your
JTextPane
is used when printing.
Horizontal and vertical alignment
J2TextPrinter will print your JTextPane either top, center, or bottom justified vertically on the page between the gap below the header and gap above the footer. The default value for vertical alignment is TOP.
Similarly, J2TextPrinter will print your JTextPane either left, center, or right justified horizontally on the page between the left and right margins. The default value for horizontal alignment is CENTER. However, note that if you have setWYSIWYG(false), which is the default, the JTextPane content rewraps to the width of the page by setting the width of the JTextPane the same as the page, so that the setHorizonalAlignment method has no real effect. To use setHorizontalAlignement effectively, call setWYSIWYG(true) and set the width of the JTextPane as desired.
setHorizontalAlignment
(int horizontalAlignment)
Sets the
horizontal alignment (LEFT, CENTER, RIGHT) for printing the JTextPane
on the page, typically used with setWYSIWYG(true).
setVerticalAlignment (int verticalAlignment)
Sets the
vertical alignment (TOP, CENTER, BOTTOM) for printing the JTextPane on
the page.
WYSIWYG support
J2TextPrinter normally reflows (line wraps) your document to fill the printed page. However, J2TextPrinter can be controlled to print your JTextPane with exactly the same flow as it appears on the screen. For this purpose J2TextPrinter has a setWYSIWYG method:
setWYSIWYG (boolean wysiwyg)
Sets whether
WYSIWYG (What-You-See-Is-What-You-Get) mode is enabled, thereby
preventing
relayout of text.
If you call setWYSIWYG(true), then you will get a WYSIWYG
representation of your JTextPane with its line layout preserved as
is. If the width of your JTextPane is wider than the available
printing width of the page (between margins), then J2TextPrinter will
perform a shrink-to-fit operation on your JTextPane to make it
fit. J2TextPrinter never prints more
than one page horizontally.
Cloning support
J2TextPrinter needs to be able to reflow (rewrap) the contents of your JTextPane without affecting its appearance on the screen. To accomplish this, J2TextPrinter prints your JTextPane's contents from its own internal JTextPane rather than from your JTextPane.
If cloningUsed is false, the StyledDocument of J2TextPrinter's internal JTextPane is set to your JTextPane's StyledDocument directly. If cloningUsed is true, the StyledDocument of J2TextPrinter's internal JTextPane is set to a clone (a copy created by Java serialization) of the StyledDocument of your JTextPane.
It has been determined that cloning is necessary if your JTextPane has inserted Components and appears in a Frame, JFrame, or JInternalFrame, or if it has inserted Components and you are printing from a separate thread (setSeparatePrintThread(true), which is the default). This is because Java doesn't support having the same component in multiple simultaneous views.
Since cloning is generally a safe, the default for cloningUsed
is true. This method allows cloning to be disabled if it causes any
problems for a particular JTextPane and since it is a bit slower.
This can occur in particular if the JTextPane contains embedded
components that are for whatever reason not serializable. There
are also certain known serialization bugs in Java. For example,
under JDK 1.4.x certain
HTML tags such as the "border" subtag of "table" are lost during
serialization, so
it turns out cloningUsed needs to be set to false for HTML
documents that contain tables with borders, otherwise the borders will
be missing. This problem is fixed under JDK 1.5.
setCloningUsed (boolean cloningUsed)
Specify whether
cloning is to be used when printing with J2TextPrinter.
clone (javax.swing.JTextPane pane)
Convenience
factory method for making a new JTextPane whose StyledDocument is a
serialized copy (deep clone) of the specified JTextPane's
StyledDocument.
If your JTextPane does not have embedded images or embedded components,
then you can clone your JTextPane without resorting to serialization
using the following code:
JTextPane text2 = new JTextPane();
text2.setContentType(text1.getContentType());
text2.setText(text1.getText());
text2.setSize(text2.getPreferredSize()); // size required
The same technique can always be used for JEditorPane, which does
not support embedded images or embedded components.
When J2TextPrinter is used as a Pageable, it can have its own ("local") headers & footers (left, center, and right), margins (left, right, top, and bottom), and orientation (portrait & landscape). Headers and footers can be specified as a String or a JLabel, can be different on the first page vs. the rest of the pages of the Pageable, and can include date, time, and page numbering. The methods are the same as the parallel set of methods described in the J2Printer section under "Pageable properties".
If "local" values are not specified for this J2TextPrinter instance, the "global" (overall, default) values set using the parallel J2Printer methods will be used. You can force the J2Printer "global" values to be used by calling the J2TextPrinter method(s) with the argument J2Printer.GLOBAL.
The Pageable properties of J2TextPrinter will be ignored when the
J2TextPrinter is used as a Flowable. This is because in this case
the Pageable
is the containing J2FlowPrinter, so page properties such as headers,
footers, margins, and orientation will be controlled by the
J2FlowPrinter Pageable, not the J2TextPrinter used as a Flowable. Note,
however, that scaling does work for J2TextPrinter used as either
a Pageable or a Flowable, that is, the J2TextPrinter can appear at its
own scale within an overall J2FlowPrinter sequence.
Fit-to-page scaling
In addition to regular percentage scaling accomplished using the setScale method, J2TextPrinter also supports fit-to-page scaling when J2TextPrinter is used as a Pageable using the following method:
setMaximumPages (int pagesHigh)
Set the maximum
number of vertical pages for printing this J2TextPrinter (will minify
to fit).
The setMaximumPages method causes your J2TextPrinter to be scaled down until it fits within pagesHigh pages vertically. This method cannot be used to magnify and instead will only minify your J2TextPrinter (hence the name setMaximumPages). The method works by starting at a scale of 1.0 and reducing the scale in increments of 0.005 (half a percent) until your J2TextPrinter fits within the prescribed limits (note that if setWYSIWYG(false) is in effect, the JTextPane will reflow as scaling progresses). If pagesHigh is set to 0 or less, this is taken as a signal that the scaling is unconstrained, that is, the J2TextPrinter can use as many pages as it needs.
NOTE: This method causes the rescaling to take place at the time it is called and does NOT remember or maintain the page limits you specify. Thus, if you change any printing parameters including your document content, headers, footers, margins, paper size, orientation, etc., you must call setMaximumPages again.
The percentage and fit-to-page scaling features interact. You
can call setMaximumPages(pagesHigh) to specify a number of
pages and then use the method getScale() to find out the
resulting scaling factor. Or you can call setScale(factor)
to scale to a
desired percentage and then use getNumberOfPages() to find
out
the number of resulting pages. The getNumberOfPages()
method
works for both magnification and minification (thus you could use it to
implement your own fit-to-page feature for magnification, which you
might
call setMinimumPages(pagesHigh) ).
The underlying model of a JTextPane is an instances of the Java
class
StyledDocument. You can specify the contents of your
StyledDocument either directly by programming a StyledDocument directly
or by using Java's HTML or RTF formatted text support.
Plain text
We begin by noting that you can set the contents of a JTextPane
using
plain text simply using the code:
yourJTextPane.setContentType("text/plain");
yourJTextPane.setText(yourString);
StyledDocument
At the other end of the spectrum, the contents of a JTextPane StyledDocument can be specified using the rich text editing methods defined in the JTextPane class. These methods are the most general way to defined a StyledDocument but can be somewhat complex to use. But since many text documents can be built up sequentially by adding text in a given font to the end of the document, we have provided two methods to simplify this style of document creation.
appendStyledText (javax.swing.JTextPane pane, java.lang.String
string, javax.swing.text.SimpleAttributeSet attribute)
Convenience
method for appending text with the specified rich text attributes to
the end of a JTextPane's StyledDocument.
makeSimpleAttributeSet (java.lang.String fontName,
java.lang.String style, int size, int align, java.awt.Color color)
Convenience
factory method for making a SimpleAttributeSet for a desired Font,
specified using font name, style, size, alignment, and color.
Having created this SimpleAttributeSet instance for a desired Font, you
can optionally add numerous other text formatting attributes such as
LineSpacing, TabSet, FirstLineIndent, etc. using commands like:
StyleConstants.setLineSpacing(yourSimpleAttributeSet, spacing);
where spacing is a float giving the desired line spacing in
"points", i.e. 1/72nds of an inch.
Writing a StyledDocument to a file
The following code can write out the contents of a JTextPane
StyledDocument as a serialized object to a file:
FileOutputStream fos = new
FileOutputStream(fileName);
ObjectOutputStream oos = new
ObjectOutputStream(fos);
oos.writeObject(yourJTextPane.getStyledDocument());
oos.flush();
oos.close();
This is the same way the Java "StylePad" sample code reads and writes its files. You can use this code to write out a StyledDocument whether it was defined using the JTextPane StyledDocument methods or by reading the docuement using HTML or RTF.
Reading a StyledDocument to a file
The following code can read back the contents of a JTextPane
StyledDocument as a serialized object from a file:
EditorKit editorKit = new StyledEditorKit();
JTextPane1.setEditorKit(editorKit);
FileInputStream fis = new
FileInputStream(fileName);
ObjectInputStream ois = new
ObjectInputStream(fis);
StyledDocument doc = (StyledDocument)
ois.readObject();
ois.close();
yourJTextPane.setStyledDocument(doc);
Note that since Java has not yet solved the problem of reading
serialized data between JDK versions, you can only read and
write serialized documents created within the same JDK version.
HTML
JTextPane StyledDocuments can also be specified using HTML. While the results are not as general as creating a StyledDocument directly, it is generally easier and leverages the broad availability of HTML content and tools.
Important note: The use of HTML is limited by Java's JTextPane implementation of HTML. In general, you can only rely on basic HTML commands, and many subtags and options supported by common browsers such as Netscape or Internet Explorer are not supported by Java. Enough basic HTML is implemented to be a useful tool in creating rich text documents, but you cannot always take the HTML you get from FrontPage, Netscape, or off the web and count on JTextPane to display it properly . If you are using HTML, you first need to make sure you can get JTextPane to display your HTML, since J2TextPrinter can only print what JTextPane can display (try using J2TextPrinterTestApplication to read in HTML files). Another common problem is that you can easily define HTML content such as tables or images that may display OK but are too wide for the printed page (in which case J2TextPrinter will perform a shrink-to-fit operation to make these portions of your HTML fit).
Specifying HTML in Java
You can specify a JTextPane using HTML using code like this:
JTextPane pane = new JTextPane();
pane.setContentType("text/html");
pane.setText("<html>Here are two
lines of <b>HTML text</b>
+ "<br>that <i>will</i> be printed</html>");
To make this common operation even easier, J2TextPrinter provides a convenience method makeHTMLPane that does the same thing:
makeHTMLPane (java.lang.String html)
Convenience
factory method for creating a JTextPane using an HTML String.
However, a big advantage to using the makeHTMLPane method is that it
creates a JTextPane that uses
a special HTMLEditorKit which, unlike the default, uses synchronous
loading of images,
so that images are assured to be loaded when this method returns.
Reading HTML from a file or URL
You can also set the contents of your JTextPane by reading HTML from a
file or URL using code like the following:
JTextPane1.setContentType("text/html");
try {
java.net.URL url = new
File(fileName).toURL();
yourJTextPane.setPage(url);
} catch (Exception e) { e.printStackTrace(); }
Note that by default, setPage loads asynchronously. That is, the setPage method returns immediately and the page contents proceeds to load in the background on a separate thread, which can take some amount of time if the HTML file is big, contains images, or loads some or all of its content from over a network, etc. To make setPage load synchronously, so that the entire HTML page is loaded before setPage returns, replace the default HTMLEditorKit with one that forces synchronous loading, as follows:
yourJTextPane.setEditorKit(new HTMLEditorKit() {
public Document createDefaultDocument() {
Document doc = super.createDefaultDocument();
( (HTMLDocument) doc).setAsynchronousLoadPriority( -1);
return doc;
}
});
Using HTML Fonts
You can specify HTML fonts using the Java core Font names Serif,
SansSerif, Monospaced, etc. or using the exact same names as the core
fonts used
by Java, which on Windows are: Times New Roman, Arial, Courier, Symbol,
and WingDings. For all other designations, Java will substitute
Sans
Serif and as a result, the "Variable Width" font setting common in HTML
documents winds up as SansSerif instead of Serif as in the standard
browsers.
HTML page size
With HTML it is possible to specify content that JTextPane is not able
to paginate correctly. In particular, large images and tables
with widths specified in pixels can cause HTML documents to not fit
within the available page width. In this case, J2TextPrinter will
shrink-to-fit your HTML content in order to fit. J2TextPrinter
will always shrink to fit one page wide since J2TextPrinter does not
paginate horizontally. To paginate vertically, J2TextPrinter will
try to break HTML tables on row and/or column boundaries. If less
than getMaximumPaginationGap() of the page remains, it will skip to the
top of the next whole
page. If more than this amount remains and the next row does not
fit, it
will search inside the row for reasonable text line boundary to break
on, though this may not work across all columns of that row.
Failing that, it will cut though the table on pixel boundaries,
like an image.
RTF
JTextPane StyledDocuments can also be specified using RTF, though Java's RTF support is more limited than either HTML or using StyledDocument directly. In particular Java's RTF implementation does not support basic RTF features such as embedded graphics or tables.
Important note: Sun has not been responsive to improving its
RTF support (see
Bug Parade 4261277 ). There are many postings on Sun's Bug
Parade requesting that Sun address the problem of missing or broken RTF
features, but Sun's responses are generally negative with statements
like
these:
"The demand for RTF support seems to be low, so
implementing this is a very low priority."
"Unfortunately the RTF support in Swing is rather
limited, and we don't plan on fixing this at this time."
It appears Java's support for RTF is very unlikely to improve over its
current state, and we must advise you to either switch to the
StyledDocument or HTML formats or restrict your use of RTF to just that
narrow subset of features that presently work.
Reading RTF from a file
You can enter RTF programmatically using setContentType and setText
as in the HTML example above, but RTF is not designed as a user format
like HTML, so this is rarely done. Usually a JTextPane is used to
read in the RTF from a file using code like the following:
JTextPane1.setContentType("text/rtf");
try {
java.net.URL url = new File(fileName).toURL();
yourJTextPane.setPage(url);
} catch (Exception e) {
e.getPrintStackTrace());
Note that by default, setPage loads asynchronously. To force setPage to load synchronously, use an RTFEditorKit modified in the manner shown above for HTMLEditorKit.
RTF graphics and tables
Sun's support for RTF does not include support for embedded graphics or
tables, which are common in RTF documents. However, once you have
read an RTF document into a JTextPane, you can use the JTextPane
methods embedIcon() or embedComponent() to insert an Image or drawing
in JPanel
at a position specified by the JTextPane method setCaretPosition().
Using RTF Fonts
Sun's RTF support will preserve most styles and sizes of fonts
correctly but substitutes SansSerif font for anything that isn't
exactly the same
name as the core fonts used by Java, which on Windows are: Times New
Roman,
Arial, Courier, Symbol, and WingDings.
Page breaks
J2TextPrinter supports explicit page breaks. Simply insert a
form feed character on its own line into your document at the
point you wish to force a page break in your output. For example,
the simplest page break sequence can be specified in a Java String as:
"\n\f\n"
Note that is is a 3 character sequence
(newline-form feed-newline), not a 6 character sequence with
backslashes and letters. If you wish to type a form feed
character
directly into your JTextPane, you will either need to use your system's
ability to directly type in special characters (e.g., on some systems
you can type Ctrl-L or use a special system accessory application or
menu command). Alternatively, you can copy and paste a form feed
character from the following line (which looks like a space in Internet
Explorer and like a small box,
representing
a "non-printing" character, in Netscape):
The entire line delimited by newline ("\n") characters
surrounding the form feed ("\f") character will be
ignored in the printed output. This feature is designed to let
you represent a page break in your JTextPane using, for example the
following sequence:
"\n page break -------------- <\f>
-------------- page break \n"
so users can see the page break in the JTextPane user interface but
still have this entire line omitted from the printout.
Note that you can even use form feed characters to indicate page
breaks in HTML documents, even though HTML does not itself define a tag
for page break. However, since HTML regards all newline
characters as "soft" carriage returns and rearranges them when
rewrapping your text, you may
inadvertantly wind up with good text on the same line as your form
feed,
resulting in it being unintentionally omitted. To prevent this,
use
the following sequence to indicate a page break in an HTML document (if
specified using a Java String)::
"<p>\f<p>"
or alternatively
"<p><p>"
If you wish to type a page break directly into your HTML-based
JTextPane, you either need to use your system's special character entry
means (see above), or copy and paste the following line
(again, the character between the <p> tags looks like a space in
Internet Explorer and a small box in Netscape):
<p><p>
However, you may find an easier alternative to using form feeds for
page breaks
within a single J2TextPrinter instance is to break your JTextPane into
two JTextPanes on either side of the intended page break. Then
make separate J2TextPrinter instances for each JTextPane and use
addPageable to add each of them to your J2Printer instance. This
will result in the page break since Pageables always start on page
boundaries. Alternatively you can use a J2FlowPrinter instance,
using addFlowable to add the two J2TextPrinter instances separated by addFlowable(new
PageBreak())
.
Embedding images
You can use the standard Java JTextPane method insertIcon(Image) to embed .gif or .jpg images in your JTextPane, and J2TextPrinter will print them. If the image does not fit within the remaining space on the current page, J2TextPrinter will print the image beginning on the next page, and if the image is bigger than a page then it will be skipped entirely since JTextPane has no provision for paginating or rescaling images that are bigger than a printed page. Use J2PanelPrinter if you want to print large images either scaled to a page or tiled across multiple pages.
The insertIcon method will actually embed the Image within the flow
of the text. If you wish to place your Image on its own line, you
can accomplish this using line breaks within the JTextPane before and
after the insertIcon call, or alternatively you can intermix a
J2PanelPrinter (with an Image) and J2TextPrinter instances using
J2FlowPrinter.
Embedding components
You can use the standard Java JTextPane method insertComponent(Component) to embed any Component (or JComponent) instance in your JTextPane, and J2TextPrinter will print them. This means you can embed JTable, JTextField, JTree, JList, JPanel, or even other JTextPane instances directly in your JTextPane document. However, the same page size limitations apply as for embedding images. That is, if the component does not fit within the remaining space on the current page, J2TextPrinter will print the component beginning on the next page, and if the component is bigger than a page then it will be skipped entirely. This capability is only useful for embedding components that are less than 1 page. If you need to intermix multi-page JTables, JTrees, JLists, and/or other Components, use J2FlowPrinter to intermix J2TextPrinter, J2TablePrinter, J2TreePrinter, J2ListPrinter, and/or J2PanelPrinter instances.
The insertComponent method will actually embed the Component within the flow of the text. If you wish to place your Component on its own line, you can accomplish this using line breaks before and after the insertComponent call, or alternatively you can intermix J2PanelPrinter (with a Component) and J2TextPrinter instances using J2FlowPrinter.
NOTE: Java's JTextPane insertComponent feature is
fairly flaky (see Known Problems section), so we highly recommend
using J2FlowPrinter to embed Components in your documents using
J2PanelPrinter.
Embedding drawings
You can embed drawings created with Java Graphics or Graphics2D calls in your JTextPane document for printing with J2TextPrinter by using either the insertIcon(Image) or insertComponent(Component) methods of JTextPane. As always, the rule of thumb is that anything you can display using a JTextPane, J2TextPrinter will print.
One way to embed graphics in your JTextPane is using insertIcon(Image) . You first create a Java Image, then create a Graphics (or Graphics2D) context for it, then draw into the context using standard Java Graphics (or Graphics2D) methods, then use insertIcon(Image) to embed the image in your JTextPane. Here is some sample code for this:
Image img = new Image(300,300); // create 300
x 300 Image
Graphics g = img.getGraphics(); // get
Graphics context for image
g.drawLine(50,50,200,200); // draw into
Image using drawLine,
g.drawString("This is some graphics",150,100);
// drawString, etc.
int end =
yourJTextPane.getStyledDocument().getLength(); // find end
yourJTextPane.setCaretPosition(end); // position
at end
yourJTextPane.insertIcon(img); //
insert Image
An alternative way to embed graphics in your JTextPane is using insertComponent(Component). You first create a JPanel subclass, override its paint method to draw your graphics, then use insertComponent(Component) to embed your JPanel in your JTextPane. Here is some sample code to accomplish this (to keep the code compact, we use an inner class to define the JPanel subclass):
JPanel jp = new JPanel() { // define
JPanel subclass
public Dimension
getPreferredSize() { return new Dimension(300,300); }
public void
paint(Graphics g) { // override paint method
g.drawLine(50,50,200,200); // draw using drawLine,
g.drawString("This is some graphics",150,100); // drawString, etc.
}
};
int end =
yourJTextPane.getStyledDocument().getLength(); // find end
yourJTextPane.setCaretPosition(end); // position
at end
yourJTextPane.insertComponent(jp);
// insert Component at end
As discussed above, embedded Images or Components cannot be broken
over page boundaries, so an embedded Image or Component will
shrink-to-fit in order to fit if over half a page is available is on
the current page, or
it will skip to the next whole page and shrink-to-fit there.
If you prefer to tile rather than shrink-to-fit oversize images or
drawings, we recommend using a J2FlowPrinter and alternate
J2TextPrinter instances containing your text with J2PanelPrinter
instances containing your images or drawings.
Non-GUI JTextPane printing
It is not necessary that the JTextPane you print be in a JFrame visible on the screen. You may be printing from a server application and have no display. Or you may have a JTextPane displayed but wish to print from a different non-GUI copy of the JTextPane. The latter situation can arise when you want to set the printing JTextPane properties different from your on-screen JTextPane display, such as to force different document width and line wrap as appropriate for a printed page. In such cases, you can use code like:
JTextPane text2 = new JTextPane();
text2.setContentType(text1.getContentType());
text2.setStyledDocument(text1.getStyledDocument());
text2.setSize(text2.getPreferredSize()); // size required
Or you can just use the J2TextPrinter convenience method:
JTextPane text2 = J2TextPrinter.clone(text1);
Java Borders
You can use the Java Swing Borders classes to add various kinds of borders to your JTextPane, and these will be printed by J2TextPrinter. Borders work when using J2TextPrinter as either a Pageable or a Flowable. You can use both the Java Borders feature and the J2TextPrinter method setOutsideLines(true) at the same time (the Java Border will be inside the outside line). Some examples of Java Borders are:Freeing memory
The Java support for JTextPane imaging consumes relatively large amounts of memory, so that considerable memory space is allocated and held when printing large documents. This can lead to problems especially when printing multiple times during the running of an application. To facilitate garbage collection, J2PrinterWorks includes a dispose() method which explicitly releases all allocated storage and nulls all held references (similar to JFrame.dispose()). Important: Do not call until printing completes, i.e., only after return from print if setSeparatePrintThread(false) or only after receive printing event + isPrinting() true if setSeparatePrintThread(true).
dispose()
Release all resources held by
this J2TextPrinter object, must not be called until printing completes.
The dispose() method also can be used to fix another problem.
If you have an embedded component in your JTextPane and you call
setCloningUsed(false) because the embedded component is not cloneable
(Serializable), then J2PrinterWorks calls setVisible(true) on the
internal imaging JFrame it uses as part of printing (or print
preview). This causes a "printing..." tab to show up in the
Windows task bar, which is not removed when printing completes.
Calling dispose() when printing completes will deallocate this JFrame
and thereby cause the "printing..." tab to go away.
setDirectPrint(boolean directPrint)
The main benefit of using direct print is that text entries in the fields of an HTML form will be printed, as well as any embedded components (even if they are not cloneable) without the need to remove them from the current display.
The direct print technique only works under JDK 1.3.1, 1.4.1, and 1.4.2 or later. It does not work at all prior to JDK 1.3.1. Under JDK 1.4, there is a Java bug (Bug Parade 4708924) that causes any use of the direct print technique to throw an "IllegalStateException: constrain(xywh) is not supported for complex transform". In subsequent releases, the bug was partially fixed so that direct printing will work but prior to JDK 1.4.2_02 you can only perform a print preview with 100% scale and cannot have a JTextPane wider than getBodyWidth() which would cause the JTextPane to be scaled down.
"Widow" controlIf J2PrinterWorks.jar is properly installed, you will see the J2PrinterWorks components, including J2Printer and J2TextPrinter, in the component palette of your visual programming environment. Click on the J2Printer bean and drop it on your work area and likewise drag the J2TextPrinter bean and drop it on your work area. You will see icons representing instances of these beans. These will not be displayed at run-time.
When you bring up the property sheet for either component, you will be able to see and edit their properties. The properties may be set as desired, with values as defined in the Javadoc documentation .
You can make the J2Printer bean print by using your visual programming environment to perform event wiring from an actionPerformed event such as a button push to the J2Printer "print" event target method. You can use this to print the instance of J2TextPrinter, using the setPane method or the J2TextPrinter constructor itself to specify your JTextPane.
All the J2PrinterWorks properties are bound properties. You may use your visual programming environment to do property-to-property binding in either direction between the J2PrinterWorks components and your other beans. None of the J2PrinterWorks properties are constrained properties. This frees you from having to place try...catch blocks around your "set" calls in regular programming.
J2PrinterWorks components are fully serializable. After customizing any properties, instances can be saved along with any other beans to which they may be wired. When reloaded, the instances will come back with their customized values. No J2PrinterWorks properties are declared transient.