Hi everyone,
I have a JTextPane with an embedded JLabel and i am trying to print the contents of the JTextPane. When i print it an exception gets thrown saying that there is an error in the views.
This only happens if i have an embedded jcomponent in the jTextPane but other than that it prints fine with no problems. I thinking i have done something wrong with the views and have tried manipulating but nothing seems to work. I not really sure what i am doing wrong so i am listing a runnable example so you guys can run the program and see what i mean.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.awt.print.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.plaf.basic.*;
import javax.swing.text.rtf.*;
public class JWord implements ActionListener, CaretListener
{
JFrame fr = new JFrame ("Frame");
JLabel Label1 = new JLabel("Label1 ", SwingConstants.RIGHT);
JLabel Label2 = new JLabel("Hello World ", SwingConstants.RIGHT);
JButton Button1 = new JButton("Print");
JTextPane TextPane1 = new JTextPane();
//The below two command lines creates instances for fonts
SimpleAttributeSet sas = new SimpleAttributeSet();
StyleContext sc = new StyleContext();
//The below command line sets up the variable for font updating
MutableAttributeSet mas;
//Then below command line sets the style for the JTextPane document
DefaultStyledDocument dse = new DefaultStyledDocument(sc);
JScrollPane ScrollPane1 = new JScrollPane(TextPane1, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//The below command line is the constructor for the rtf editor kit
RTFEditorKit rtfkit = new RTFEditorKit();
Dimension Size1 = new Dimension();
//The below external class helps in the printing of the rtf document
RTFRenderer RTFRenderer1 = new RTFRenderer();
public void initialize ()
{
Container pane = fr.getContentPane();
pane.setLayout(new FlowLayout());
fr.setSize(250,300);
fr.setLocation(300,300);
fr.setBackground(Color.lightGray);
//The below command line is the JTextPane using the rtf editor kit
//for any rtf editing
TextPane1.setEditorKit(rtfkit);
//The below command line sets the document that the JTextPane will be
//be referencing to
TextPane1.setDocument(dse);
Size1.width = 500;
Size1.height = 300;
ScrollPane1.setPreferredSize(Size1);
pane.add(ScrollPane1);
TextPane1.insertComponent(Label2);
pane.add(Button1);
pane.add(Label1);
// Use the JAVA constant JFrame.HIDE_ON_CLOSE for subsequent forms in multi form
// applications
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Button1.addActionListener(this);
TextPane1.addCaretListener(this);
fr.pack();
fr.setVisible(true);
}
public void printData()
{
//This is the main printing function that prints out the document
//The below command line sets the current JTextPane for printing
//by using the external printing class
RTFRenderer1.setpane(TextPane1);
//The below command line gets the attributes for the JAVA print dialog
try
{
//The below two command lines gets the Printer Job and uses the
//external RTFRenderer class as its Printable
PrinterJob prnJob = PrinterJob.getPrinterJob();
PageFormat format = prnJob.pageDialog(prnJob.defaultPage());
prnJob.setPrintable(RTFRenderer1, format);
if (prnJob.printDialog() == false)
{
return;
}
//The below command line prints out the document if the user clicked Ok
prnJob.print();
}
catch (PrinterException e)
{
Label1.setText("A printing error has occurred");
}
}
public void actionPerformed(ActionEvent event)
{
JComponent b = (JComponent)event.getSource();
if(b == Button1)
{
//The below two command lines prints the current content of the document
//and repaints the main frame
printData();
fr.repaint();
}
}
public void caretUpdate(CaretEvent event)
{
JComponent w = (JComponent)event.getSource();
int g;
if(w == TextPane1)
{
g = event.getDot();
Label1.setText("Current Caret Position: " + g);
}
}
public static void main(String args[])
{
JWord a = new JWord();
a.initialize();
}
}
class RTFRenderer implements Printable
{
//This external class that does all the printing of all the rtf document pages
int currentPage = -1;
JTextPane jtextPane = new JTextPane();
double pageEndY = 0;
double pageStartY = 0;
boolean scaleWidthToFit = true;
int currentIndex = 0;
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
{
//This function is the main printable overided function
double scale = 1.0;
Graphics2D graphics2D;
View rootView;
graphics2D = (Graphics2D) graphics;
jtextPane.setSize((int)pageFormat.getImageableWidth(),Integer.MAX_VALUE);
jtextPane.validate();
//I think the error is somwhere here
rootView = jtextPane.getUI().getRootView(jtextPane);
if((scaleWidthToFit) && (jtextPane.getMinimumSize().getWidth() >
pageFormat.getImageableWidth()))
{
scale = pageFormat.getImageableWidth()/jtextPane.getMinimumSize().getWidth();
graphics2D.scale(scale, scale);
}
//The below four command lines shows that the content is clipped
//to the size of the printable page
graphics2D.setClip((int)(pageFormat.getImageableX()/scale),
(int)(pageFormat.getImageableY()/scale),
(int)(pageFormat.getImageableWidth()/scale),
(int)(pageFormat.getImageableHeight()/scale));
//The below if statement is to check to see if there is a new page to render
if(pageIndex > currentPage)
{
currentPage = pageIndex;
pageStartY += pageEndY;
pageEndY = graphics2D.getClipBounds().getHeight();
}
graphics2D.translate(graphics2D.getClipBounds().getX(),
graphics2D.getClipBounds().getY());
Rectangle allocation = new Rectangle(0, (int)-pageStartY,
(int)(jtextPane.getMinimumSize().getWidth()),
(int)(jtextPane.getPreferredSize().getHeight()));
//The below if else statements return PAGE_EXISTS only if the class
//sees that there are some contents in the document by calling the printView class
if(printView(graphics2D,allocation,rootView))
{
return PAGE_EXISTS;
}
else
{
pageStartY = 0;
pageEndY = 0;
currentPage = -1;
currentIndex = 0;
return NO_SUCH_PAGE;
}
}
protected boolean printView(Graphics2D graphics2D, Shape allocation, View view)
{
//This function paints the page if it exists
boolean pageExists = false;
Rectangle clipRectangle = graphics2D.getClipBounds();
Shape childAllocation;
View childView;
if(view.getViewCount() > 0)
{
for(int i = 0;i<view.getViewCount();i++)
{
childAllocation = view.getChildAllocation(i,allocation);
if (childAllocation != null)
{
childView = view.getView(i);
if(printView(graphics2D,childAllocation,childView))
{
pageExists = true;
}
}
}
}
else
{
//The below if statement checks if there are pages currently to paint
if(allocation.getBounds().getMaxY() >= clipRectangle.getY())
{
pageExists = true;
if((allocation.getBounds().getHeight() > clipRectangle.getHeight()) &&
(allocation.intersects(clipRectangle)))
{
view.paint(graphics2D,allocation);
}
else
{
if(allocation.getBounds().getY() >= clipRectangle.getY())
{
if(allocation.getBounds().getMaxY() <= clipRectangle.getMaxY() - 15)
{
view.paint(graphics2D,allocation);
}
else
{
if(allocation.getBounds().getY() < pageEndY)
{
pageEndY = allocation.getBounds().getY();
}
}
}
}
}
}
return pageExists;
}
public void setpane(JTextPane TextPane1)
{
//This function gets the JTextPane
jtextPane.setContentType("text/rtf");
jtextPane = TextPane1;
}
}
I am using the default styled document together with rtf editor kit and the content of the JTextPane is set to rtf.
It seems that i can print everthing else including embedded images and rtf text except an embedded jcomponent and maybe someone could have a look at my code and see what i am doing wrong and help me
print multi-page embedde jcomponents in the JTextPane
I hope someone can help me with this problem
Any help is greatly appreciated
Thank You
Yours Sincerely
Richard West