title: Java - How to visually center a specific string (not just a font) in a rectangle
body: <p>I am trying to visually center an arbitrary user-supplied string on a JPanel.  I have read dozens of other similar questions and answers here on SO but haven't found any that directly address the problem I am having.</p>
  
  <p>In the code sample below, getWidth() and getHeight() refer to the width and height of the JPanel on which I'm placing the text string.  I have found that <strong>TextLayout.getBounds()</strong> does a very good job of telling me the size of a bounding rectangle that encloses the text.  So, I figured that it would be relatively simple to center the text rectangle in the JPanel rectangle by calculating the x and y positions on the JPanel of the lower left corner of the text-bounding rectangle:</p>
  
  <pre><code>FontRenderContext context = g2d.getFontRenderContext();
  messageTextFont = new Font("Arial", Font.BOLD, fontSize);
  TextLayout txt = new TextLayout(messageText, messageTextFont, context);
  Rectangle2D bounds = txt.getBounds();
  xString = (int)((getWidth() - (int)bounds.getWidth()) / 2 );
  yString = (int)((getHeight()/2) + (int)(bounds.getHeight()/2));
  
  g2d.setFont(messageTextFont);
  g2d.setColor(rxColor);
  g2d.drawString(messageText, xString, yString);
  </code></pre>
  
  <p>This worked perfectly for strings which were all uppercase.  However, when I started testing with strings that contained lowercase letters with descenders (like g, p, y), the text was no longer centered.  The descenders on the lower case letters (the parts that extend below the baseline of the font) were being drawn too low on the JPanel to have the text appear to be centered.</p>
  
  <p>That's when I discovered (thanks to SO) that the y parameter passed to <strong>drawString()</strong> specifies the <strong>baseline</strong> of the drawn text, not the lower bound.  Thus, again with the help of SO, I realized that I needed to adjust the placement of the text by the length of the descenders in my string:</p>
  
  <pre><code>....
      TextLayout txt = new TextLayout(messageText, messageTextFont, context);
      Rectangle2D bounds = txt.getBounds();
      int descent = (int)txt.getDescent();
      xString = (int)((getWidth() - (int)bounds.getWidth()) / 2 );
      yString = (int)((getHeight()/2) + (int)(bounds.getHeight()/2) - descent);
  ....
  </code></pre>
  
  <p>I tested this with strings heavy in lowercase letters like g, p, and y and it worked great!  WooHoo!  But....wait.  Ugh.  Now when I try with only uppercase letters, the text is way too HIGH on the JPanel to look centered.</p>
  
  <p>That's when I discovered that <strong>TextLayout.getDescent()</strong> (and all the other getDescent() methods I have found for other classes) returns the maximum descent of the <strong>FONT</strong> not of the specific string.  Thus, my uppercase string was being raised up to account for descenders that didn't even occur in that string.</p>
  
  <p>What am I to do?  If I don't adjust the y parameter for drawString() to account for descenders then lowercase strings with descenders are visually too low on the JPanel.  If I do adjust the y parameter for drawString() to account for the descenders then strings which do not contain any characters with descenders are visually too high on the JPanel.  There doesn't seem to be any way for me to determine where the baseline is in the text-bounding rectangle for a GIVEN string.  Thus, I can't figure out exactly what y to pass to drawString().</p>
  
  <p>Thanks for any help or suggestions.</p>