Cómo eliminar la brecha en la etiqueta de swing de java de gran tamaño

en mi aplicación, tengo una etiqueta que tiene un tamaño de fuente superior a 200. Esta etiqueta contiene una gran brecha hacia arriba y hacia abajo (irregular). Como puedo quitarlo ?

Este es mi código:

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's GUI. SwingUtilities.invokeLater(new Runnable() { public void run() { // Turn off metal's use of bold fonts UIManager.put("swing.boldMetal", Boolean.FALSE); createAndShowGUI(); } }); } } 

También bash mi última publicación: cómo cambiar la brecha en la etiqueta de swing y experimentar con las inserciones, pero esto se ve diferente en Linux y Windows

¿Hay alguna forma mejor de eliminar esta brecha?

JDigit puede darte algunas ideas:

  • paintComponent() para muestrear una imagen BufferedImage alta resolución y controlar la geometría.

  • Utiliza setBorderPainted(false) para establecer la propiedad borderPainted .

  • Utiliza un FocusHandler para resaltado personalizado.

imagen

Adición: Como se señala aquí , el problema subyacente es el encabezado de la fuente, definido en FontMetrics como incluido en la altura de la fuente. Como se sugiere en un comentario de @Guillaume Polet, puede representar el texto donde desee en su propio JComponent . TextLayout , discutido aquí , se puede utilizar para calcular los límites, como se muestra a continuación.

Pros:

  • Control absoluto sobre la colocación.

  • Geometry of TexteLayout bounds basado en FontMetrics .

Contras:

  • Sin soporte de Icon

  • Sin soporte HTML

Tenga en cuenta que los autores de JComponent “recomiendan que coloque el componente en un JPanel y establezca el borde en el JPanel “.

Imagen sin plomo

 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(); } }); } } 

La “forma correcta” de hacerlo sería extender “BasicLabelUI” y anular el “método protegido String layoutCL ()”. Este es el método que es responsable de diseñar todo dentro de la etiqueta y se invoca cuando se llama al “getPreferredSize ()” de JLabel. Entonces este método determina la altura que tendrá el componente.

Si profundiza lo suficiente, verá que la altura está determinada por la siguiente línea en la clase SwingUtilities: 1021 (que es utilizada por layoutCL):

 textR.height = fm.getHeight(); 

Entonces la etiqueta no está causando el espacio en blanco, la fuente es. La etiqueta solo se ajusta a lo que el objeto FontMetrics dice es la altura máxima de la fuente para ese tamaño.

La forma más fácil sería hacer trampa; Fuerce el cálculo de tamaño para hacer algo que no debería. A continuación está su ejemplo con un componente personalizado LabelUI con el que puede experimentar. Por ejemplo, si fuerza la variable a ‘dy’ a ‘-40’, el texto estará en la parte superior. Si desea hacer algo más duradero, puede verificar todos los leters en la cadena de la etiqueta, medir su altura máxima y usarla en el método layoutCL. Pero eso es más trabajo, obviamente.

 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's GUI. SwingUtilities.invokeLater(new Runnable() { public void run() { // Turn off metal's 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's 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; } } } 

cambiar el desplazamiento del borde podría ayudar:

 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); } });