Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove gap in java swing label of large size

Tags:

java

swing

jlabel

in my application I have label which has a font size over 200. This label contains big up and down (irregular)gap. How can I 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's GUI.
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                // Turn off metal's use of bold fonts
                UIManager.put("swing.boldMetal", Boolean.FALSE);

                createAndShowGUI();
            }
        });
    }
}

I also try my last post: How to change gap in swing label and experiment with insets but this looks different in linux and windows

Is there some better way how to remove this gap ?

like image 507
hudi Avatar asked Apr 15 '13 10:04

hudi


People also ask

How do you change the alignment of a label in Java?

A JLabel object can display either text, an image, or both. You can specify where in the label's display area the label's contents are aligned by setting the vertical and horizontal alignment. By default, labels are vertically centered in their display area.

How do you remove labels in Java?

add(label); final JButton remove = new JButton("Remove label"); leftPanel. add(remove); add. addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { rightPanel. remove(label); } });

How do I change the size of my Java Swing in Windows?

Using setSize() you can give the size of frame you want but if you use pack() , it will automatically change the size of the frames according to the size of components in it. It will not consider the size you have mentioned earlier.


2 Answers

JDigit may give you some ideas:

  • It override's paintComponent() to down-sample a high-resolution BufferedImage and control the geometry.

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

  • It uses a FocusHandler for custom highlighting.

image

Addendum: As noted here, the underlying problem is the font's leading, defined in FontMetrics as being included in the font's height. As suggested in a comment by @Guillaume Polet, you can render the text wherever you want in your own JComponent. TextLayout, discussed here, can be used to calculate the bounds, as shown below.

Pros:

  • Absolute control over placement.

  • Geometry of TexteLayout bounds based on FontMetrics.

Cons:

  • No Icon support.

  • No HTML support.

Note that the JComponent authors "recommend that you put the component in a JPanel and set the border on the 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, -r.x, -r.y);
        }

        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();
            }
        });
    }
}
like image 102
trashgod Avatar answered Oct 11 '22 20:10

trashgod


The "right way" to do this would be 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()" of the JLabel is called. So this method determines the height the component is going to be.

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

textR.height = fm.getHeight();

So the label is not causing the white space, the font is. The label just conforms to what the FontMetrics object says is the maximum height of the font for that size.

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

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;
        }
    }
}
like image 3
Jasper Siepkes Avatar answered Oct 11 '22 22:10

Jasper Siepkes