Link to home
Start Free TrialLog in
Avatar of anner
anner

asked on

Printing JTextArea

Hi
I have an app and have created a function that prints a JTable, but now I also need to print a JTextArea(on multiple pages). I am I newbie in the art of Java programming so I'm a bit at a loss on how this can be done. I guess I need to modify my print function so that it can print all kinds of components. Does anyone have some code that works better than mine to this purpose or a better idea on how I can solve this I would be grateful.

Thnx
Avatar of anner
anner

ASKER

This is my current print():
public int print(Graphics g, PageFormat pageFormat,int pageIndex) throws PrinterException
{
        Graphics2D  g2 = (Graphics2D) g;
            g2.setColor(Color.black);
            int fontHeight=g2.getFontMetrics().getHeight();
            int fontDesent=g2.getFontMetrics().getDescent();

      //leave room for page number
            double pageHeight = pageFormat.getImageableHeight()-fontHeight;
            double pageWidth = pageFormat.getImageableWidth();
            double tableWidth =(double) selectedTable.getColumnModel().getTotalColumnWidth();
            double scale = 1;
            if (tableWidth >= pageWidth)
            {
                  scale =  pageWidth / tableWidth;
            }
            double headerHeightOnPage = selectedTable.getTableHeader().getHeight()*scale;
            double tableWidthOnPage=tableWidth*scale;
            double oneRowHeight=(selectedTable.getRowHeight()+selectedTable.getRowMargin())*scale;
            int numRowsOnAPage = (int)((pageHeight-headerHeightOnPage)/oneRowHeight);
            double pageHeightForTable=oneRowHeight*numRowsOnAPage;
            int totalNumPages= (int)Math.ceil(((double)selectedTable.getRowCount())/numRowsOnAPage);
            if(pageIndex>=totalNumPages)
            {
                  System.out.println("Ingen utskrift");
                  return NO_SUCH_PAGE;
            }
            g2.translate(pageFormat.getImageableX(),pageFormat.getImageableY());
            g2.drawString("Page: "+(pageIndex+1),(int)pageWidth/2-35,(int)(pageHeight+fontHeight-fontDesent));//bottom center
            g2.translate(0f,headerHeightOnPage);
            g2.translate(0f,-pageIndex*pageHeightForTable);
      //TODO this next line treats the last page as a full page
            g2.setClip(0, (int)(pageHeightForTable*pageIndex),(int)Math.ceil(tableWidthOnPage),(int) Math.ceil(pageHeightForTable));
            g2.scale(scale,scale);
            selectedTable.paint(g2);
            g2.scale(1/scale,1/scale);
            g2.translate(0f,pageIndex*pageHeightForTable);
            g2.translate(0f, -headerHeightOnPage);
            g2.setClip(0, 0,(int) Math.ceil(tableWidthOnPage),(int)Math.ceil(headerHeightOnPage));
            g2.scale(scale,scale);
            selectedTable.getTableHeader().paint(g2);//paint header at top

            return Printable.PAGE_EXISTS;
      }
Avatar of anner

ASKER

Yes, I have seen these tutorials, but I find them a bit difficult to follow. It was managable while I only had to print a JTable but now that the same function has to print a JTextArea as well I'm in a little over my head
 If you just want to print the contents of the text area you could just get the text of the text area and send it to the printer. If you want to print the text area itself then you could modify the exampels above. Sorry I can't offer you any exact help as I have never done any printing before.
Avatar of anner

ASKER

Yes, I know it is the modifying bit that's the problem. Since the print function needs to print from both a table and a textarea wich are so different from eachother.
Try this method for the table:
     
     JTable table;
     .......

    public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
      int width = (int) pageFormat.getWidth();
      int height = (int) pageFormat.getHeight();
      g.setColor(Color.white);
      g.fillRect(0, 0, width, height);
     
      g.translate(10 * pageIndex, 10 * pageIndex);
      table.print(g);
      g.translate(-10 * pageIndex, -10 * pageIndex);
      return 1;
    }
Avatar of anner

ASKER

