7

I'm not quite sure I understand g.drawString.

I have a program that writes to a preprinted form. The users claim that the printing is irregular...ie, text on the form is higher/lower than the previous print. Personally, I think they're misloading the form, but since they pay me to write code, I'm measuring the form and converting dimensions to pixels and rewriting the portion that deals with printing.

To print the form correctly, c.getCostAmount() has to be printed one pixel ABOVE c.getAppraisersAmount() for it to appear one line below it. Yet, each succeeding line is 4mm (or roughly 15 pixels) below that.

My problem is that I don't understand the vertical distances and why the 3rd line has to be placed a pixel above the previous line for it to be underneath.

Anybody have a quick-n-easy explanation or a link to a tutorial/explanation?

Much thanks!

The code (h/t Alex, Java: Printing program output to a physical printer):

public int print(Graphics g, PageFormat pf, int page, Check c){
    final double MILLIMETER_IN_PIXELS = 3.779527559;
    DecimalFormat df = new DecimalFormat("$#.00");

    if (page > 0) {
        return NO_SUCH_PAGE;
    }

    Graphics2D g2d = (Graphics2D) g;
    int x = (int) pf.getImageableX();
    int y = (int) pf.getImageableY();
    g2d.translate(x, y + .5);

    Font font = new Font("Courier New", Font.PLAIN, 10);
    g2d.setFont(font);
    FontMetrics metrics = g.getFontMetrics(font);
    g.drawString("CHECK #" + c.getCheckNumber(), ((int) MILLIMETER_IN_PIXELS* 55),((int) MILLIMETER_IN_PIXELS*15));

    int strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getAppraisersAmount()));
    g.drawString(df.format(c.getAppraisersAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) MILLIMETER_IN_PIXELS*23));

    Date d = c.getJavaDate();
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
    g.drawString(sdf.format(d), ((int) MILLIMETER_IN_PIXELS*90), ((int) MILLIMETER_IN_PIXELS*24));

    strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getCostAmount()));
    g.drawString(df.format(c.getCostAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*22)));

    strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getRefundsAmount()));
    g.drawString(df.format(c.getRefundsAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*26)));        

    strWidth = SwingUtilities.computeStringWidth(metrics, df.format(c.getOfficersAmount()));
    g.drawString(df.format(c.getOfficersAmount()), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*30)));

    Double totalLeft = c.getAppraisersAmount() + c.getCostAmount() + c.getRefundsAmount() + c.getOfficersAmount();
    strWidth = SwingUtilities.computeStringWidth(metrics, df.format(totalLeft));
    g.drawString(df.format(totalLeft), ((int) ((MILLIMETER_IN_PIXELS*62)-strWidth)), ((int) (MILLIMETER_IN_PIXELS*44)));

    return PAGE_EXISTS;
}
Community
  • 1
  • 1
Bob Stout
  • 1,237
  • 1
  • 13
  • 26

2 Answers2

0

Im not that good at it myself either, but in a book I read there was a really good explination about tekst and how it behaves when painted. I searched for a smiliar explination and I found one from Oracle. Here it is: http://docs.oracle.com/javase/tutorial/2d/text/measuringtext.html It's not as good but it's something. The problem with tekst is you need to take into account ascend decend and baseline to paint it correctly. Sorry I can't be of more help, I hope Oracles page it helpful enough.

Roan
  • 1,200
  • 2
  • 19
  • 32
  • I read that link previously...it helped me get to the point I am now, actually. If you remember the name of the book, let me know. My wife's not doing anything, she can make a run to the bookstore. :) – Bob Stout Oct 23 '14 at 16:08
  • 1
    Well the book was actually a digital app for android and I was called an 'introduction to java programming' and it was by thu gian viet. It was my first book and I believe the part about fonts is somewhere near the end. I don't know if it covers much more though. btw the app is for free. – Roan Oct 23 '14 at 16:11
  • By the way there is an online version of the book here: http://math.hws.edu/javanotes/ – Roan Oct 23 '14 at 17:01
  • I found the chapter in the book online here is it: http://math.hws.edu/eck/cs124/javanotes7/c13/s2.html I think your problem has something to do with the leading property. – Roan Oct 23 '14 at 17:03
  • Outstanding! Thanks! – Bob Stout Oct 23 '14 at 17:51
0

I’m not sure how you determined that MILLIMETER_IN_PIXELS value, it looks entirely suspicious to me.

However, the error which is confusing you is simply a case of missing braces:

You use the terms: ((int) MILLIMETER_IN_PIXELS*23), ((int) MILLIMETER_IN_PIXELS*24), and ((int) (MILLIMETER_IN_PIXELS*22)).

Note that the first two terms lack the braces around the product MILLIMETER_IN_PIXELS*… which means you cast MILLIMETER_IN_PIXELS to int first, getting the value 3, and multiply then, instead of performing a double multiplication first and casting to int then.

Therefore the rounding errors are different. The resulting values are 69, 72, 83.

Note, that the error of missing braces appears at some other place as well, the horizontal positions are affected too.


As an addendum, here’s how you get the real DPI:

Point2D p = g2d.getDeviceConfiguration().getDefaultTransform()
    .transform(new Point2D.Float(72,72),null);
// normally, both are the same
int horizontalDPI=(int)p.getX(), verticalDPI=(int)p.getY();

Explanation: the default transformation is specified as a transformation which will transform 72 user-space pixel to one inch, so when applying the transformation to 72, it will result in the number of device pixels matching one inch.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • That was the issue, then. Thanks, for both solving it and reinforcing my belief in my understanding of Java. – Bob Stout Oct 23 '14 at 16:30
  • 1
    Parentheses have higher priority than cast, but cast comes before multiplication (exponent doesn’t apply here as there’s no such operator in Java). By the way, if in doubt, you can put parentheses around anything and then press CTRL+1 in Eclipse an choose “Remove extra parentheses” from the popup menu which will remove all obsolete braces but retain all necessary ones. – Holger Oct 23 '14 at 16:31