18
Font font = Font("Arial", Font.BOLD, 35);

JLabel label = new JLabel("57");
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(label);

This creates a JLabel with an extra space above and below it. I tried setVerticalAlignment(SwingConstants.TOP) but it not working. Again, I don't want to align JLabel to top but the text inside JLabel should be aligned to top.

here is how my label looks like enter image description here

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
arpanoid
  • 2,123
  • 4
  • 17
  • 15
  • forgot one line. label.setFont(font); – arpanoid Aug 18 '11 at 22:49
  • 1
    The probable reason for that is that some symbols would extend upward further than numbers, and the text alignment within the label, combined with the label's size, must take multiple font metrics into account. http://upload.wikimedia.org/wikipedia/commons/3/39/Typography_Line_Terms.svg Not an answer to your question, but it might help. – G_H Aug 18 '11 at 23:25
  • 1
    +1 for including a picture; as an aside, don't overlook the value of [`RenderingHints`](http://download.oracle.com/javase/6/docs/api/java/awt/RenderingHints.html). – trashgod Aug 19 '11 at 00:26

2 Answers2

29

The text in your label is actually aligned to the top already. Even if you set all three of:

label.setVerticalAlignment(JLabel.TOP);
label.setVerticalTextPosition(JLabel.TOP);
panel.setAlignmentY(TOP_ALIGNMENT);

you still would find that gap.

The problem is related to font-metrics. The font leaves space for diacritics, and while English numbers and even letters do not contain diacritics on capital letters, Arial definitely contains a full-breadth of international characters including ones taller than a capital letter, for example, German umlauts (ÄÖÜ) or characters containing Portuguese diacritics (ÁÂÃ).

If you want a quick, easy solution that is a hack, that may not scale well across fonts and platforms, you can use a negative value on a border to compensate for the font metrics.

label.setBorder(BorderFactory.createEmptyBorder( -3 /*top*/, 0, 0, 0 ));

If you want to fix it "right" you should look into learning about the FontMetrics package, as it has many functions that could be useful to calculating the actual height and location of the text being displayed, such that you can move the whole string by the appropriate amount of pixels.

Jessica Brown
  • 8,222
  • 7
  • 46
  • 82
  • +1 Can you comment on the relative safety of this workaround? – trashgod Aug 19 '11 at 01:00
  • +1, Nice hack. I wasn't aware that you could use negative values. :D – mre Aug 19 '11 at 01:16
  • 1
    I don't think there's anything particularly harmful to worry about, the risk is mostly that its not very robust and could offset the incorrect amount should the font be changed pragmatically, or the font be rendered a different number of pixels tall on different platforms, etc. – Jessica Brown Aug 19 '11 at 19:57
6

The arrow in your diagram points to the difference between the glyph's nominal ascent and the maximum ascent, as discussed in FontMetrics. You can tinker with setBorder(null); but for absolute control, you'll have to render the glyphs yourself, as shown here. Fortunately, the digit glyphs of most fonts have a uniform advance and ascent.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 3
    even if you do `FontMetrics fontMetrics = label.getFontMetrics(font); int offset = fontMetrics.getMaxAscent() - fontMetrics.getAscent(); System.out.println(offset);` using his sample code with the font set to Arial, you will get a difference of zero. This is actually a known bug (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6623223) that likely won't get fixed because it breaks backward compatibility and is marked with such a low priority. – Jessica Brown Aug 19 '11 at 00:42