I call the function like this for the Table printing. The setPrintable does not seem to take a textarea as an argument. Any idea on what I'm doing wrong.
/*selectedTable=table;*/
                        PrinterJob pj=PrinterJob.getPrinterJob();
                        pj.setPrintable(this);
                        pj.printDialog();
                        try
                        {
                              pj.print();
                        }
                        catch (Exception PrintException) {}

Avatar of anner

ASKER

I print a table fine with the first function I posted, it is printing a textarea that is causing the problem.
Avatar of anner

ASKER

>>Ovi
I looked at the URL you suggested. It seems to be a bit over my head. I was thinking more in the line of calling a different print method with a different constructor. But I'm having trouble sending the textarea to the printer. I get the priterdialog but nothing seems to be sent.
I believe all you have to do if you utilize the code in the previous link is:

DocumentRenderer DocumentRenderer = new DocumentRenderer();
DocumentRenderer.print(yourTextArea.getDocument());
This class handle page breaks on printer. By default was designed to be used with JEditorPane objects, but (see my previous comment) it can accept in general JTextComponent instances with few modifications.
Avatar of anner

ASKER

>>DocumentRenderer DocumentRenderer = new DocumentRenderer();
>>DocumentRenderer.print(yourTextArea.getDocument());

Do you mean that this is all the modification I need to do to send  the content of a JTextArea to the DocumentRenderer in the previouse link?

I tried the "easy"  way and changed the JTextArea to a JEditorPane,(is there any reason way you shouldn't use a JEditorPane instead, anything a JTextArea can do that a JEditorPane can't)
ASKER CERTIFIED SOLUTION
Avatar of Ovi
Ovi

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>>"I tried the "easy"  way and changed the JTextArea to a JEditorPane,(is there any reason way you shouldn't use a JEditorPane instead, anything a JTextArea can do that a JEditorPane can't)"

This is a good choice. Basically the JEditorPane does evrithing as JTextArea, but it offers to you aditional capabilities of editing  and viewing html content (web pages) and RTFContent. I believe this is a huge difference. I suggest you to switch to JEditorPane.

In my previous comment I have modified (cut + modify) the oriiginal code and now you should be able to print any type of document. Please etest the program by pasting something on thet text area and then push the Print button. I have test it myself and seems to work fine, and paginates the text (paste a bigger one) very nice.
Avatar of anner

ASKER

Beutiful, it works, I the printer still has a problem recognizing the text format so I have to force the print but that is probably a local issue, we have just set up a printserver so problems with printing are not far between. I appreciate the code and the advice.:)
Here is an "improved" version of the class:

/*  Copyright 2002
    Kei G. Gauthier
    Suite 301
    77 Winsor Street
    Ludlow, MA  01056
*/


import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;
import javax.swing.text.StyledDocument;
import javax.swing.text.View;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.rtf.RTFEditorKit;

public class DocumentRenderer implements Printable {
      protected int currentPage = -1; //Used to keep track of when
      //the page to print changes.

      protected JTextComponent editor; //Container to hold the
      //Document. This object will
      //be used to lay out the
      //Document for printing.

      protected double pageEndY = 0; //Location of the current page
      //end.

      protected double pageStartY = 0; //Location of the current page
      //start.

      protected boolean scaleWidthToFit = true; //boolean to allow control over
      //whether pages too wide to fit
      //on a page will be scaled.

      protected PageFormat pFormat;
      protected PrinterJob pJob;

      public DocumentRenderer() {
            pFormat = new PageFormat();
            pJob = PrinterJob.getPrinterJob();
      }

      public Document getDocument() {
            if (editor != null)
                  return editor.getDocument();
            else
                  return null;
      }

      public boolean getScaleWidthToFit() {
            return scaleWidthToFit;
      }

      public void pageDialog() {
            pFormat = pJob.pageDialog(pFormat);
      }

