如何消除大尺寸java swing标签的差距

时间:2013-04-15 10:42:20

标签: java swing jlabel

在我的应用程序中,我的标签字体大小超过200.此标签包含大的上下(不规则)间隙。我该如何删除它?

这是我的代码:

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

我也尝试了我的上一篇文章:How to change gap in swing label并尝试使用插图,但这在linux和windows中看起来不同

有没有更好的方法来消除这种差距?

3 个答案:

答案 0 :(得分:9)

JDigit可能会给你一些想法:

  • 覆盖paintComponent()以对高分辨率BufferedImage进行下采样并控制几何体。

  • 它使用setBorderPainted(false)设置borderPainted属性。

  • 它使用FocusHandler进行自定义突出显示。

image

附录:如上所述here,根本问题是字体的前导,在FontMetrics中定义为包含在字体的高度中。正如@Guillaume Polet的评论中所建议的那样,您可以在自己的JComponent中随意呈现文本。讨论hereTextLayout可用于计算边界,如下所示。

优点:

  • 对展示位置的绝对控制。

  • 基于TexteLayout的{​​{1}}边界的几何。

缺点:

  • 没有FontMetrics支持。

  • 没有HTML支持。

请注意,Icon作者“建议您将该组件放在JComponent中,并在JPanel上设置边框。”

Unleaded image

JPanel

答案 1 :(得分:3)

执行此操作的“正确方法”是扩展“BasicLabelUI”并覆盖“protected String layoutCL()”方法。这是负责在标签内布局所有内容的方法,并在调用JLabel的“getPreferredSize()”时调用。因此,此方法确定组件的高度。

如果向下深入,你会看到高度由SwingUtilities:1021类中的以下行确定(由layoutCL使用):

textR.height = fm.getHeight();

因此标签不会导致空格,字体是。标签符合FontMetrics对象所说的是该大小字体的最大高度。

最简单的方法可能是作弊;强制进行大小计算以执行不应该执行的操作。下面是您可以试验的自定义LabelUI组件的示例。例如,如果强制变量'dy'为'-40',则文本将位于顶部。如果你想让更耐用的东西你可以检查标签字符串中的所有leters,测量它们的最大高度并在layoutCL方法中使用它。但那显然更有效。

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

答案 2 :(得分:0)

更改边框偏移可能会有所帮助:

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