How to remove space in java shortcut of large size

In my application, I have a label whose font size exceeds 200. This label contains a large space up and down (irregular). How to remove it?

This is my code:

package Core; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class LabelDemo extends JPanel { public LabelDemo() { super(new GridBagLayout()); JLabel label2; GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; // Create the other labels. label2 = new JLabel("Text-Only Label"); label2.setBorder(BorderFactory.createTitledBorder("aaaaaaaa")); label2.setFont(new Font("Verdana", Font.PLAIN, (int) 220)); // label2.setBorder(new EmptyBorder(-50, 0, 0, 0)); // Add the labels. add(label2, c); } /** * Create the GUI and show it. For thread safety, this method should be invoked from the event dispatch thread. */ private static void createAndShowGUI() { // Create and set up the window. JFrame frame = new JFrame("LabelDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add content to the window. frame.add(new LabelDemo()); // Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { // Schedule a job for the event dispatch thread: // creating and showing this application GUI. SwingUtilities.invokeLater(new Runnable() { public void run() { // Turn off metal use of bold fonts UIManager.put("swing.boldMetal", Boolean.FALSE); createAndShowGUI(); } }); } } 

I also try my last post: How to change the difference in the swing shortcut and experiment with the inserts, but it looks different on Linux and Windows

Is there a better way to remove this gap?

+6
source share
3 answers

JDigit can give you some ideas:

  • It overrides paintComponent() to reduce the selection of high-resolution BufferedImage and control geometry.

  • It uses setBorderPainted(false) to set the borderPainted property.

  • It uses FocusHandler for custom highlighting.

image

Appendix: As noted here , the main problem is font FontMetrics , defined in FontMetrics as being included in the font height. As suggested in a comment by @Guillaume Polet, you can display text wherever you want in your own JComponent . TextLayout discussed here can be used to compute borders, as shown below.

Pros:

  • Absolute placement control.

  • TexteLayout border TexteLayout based on FontMetrics .

Minuses:

  • Icon Support

  • No HTML support.

Note that the authors of JComponent recommend placing the component in JPanel and setting the border on JPanel . "

Unleaded image

 import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; /** * @see https://stackoverflow.com/a/16014525/230513 */ public class UnleadedTest { private static class Unleaded extends JComponent { private Font font = new Font("Verdana", Font.PLAIN, 144); private FontRenderContext frc = new FontRenderContext(null, true, true); private String text; private TextLayout layout; private Rectangle r; public Unleaded(String text) { this.text = text; calcBounds(); } @Override public Dimension getPreferredSize() { return new Dimension(r.width, r.height); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; calcBounds(); layout.draw(g2d, -rx, -ry); } private void calcBounds() { layout = new TextLayout(text, font, frc); r = layout.getPixelBounds(null, 0, 0); } } private void display() { JFrame f = new JFrame("Unleaded"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Unleaded label = new Unleaded("Unleaded"); JPanel panel = new JPanel(); panel.setBorder(BorderFactory.createTitledBorder("Title")); panel.add(label); f.add(panel); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new UnleadedTest().display(); } }); } } 
+9
source

The "right way" for this is to extend "BasicLabelUI" and override the "protected String layoutCL ()" method. This is the method that is responsible for laying out everything inside the label and is called when the "getPreferredSize ()" JLabel is called. Thus, this method determines the height of the component.

If you drill deep enough, you will see that the height is determined by the following line in the SwingUtilities class: 1021 (which is used by layoutCL):

 textR.height = fm.getHeight(); 

Thus, the shortcut does not cause a space font. The label simply matches what the FontMetrics object says - this is the maximum font height for that size.

