Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Java Swing Printing--Jlabels With Missing Characters

setpreferredsize printing

  • Please log in to reply
30 replies to this topic

#1 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 18 April 2012 - 01:26 PM

I'm trying to write some code which will print out ID tags on 3/4" x 2" labels, but I'm getting a couple of missing characters in my JLabels. The code is as follows: (Skip to the end for pictures of the problem.)


import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.*;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

/**
 *
 * @author gwarner
 */
public class LabelPrinter implements Printable {

    JComponent comp;
    JFrame frame;

    public LabelPrinter() {

        frame = new JFrame("label test");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));

        // printPanel is the component which will get printed:
        JPanel printPanel = new JPanel();
        Dimension printSize = new Dimension(144, 54);
        printPanel.setSize(printSize);
        printPanel.setPreferredSize(printSize);
        printPanel.setMinimumSize(printSize);
        printPanel.setMaximumSize(printSize);
        printPanel.setLayout(new BoxLayout(printPanel, BoxLayout.PAGE_AXIS));
        printPanel.setBorder(BorderFactory.createEmptyBorder(0, 18, 0, 0));
        printPanel.setBackground(Color.WHITE);

        Font font = new Font("Arial", Font.PLAIN, 8);

        JLabel patientLabel = new JLabel("PATIENT: Doe, John");
        patientLabel.setFont(font);
        patientLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        printPanel.add(patientLabel);

        JLabel ssnLabel = new JLabel("SSN: 123-45-6789 DOB: 01/01/08");
        ssnLabel.setFont(font);
        ssnLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        printPanel.add(ssnLabel);

        JLabel idLabel = new JLabel("ID #: T1234");
        idLabel.setFont(font);
        idLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        printPanel.add(idLabel);

        // Store this component for printing later.
        comp = printPanel;

        // The purpose of viewPanel is just to put a little border around the preview onscreen. This border shouldn't be printed, though.
        JPanel viewPanel = new JPanel();
        viewPanel.setBorder(BorderFactory.createEmptyBorder(9, 0, 9, 18));
        viewPanel.setBackground(Color.WHITE);
        viewPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
        viewPanel.add(comp);
        panel.add(viewPanel);

        JButton printButton = new JButton("Print");
        printButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        printButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                PrinterJob job = PrinterJob.getPrinterJob();
                if (job.printDialog()) {
                    try {
                        PageFormat format = job.defaultPage();
                        Paper paper = format.getPaper();
                        paper.setSize(54.0, 144.0);
                        paper.setImageableArea(0.0, 0.0, 54.0, 144.0);
                        format.setPaper(paper);
                        format.setOrientation(PageFormat.LANDSCAPE);
                        Book book = new Book();
                        book.append(LabelPrinter.this, format);
                        job.setPageable(book);
                        job.print();
                    } catch (PrinterException ex) {
                        Logger.getLogger(LabelPrinter.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        panel.add(printButton);

        frame.add(panel);
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                @Override
                public void run() {
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        } catch (InterruptedException ex) {
            Logger.getLogger(LabelPrinter.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(LabelPrinter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void main(String[] args) {

        final LabelPrinter label = new LabelPrinter();
    }

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {

        if (pageIndex > 0) {
            return NO_SUCH_PAGE;
        } else {
            Graphics2D g2d = (Graphics2D) graphics;

            g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());

            disableDoubleBuffering(comp);
            comp.printAll(g2d);
            enableDoubleBuffering(comp);

            return PAGE_EXISTS;
        }
    }

    public static void disableDoubleBuffering(JComponent c) {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(false);
    }

    public static void enableDoubleBuffering(JComponent c) {
        RepaintManager currentManager = RepaintManager.currentManager(c);
        currentManager.setDoubleBufferingEnabled(true);
    }
}

It looks fine on the screen:
Posted Image

However, when I print it, there are 2 problems: The 'n' on the name line is getting cut off, and the space between the SSN and the DOB has disappeared: (I've rotated the image 90 degrees since the label is printed in landscape, and it shows up vertically on the PDF. This orientation is correct.) I'm using PrimoPDF to simulate a printer here by capturing the print job as a PDF file. What's interesting is the I-beam cursor selects as though the space and the 'n' are still there, they're just invisible in the case of the 'n', and of negative width in the case of the space.
Posted Image

Likewise, when I actually print it, you can see that the 'n' is still cut off, though not quite as much, but the space between the SSN and the DOB is still missing:
Posted Image

I'm printing this on a Dymo LabelWriter 330 Turbo.

What's weird to me is that the 1st line is cutting off at the end, but the 2nd line is ignoring my space in the middle of the string, which seems strange since it should cut off only at the end if it was some sort of margin width or container width issue. There's also nothing wrong with the 3rd line. In other words, the behavior doesn't seem consistent. Any ideas what's causing this?
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#2 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 18 April 2012 - 09:45 PM

It looks fine on the screen


Try to use the g2d object you get from the print method and throw it onto a JPanel. (Make panel a class variable, and call panel.paint(g2d) at the end of the print method as a quick 'n dirty test :) )

If it then looks bad on the screen, it has nothing to do with the printing or pdf,
but with how the Graphics object gets filled (in comp.printAll(g2d); )


And for the printing, did you mean printing the PDF, or printing straight from Java to printer?
  • 0

#3 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 19 April 2012 - 05:20 AM

Try to use the g2d object you get from the print method and throw it onto a JPanel. (Make panel a class variable, and call panel.paint(g2d) at the end of the print method as a quick 'n dirty test :) )

I believe that's what I did here: (Correct me if I'm wrong) Does 'comp' have to be of type JPanel rather than JComponent?
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
    ...
    Graphics2D g2d = (Graphics2D) graphics;
    ....
    comp.printAll(g2d); // 'comp' is the JPanel I wish to print.
    ....
}
What should I do differently?

If it then looks bad on the screen, it has nothing to do with the printing or pdf,
but with how the Graphics object gets filled (in comp.printAll(g2d); )

It looks fine on the screen. It's only when it gets printed that it looks wrong.

And for the printing, did you mean printing the PDF, or printing straight from Java to printer?

Both. Both methods are using the same printing API's in the JDK. PrimoPDF creates a virtual printer device that Windows can print to just like any other printer, except that the output gets redirected to a PDF file rather than a physical device. (It saves me paper while I'm testing.) Both the virtual printer and the physical label printer exhibit the same problems.

EDIT: What is confusing to me is that I pretty much followed some tutorials I found on the web to the letter, yet none of them talked about this kind of issue. Nor can I find a Google search string to yield results that deal with this specific issue.
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#4 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 19 April 2012 - 05:58 AM

Oh, I'm sorry. I guess I skimmed trough your post too fast.
I'll definitely try your code out at home in about 2-3 hours. This is quite interesting behaviour :)
  • 0

#5 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 19 April 2012 - 06:02 AM

Thanks. I feel like I'm going crazy. :)
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#6 lethalwire

lethalwire

    while(false){ ... }

  • Senior Member
  • PipPipPipPipPipPip
  • 766 posts
  • Programming Language:C, Java, PHP, JavaScript
  • Learning:PHP

Posted 19 April 2012 - 06:12 AM

Weeirrdd.... Here's where I'm at right now:


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class HelloPrint extends JPanel implements Printable {

	public static void main(String[] args) {
   	   final JFrame frame = new JFrame("Hello Frame");
			
   	   final HelloPrint printPanel = new HelloPrint();
   	   printPanel.add(new JLabel("PATIENT: Doe, John"));
   	   printPanel.add(new JLabel("SSN: 123-45-6789 DOB: 01/01/08"));
   	   printPanel.add(new JLabel("ID #: T1234"));
   	   printPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
   	   printPanel.setPreferredSize(new Dimension(144,54));
   	   printPanel.setMinimumSize(new Dimension(144,54));
   		
   	   frame.getContentPane().add(printPanel);
   		
   	   //frame.setSize(400,400);
   	   frame.pack();
   		
   	   //invokeLater() is used as a workaround for a java
   	   //gui bug.
   	   SwingUtilities.invokeLater(new Runnable() {
   		  public void run() {
   			 try {
   				frame.setVisible(true);
   						
   				//get a PrintJob
   				PrinterJob pjob = PrinterJob.getPrinterJob();
   				//set a HelloPrint as the target to print
   				pjob.setPrintable(printPanel, pjob.defaultPage());
   				//get the print dialog, continue if canel
   				//is not clicked
   				if (pjob.printDialog()) {
   				   //print the target (HelloPrint)
   				   pjob.print();
   				}
   			 } catch (Exception e) {
   				e.printStackTrace();
   			 }
   		  }
   	   });
	   				
	   }

	/**
	 * We happen to implement a paint method, but this could be ignored for
	 * components that already to something interesting on their own.
	 */
	//public void paint(Graphics g) {
		//super.paint(g);
		//g.drawString("Hello world!", 35, 100);
	//}

	/**
	 * Printable's implementation
	 */
	public int print(Graphics g, PageFormat pf, int pageIndex) {
		// assume the page exists until proven otherwise
		int retval = Printable.PAGE_EXISTS;

		// We only want to deal with the first page.
		// The first page is numbered '0'
		if (pageIndex > 0) {
			retval = Printable.NO_SUCH_PAGE;
		} else {
			// setting up the Graphics object for printing
			g.translate((int) (pf.getImageableX()), (int) (pf.getImageableY()));
			// populate the Graphics object from HelloPrint's paint() method
			paint(g);
		}

		return retval;
	}
}

Notice how it's dragging the 'n' in John to the next line? I wonder if it has to do something with the Dimensions... It's also weird because it pulls part of the date outside of the border...

*****EDIT*****: Bah... It might have something to do with the panels Layout. I just changed the printPanel's layout to GridLayout(3,1) and it printed fine.
  • 0

#7 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 19 April 2012 - 06:19 AM

*****EDIT*****: Bah... It might have something to do with the panels Layout. I just changed the printPanel's layout to GridLayout(3,1) and it printed fine.


Weird. I never considered the Layout Manager as the culprit. I'll give this a try.

Thanks.
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#8 wim DC

wim DC

    Roar

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 2681 posts
  • Programming Language:Java, JavaScript, PL/SQL
  • Learning:Python

Posted 19 April 2012 - 06:19 AM

Prints perfectly with your code, greg. Using Cute pdf writer. (And java 5 at work)
  • 0

#9 lethalwire

lethalwire

    while(false){ ... }

  • Senior Member
  • PipPipPipPipPipPip
  • 766 posts
  • Programming Language:C, Java, PHP, JavaScript
  • Learning:PHP

Posted 19 April 2012 - 06:20 AM

Prints perfectly with your code, greg. Using Cute pdf writer. (And java 5 at work)


I can't get it to print perfectly with that code... jdk7 :\
  • 0

#10 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 19 April 2012 - 06:31 AM

Huh. I'm JDK 6 here.
Is it perhaps a JDK bug?
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#11 lethalwire

lethalwire

    while(false){ ... }

  • Senior Member
  • PipPipPipPipPipPip
  • 766 posts
  • Programming Language:C, Java, PHP, JavaScript
  • Learning:PHP

Posted 19 April 2012 - 06:38 AM

It also might be a printer deal. I guess if page.setSize( your size here ) can't match a size of paper to your printer, it finds the closest page size and uses that as your paper size.

I added 3 spaces in between the SSN and DOB.
Then I changed some code to:
PageFormat format = job.defaultPage();
Paper paper = format.getPaper();
//paper.setSize(printSize.getHeight(), printSize.getWidth());
paper.setImageableArea(18.0, 140.0, paper.getHeight(), paper.getWidth());

At the same time though, I'm thinking this may not work for you because of possible printer size options.

Edit**
Also changed:
	    final JPanel printPanel = new JPanel();
	    final Dimension printSize = new Dimension(134, 34);
	    //printPanel.setSize(printSize);
	    printPanel.setPreferredSize(printSize);
	    printPanel.setMinimumSize(printSize);
	    printPanel.setMaximumSize(printSize);
	    printPanel.setLayout(new GridLayout(3, 1, 0, 0));
	    //printPanel.setBorder(BorderFactory.createEmptyBorder(0, 18, 0, 0));
	    //printPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
	    printPanel.setBackground(Color.WHITE);

  • 0

#12 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 19 April 2012 - 06:46 AM

It also might be a printer deal. I guess if page.setSize( your size here ) can't match a size of paper to your printer, it finds the closest page size and uses that as your paper size.

I thought you might have been right about this, but I commented out all the lines in the ActionListener which alter the PageFormat and Paper, and let it keep the default format and paper size, yet the issue remained.

Did your changes above work for you?
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid






Also tagged with one or more of these keywords: setpreferredsize, printing

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download