      public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) {
            double scale = 1.0;
            Graphics2D graphics2D;
            View rootView;
            //  I
            graphics2D = (Graphics2D) graphics;
            //  II
            editor.setSize((int) pageFormat.getImageableWidth(), Integer.MAX_VALUE);
            editor.validate();
            //  III
            rootView = editor.getUI().getRootView(editor);
            //  IV
            if ((scaleWidthToFit) && (editor.getMinimumSize().getWidth() > pageFormat.getImageableWidth())) {
                  scale = pageFormat.getImageableWidth() / editor.getMinimumSize().getWidth();
                  graphics2D.scale(scale, scale);
            }
            //  V
            graphics2D.setClip(
                  (int) (pageFormat.getImageableX() / scale),
                  (int) (pageFormat.getImageableY() / scale),
                  (int) (pageFormat.getImageableWidth() / scale),
                  (int) (pageFormat.getImageableHeight() / scale));
            //  VI
            if (pageIndex > currentPage) {
                  currentPage = pageIndex;
                  pageStartY += pageEndY;
                  pageEndY = graphics2D.getClipBounds().getHeight();
            }
            //  VII
            graphics2D.translate(graphics2D.getClipBounds().getX(), graphics2D.getClipBounds().getY());
            //  VIII
            Rectangle allocation =
                  new Rectangle(0, (int) - pageStartY, (int) (editor.getMinimumSize().getWidth()), (int) (editor.getPreferredSize().getHeight()));
            //  X
            if (printView(graphics2D, allocation, rootView)) {
                  return Printable.PAGE_EXISTS;
            } else {
                  pageStartY = 0;
                  pageEndY = 0;
                  currentPage = -1;
                  return Printable.NO_SUCH_PAGE;
            }
      }

      public void print(JTextComponent editor) {
            this.editor = editor;
            printDialog();
      }

      public void print(Document plainDocument) {
            setDocument(plainDocument);
            printDialog();
      }

      protected void printDialog() {
            if (pJob.printDialog()) {
                  pJob.setPrintable(this, pFormat);
                  try {
                        pJob.print();
                  } catch (PrinterException printerException) {
                        pageStartY = 0;
                        pageEndY = 0;
                        currentPage = -1;
                        System.out.println("Error Printing Document");
                  }
            }
      }

      protected boolean printView(Graphics2D graphics2D, Shape allocation, View view) {
            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 {
                  //  I
                  if (allocation.getBounds().getMaxY() >= clipRectangle.getY()) {
                        pageExists = true;
                        //  II
                        if ((allocation.getBounds().getHeight() > clipRectangle.getHeight()) && (allocation.intersects(clipRectangle))) {
                              view.paint(graphics2D, allocation);
                        } else {
                              //  III
                              if (allocation.getBounds().getY() >= clipRectangle.getY()) {
                                    if (allocation.getBounds().getMaxY() <= clipRectangle.getMaxY()) {
                                          view.paint(graphics2D, allocation);
                                    } else {
                                          //  IV
                                          if (allocation.getBounds().getY() < pageEndY) {
                                                pageEndY = allocation.getBounds().getY();
                                          }
                                    }
                              }
                        }
                  }
            }
            return pageExists;
      }

      public void setDocument(Document document) {
            editor = new JEditorPane();
            String contentType = "text/plain";
            if (document instanceof HTMLDocument) {
                  contentType = "text/html";
            } else if (document instanceof StyledDocument) {
                  contentType = "text/rtf";
            }
            ((JEditorPane) editor).setContentType(contentType);
            editor.setDocument(document);
      }

      public void setScaleWidthToFit(boolean scaleWidth) {
            scaleWidthToFit = scaleWidth;
      }

      public static void main(String[] args) {
            JFrame f = new JFrame("JTextArea printer");
            f.getContentPane().setLayout(new BorderLayout());
            JTextComponent area = null;
            try {
                  area = new JEditorPane("http://www.google.com");
            } catch (IOException e1) {
                  e1.printStackTrace();
            }
            final Document doc = area.getDocument();
            JButton print = new JButton("Print");
            print.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                        DocumentRenderer dr = new DocumentRenderer();
                        dr.print(doc);
                  }
            });
            JPanel p = new JPanel();
            p.add(print);

            f.getContentPane().add(new JScrollPane(area), BorderLayout.CENTER);
            f.getContentPane().add(p, BorderLayout.SOUTH);

            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setSize(500, 400);
            f.setLocation(200, 100);
            f.setVisible(true);
      }
}
Thanks.