The easiest way is to cheat; Force the size calculation to do something that it shouldn't. Below is an example with a custom LabelUI component on which you can experiment. For example, if you force the variable "dy" to "-40", the text will be at the top. If you want to make something more durable, you can check all the letters in the label string, measure their maximum height and use it in the layoutCL method. But this is more obvious.

 package Core; import sun.swing.SwingUtilities2; import javax.swing.*; import javax.swing.plaf.LabelUI; import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.text.View; import java.awt.*; public class LabelDemo extends JPanel { public LabelDemo() { super(new GridBagLayout()); JLabel label2; GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; // Create the other labels. label2 = new JLabel("Text-Only Label"); label2.setVerticalAlignment(SwingUtilities.TOP); label2.setVerticalTextPosition(SwingUtilities.TOP); label2.setUI(SkinnyLabelUI.createUI(label2)); label2.setBorder(BorderFactory.createTitledBorder("aaaaaaaa")); label2.setFont(new Font("Verdana", Font.PLAIN, (int) 220)); // label2.setBorder(new EmptyBorder(-50, 0, 0, 0)); // Add the labels. add(label2, c); } /** * Create the GUI and show it. For thread safety, this method should be * invoked from the event dispatch thread. */ private static void createAndShowGUI() { // Create and set up the window. JFrame frame = new JFrame("LabelDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add content to the window. frame.add(new LabelDemo()); // Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { // Schedule a job for the event dispatch thread: // creating and showing this application GUI. SwingUtilities.invokeLater(new Runnable() { public void run() { // Turn off metal use of bold fonts UIManager.put("swing.boldMetal", Boolean.FALSE); createAndShowGUI(); } }); } private static class SkinnyLabelUI extends BasicLabelUI { private static final SkinnyLabelUI labelUI = new SkinnyLabelUI(); public static LabelUI createUI(JComponent c) { return labelUI; } protected String layoutCL( JLabel label, FontMetrics fm, String text, Icon icon, Rectangle viewR, Rectangle iconR, Rectangle textR) { int verticalAlignment = label.getVerticalAlignment(); int horizontalAlignment = label.getHorizontalAlignment(); int verticalTextPosition = label.getVerticalTextPosition(); int horizontalTextPosition = label.getHorizontalTextPosition(); if (icon != null) { iconR.width = icon.getIconWidth(); iconR.height = icon.getIconHeight(); } else { iconR.width = iconR.height = 0; } /* Initialize the text bounds rectangle textR. If a null * or and empty String was specified we substitute "" here * and use 0,0,0,0 for textR. */ boolean textIsEmpty = (text == null) || text.equals(""); int lsb = 0; int rsb = 0; /* Unless both text and icon are non-null, we effectively ignore * the value of textIconGap. */ int gap; View v; if (textIsEmpty) { textR.width = textR.height = 0; text = ""; gap = 0; } else { int availTextWidth; gap = (icon == null) ? 0 : label.getIconTextGap(); if (horizontalTextPosition == SwingUtilities.CENTER) { availTextWidth = viewR.width; } else { availTextWidth = viewR.width - (iconR.width + gap); } v = (label != null) ? (View) label.getClientProperty("html") : null; if (v != null) { textR.width = Math.min(availTextWidth, (int) v.getPreferredSpan(View.X_AXIS)); textR.height = (int) v.getPreferredSpan(View.Y_AXIS); } else { textR.width = SwingUtilities2.stringWidth(label, fm, text); lsb = SwingUtilities2.getLeftSideBearing(label, fm, text); if (lsb < 0) { // If lsb is negative, add it to the width and later // adjust the x location. This gives more space than is // actually needed. // This is done like this for two reasons: // 1. If we set the width to the actual bounds all // callers would have to account for negative lsb // (pref size calculations ONLY look at width of // textR) // 2. You can do a drawString at the returned location // and the text won't be clipped. textR.width -= lsb; } if (textR.width > availTextWidth) { text = SwingUtilities2.clipString(label, fm, text, availTextWidth); textR.width = SwingUtilities2.stringWidth(label, fm, text); } textR.height = fm.getHeight(); System.out.println("font height: " + textR.height); } } /* Compute textR.x,y given the verticalTextPosition and * horizontalTextPosition properties */ if (verticalTextPosition == SwingUtilities.TOP) { if (horizontalTextPosition != SwingUtilities.CENTER) { textR.y = 0; } else { textR.y = -(textR.height + gap); } } else if (verticalTextPosition == SwingUtilities.CENTER) { textR.y = (iconR.height / 2) - (textR.height / 2); } else { // (verticalTextPosition == BOTTOM) if (horizontalTextPosition != SwingUtilities.CENTER) { textR.y = iconR.height - textR.height; } else { textR.y = (iconR.height + gap); } } if (horizontalTextPosition == SwingUtilities.LEFT) { textR.x = -(textR.width + gap); } else if (horizontalTextPosition == SwingUtilities.CENTER) { textR.x = (iconR.width / 2) - (textR.width / 2); } else { // (horizontalTextPosition == RIGHT) textR.x = (iconR.width + gap); } // WARNING: DefaultTreeCellEditor uses a shortened version of // this algorithm to position it Icon. If you change how this // is calculated, be sure and update DefaultTreeCellEditor too. /* labelR is the rectangle that contains iconR and textR. * Move it to its proper position given the labelAlignment * properties. * * To avoid actually allocating a Rectangle, Rectangle.union * has been inlined below. */ int labelR_x = Math.min(iconR.x, textR.x); int labelR_width = Math.max(iconR.x + iconR.width, textR.x + textR.width) - labelR_x; int labelR_y = Math.min(iconR.y, textR.y); int labelR_height = Math.max(iconR.y + iconR.height, textR.y + textR.height) - labelR_y; int dx, dy; if (verticalAlignment == SwingUtilities.TOP) { dy = viewR.y - labelR_y; } else if (verticalAlignment == SwingUtilities.CENTER) { dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2)); } else { // (verticalAlignment == BOTTOM) dy = (viewR.y + viewR.height) - (labelR_y + labelR_height); } if (horizontalAlignment == SwingUtilities.LEFT) { dx = viewR.x - labelR_x; } else if (horizontalAlignment == SwingUtilities.RIGHT) { dx = (viewR.x + viewR.width) - (labelR_x + labelR_width); } else { // (horizontalAlignment == CENTER) dx = (viewR.x + (viewR.width / 2)) - (labelR_x + (labelR_width / 2)); } /* Translate textR and glypyR by dx,dy. */ textR.x += dx; textR.y += dy; iconR.x += dx; iconR.y += dy; if (lsb < 0) { // lsb is negative. Shift the x location so that the text is // visually drawn at the right location. textR.x -= lsb; textR.width += lsb; } if (rsb > 0) { textR.width -= rsb; } return text; } } } 
+3
source

changing the border offset can help:

 int OFFSET_TOP=50,OFFSET_BOTTOM=50; label.setBorder(new TitledBorder(TITLE){ @Override public Insets getBorderInsets(Component c, Insets insets){ return new Insets(insets.top - OFFSET_TOP, insets.left, insets.bottom - OFFSET_BOTTOM, insets.right); } }); 
0
source

All Articles