titledBorder标题中的图标

时间:2010-03-25 20:59:33

标签: java swing

您好可以在titledBorder的标题中放置一个图标,例如以下代码:


import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class TitledExample extends JPanel {

  public TitledExample() {
    super(true);

    this.setLayout(new GridLayout(1, 1, 5, 5));

    JLabel label = new JLabel("Titled Border");
    label.setHorizontalAlignment(JLabel.CENTER);

    TitledBorder titled = new TitledBorder("Image here ?? Title");
    label.setBorder(titled);

    add(label);
  }

谢谢,干杯

6 个答案:

答案 0 :(得分:9)

尝试继承TitledBorder,并覆盖paintBorder方法:

 @Override
 public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) 
 {
     super.paintBorder(c, g, x, y, width, height);

     // Now use the graphics context to draw whatever needed
     g.drawImage(img, xImageOffset, yImageOffset, imgWidth, imgHeight, observer);
 }

不是非常确定这是完全正确的方法调用,但你明白了;一旦您可以访问Graphics对象,就可以绘制任何您需要的内容。

答案 1 :(得分:6)

这可能不是你想要的,但也许是一个不错的Unicode™ glyph或两个。

附录:@rhu's approach更可取,但我无法抗拒尝试:

enter image description here

TitledBorder titled = BorderFactory.createTitledBorder("\u2615");
titled.setTitleFont(new Font(Font.Dialog, Font.PLAIN, 32));
titled.setTitleColor(Color.blue);
label.setBorder(titled);

答案 2 :(得分:3)

您可以使用反射来访问TitledBorder使用的JLabel。

try
{
    // Get the field declaration
    Field f = TitledBorder.class.getDeclaredField("label");
    // Make it accessible (it normally is private)
    f.setAccessible(true);
    // Get the label
    JLabel borderLabel = (JLabel)f.get(titledBorder);
    // Put the field accessibility back to default
    f.setAccessible(false);
    // Set the icon and do whatever you want with your label
    borderLabel.setIcon(myIcon);
}
catch(Exception e)
{
    e.printStackTrace();
}

重要的是要注意,这在Java 10中不起作用,因为它将对setAccessible的使用有更严格的规则

答案 3 :(得分:1)

另一种方法是使用html格式。

使用img组件使图形可视化。

the result

这是一个完整的示例:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.border.TitledBorder;

public class TitledBorderIcon {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            
            // Setup GUI
            JFrame mdi = new JFrame("Test Titled Border with Icon");
            mdi.setSize(600, 400);
            mdi.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

            JLabel label = new JLabel("My Component");
            label.setHorizontalAlignment(JLabel.CENTER);
            mdi.add(label);
            
            // Build the html formatted text
            StringBuilder sb = new StringBuilder();           
            sb.append("<html>");
                sb.append("<img src=\"https://via.placeholder.com/24/007AAE/\">");
                sb.append("&nbsp;My Title");
            sb.append("</html>");
            
            TitledBorder titled = new TitledBorder(sb.toString());
            label.setBorder(titled);
            
            mdi.setVisible(true);
        });
    }    
}

答案 4 :(得分:0)

TitledBorder使用JLabel在边框上绘制文本。不幸的是,JLabel是一个私人领域。您可以通过两种方式添加图标:

  • 访问私人JLabel字段,并在JLabel上设置图标。

  • 子类TitledBorder并重新实现paintBorder方法。我&#39; d
    可能还会添加一个带有JLabel的构造函数,这样就可以了 控制边框上画的东西。

答案 5 :(得分:0)

您可以简单地将 TitledBorder 复制到您的类路径和根据需要自定义它:

例如:

public class IconTitleBorderFactory {

    public static Border create(Consumer<JLabel> leftLabelDecorator, Consumer<JLabel> rightLabelDecorator) {

        CustomTitledBorder border = new CustomTitledBorder(" ");
        border.getLabel().setHorizontalTextPosition(SwingConstants.LEFT);
        leftLabelDecorator.accept(border.getLabel());

        CustomTitledBorder border2 = new CustomTitledBorder(" ");
        border2.setTitleJustification(TitledBorder.RIGHT);
        rightLabelDecorator.accept(border2.getLabel());

        border.setBorder(border2);

        return border;
    }

    private static class CustomTitledBorder extends AbstractBorder {
        protected String title;
        protected Border border;
        protected int titlePosition;
        protected int titleJustification;
        protected Font titleFont;
        protected Color titleColor;

        private final JLabel label;

        /**
         * Use the default vertical orientation for the title text.
         */
        static public final int DEFAULT_POSITION = 0;
        /** Position the title above the border's top line. */
        static public final int ABOVE_TOP = 1;
        /** Position the title in the middle of the border's top line. */
        static public final int TOP = 2;
        /** Position the title below the border's top line. */
        static public final int BELOW_TOP = 3;
        /** Position the title above the border's bottom line. */
        static public final int ABOVE_BOTTOM = 4;
        /** Position the title in the middle of the border's bottom line. */
        static public final int BOTTOM = 5;
        /** Position the title below the border's bottom line. */
        static public final int BELOW_BOTTOM = 6;

        /**
         * Use the default justification for the title text.
         */
        static public final int DEFAULT_JUSTIFICATION = 0;
        /** Position title text at the left side of the border line. */
        static public final int LEFT = 1;
        /** Position title text in the center of the border line. */
        static public final int CENTER = 2;
        /** Position title text at the right side of the border line. */
        static public final int RIGHT = 3;
        /**
         * Position title text at the left side of the border line for left to right
         * orientation, at the right side of the border line for right to left
         * orientation.
         */
        static public final int LEADING = 4;
        /**
         * Position title text at the right side of the border line for left to right
         * orientation, at the left side of the border line for right to left
         * orientation.
         */
        static public final int TRAILING = 5;

        // Space between the border and the component's edge
        static protected final int EDGE_SPACING = 2;

        // Space between the border and text
        static protected final int TEXT_SPACING = 2;

        // Horizontal inset of text that is left or right justified
        static protected final int TEXT_INSET_H = 5;

        /**
         * Creates a TitledBorder instance.
         *
         * @param title the title the border should display
         */
        public CustomTitledBorder(String title) {
            this(null, title, LEADING, DEFAULT_POSITION, null, null);
        }

        /**
         * Creates a TitledBorder instance with the specified border and an empty title.
         *
         * @param border the border
         */
        public CustomTitledBorder(Border border) {
            this(border, "", LEADING, DEFAULT_POSITION, null, null);
        }

        /**
         * Creates a TitledBorder instance with the specified border and title.
         *
         * @param border the border
         * @param title  the title the border should display
         */
        public CustomTitledBorder(Border border, String title) {
            this(border, title, LEADING, DEFAULT_POSITION, null, null);
        }

        /**
         * Creates a TitledBorder instance with the specified border, title,
         * title-justification, and title-position.
         *
         * @param border             the border
         * @param title              the title the border should display
         * @param titleJustification the justification for the title
         * @param titlePosition      the position for the title
         */
        public CustomTitledBorder(Border border, String title, int titleJustification, int titlePosition) {
            this(border, title, titleJustification, titlePosition, null, null);
        }

        /**
         * Creates a TitledBorder instance with the specified border, title,
         * title-justification, title-position, and title-font.
         *
         * @param border             the border
         * @param title              the title the border should display
         * @param titleJustification the justification for the title
         * @param titlePosition      the position for the title
         * @param titleFont          the font for rendering the title
         */
        public CustomTitledBorder(Border border, String title, int titleJustification, int titlePosition, Font titleFont) {
            this(border, title, titleJustification, titlePosition, titleFont, null);
        }

        /**
         * Creates a TitledBorder instance with the specified border, title,
         * title-justification, title-position, title-font, and title-color.
         *
         * @param border             the border
         * @param title              the title the border should display
         * @param titleJustification the justification for the title
         * @param titlePosition      the position for the title
         * @param titleFont          the font of the title
         * @param titleColor         the color of the title
         */
        @ConstructorProperties({ "border", "title", "titleJustification", "titlePosition", "titleFont", "titleColor" })
        public CustomTitledBorder(Border border, String title, int titleJustification, int titlePosition, Font titleFont,
                Color titleColor) {
            this.title = title;
            this.border = border;
            this.titleFont = titleFont;
            this.titleColor = titleColor;

            setTitleJustification(titleJustification);
            setTitlePosition(titlePosition);

            this.label = new JLabel();
            this.label.setOpaque(false);
            this.label.putClientProperty(BasicHTML.propertyKey, null);
        }

        public JLabel getLabel() {
            return label;
        }

        /**
         * Paints the border for the specified component with the specified position and
         * size.
         * 
         * @param c      the component for which this border is being painted
         * @param g      the paint graphics
         * @param x      the x position of the painted border
         * @param y      the y position of the painted border
         * @param width  the width of the painted border
         * @param height the height of the painted border
         */
        @Override
        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
            Border border = getBorder();
            String title = getTitle();
            if ((title != null) && !title.isEmpty()) {
                int edge = (border instanceof CustomTitledBorder) ? 0 : EDGE_SPACING;
                JLabel label = getLabel(c);
                Dimension size = label.getPreferredSize();
                Insets insets = getBorderInsets(border, c, new Insets(0, 0, 0, 0));

                int borderX = x + edge;
                int borderY = y + edge;
                int borderW = width - edge - edge;
                int borderH = height - edge - edge;

                int labelY = y;
                int labelH = size.height;
                int position = getPosition();
                switch (position) {
                case ABOVE_TOP:
                    insets.left = 0;
                    insets.right = 0;
                    borderY += labelH - edge;
                    borderH -= labelH - edge;
                    break;
                case TOP:
                    insets.top = edge + insets.top / 2 - labelH / 2;
                    if (insets.top < edge) {
                        borderY -= insets.top;
                        borderH += insets.top;
                    } else {
                        labelY += insets.top;
                    }
                    break;
                case BELOW_TOP:
                    labelY += insets.top + edge;
                    break;
                case ABOVE_BOTTOM:
                    labelY += height - labelH - insets.bottom - edge;
                    break;
                case BOTTOM:
                    labelY += height - labelH;
                    insets.bottom = edge + (insets.bottom - labelH) / 2;
                    if (insets.bottom < edge) {
                        borderH += insets.bottom;
                    } else {
                        labelY -= insets.bottom;
                    }
                    break;
                case BELOW_BOTTOM:
                    insets.left = 0;
                    insets.right = 0;
                    labelY += height - labelH;
                    borderH -= labelH - edge;
                    break;
                }
                insets.left += edge + TEXT_INSET_H;
                insets.right += edge + TEXT_INSET_H;

                int labelX = x;
                int labelW = width - insets.left - insets.right;
                if (labelW > size.width) {
                    labelW = size.width;
                }
                switch (getJustification(c)) {
                case LEFT:
                    labelX += insets.left;
                    break;
                case RIGHT:
                    labelX += width - insets.right - labelW;
                    break;
                case CENTER:
                    labelX += (width - labelW) / 2;
                    break;
                }

                if (border != null) {
                    if ((position != TOP) && (position != BOTTOM)) {
                        border.paintBorder(c, g, borderX, borderY, borderW, borderH);
                    } else {
                        Graphics g2 = g.create();
                        if (g2 instanceof Graphics2D) {
                            Graphics2D g2d = (Graphics2D) g2;
                            Path2D path = new Path2D.Float();
                            path.append(new Rectangle(borderX, borderY, borderW, labelY - borderY), false);
                            path.append(new Rectangle(borderX, labelY, labelX - borderX - TEXT_SPACING, labelH), false);
                            path.append(new Rectangle(labelX + labelW + TEXT_SPACING, labelY,
                                    borderX - labelX + borderW - labelW - TEXT_SPACING, labelH), false);
                            path.append(new Rectangle(borderX, labelY + labelH, borderW,
                                    borderY - labelY + borderH - labelH), false);
                            g2d.clip(path);
                        }
                        border.paintBorder(c, g2, borderX, borderY, borderW, borderH);
                        g2.dispose();
                    }
                }
                g.translate(labelX, labelY);
                label.setSize(labelW, labelH);
                label.paint(g);
                g.translate(-labelX, -labelY);
            } else if (border != null) {
                border.paintBorder(c, g, x, y, width, height);
            }
        }

        /**
         * Reinitialize the insets parameter with this Border's current Insets.
         * 
         * @param c      the component for which this border insets value applies
         * @param insets the object to be reinitialized
         */
        @Override
        public Insets getBorderInsets(Component c, Insets insets) {
            Border border = getBorder();
            insets = getBorderInsets(border, c, insets);

            String title = getTitle();
            if ((title != null) && !title.isEmpty()) {
                int edge = (border instanceof CustomTitledBorder) ? 0 : EDGE_SPACING;
                JLabel label = getLabel(c);
                Dimension size = label.getPreferredSize();

                switch (getPosition()) {
                case ABOVE_TOP:
                    insets.top += size.height - edge;
                    break;
                case TOP: {
                    if (insets.top < size.height) {
                        insets.top = size.height - edge;
                    }
                    break;
                }
                case BELOW_TOP:
                    insets.top += size.height;
                    break;
                case ABOVE_BOTTOM:
                    insets.bottom += size.height;
                    break;
                case BOTTOM: {
                    if (insets.bottom < size.height) {
                        insets.bottom = size.height - edge;
                    }
                    break;
                }
                case BELOW_BOTTOM:
                    insets.bottom += size.height - edge;
                    break;
                }
                insets.top += edge + TEXT_SPACING;
                insets.left += edge + TEXT_SPACING;
                insets.right += edge + TEXT_SPACING;
                insets.bottom += edge + TEXT_SPACING;
            }
            return insets;
        }

        /**
         * Returns whether or not the border is opaque.
         */
        @Override
        public boolean isBorderOpaque() {
            return false;
        }

        /**
         * Returns the title of the titled border.
         *
         * @return the title of the titled border
         */
        public String getTitle() {
            return title;
        }

        /**
         * Returns the border of the titled border.
         *
         * @return the border of the titled border
         */
        public Border getBorder() {
            return border != null ? border : UIManager.getBorder("TitledBorder.border");
        }

        /**
         * Returns the title-position of the titled border.
         *
         * @return the title-position of the titled border
         */
        public int getTitlePosition() {
            return titlePosition;
        }

        /**
         * Returns the title-justification of the titled border.
         *
         * @return the title-justification of the titled border
         */
        public int getTitleJustification() {
            return titleJustification;
        }

        /**
         * Returns the title-font of the titled border.
         *
         * @return the title-font of the titled border
         */
        public Font getTitleFont() {
            return titleFont == null ? UIManager.getFont("TitledBorder.font") : titleFont;
        }

        /**
         * Returns the title-color of the titled border.
         *
         * @return the title-color of the titled border
         */
        public Color getTitleColor() {
            return titleColor == null ? UIManager.getColor("TitledBorder.titleColor") : titleColor;
        }

        // REMIND(aim): remove all or some of these set methods?

        /**
         * Sets the title of the titled border.
         * 
         * @param title the title for the border
         */
        public void setTitle(String title) {
            this.title = title;
        }

        /**
         * Sets the border of the titled border.
         * 
         * @param border the border
         */
        public void setBorder(Border border) {
            this.border = border;
        }

        /**
         * Sets the title-position of the titled border.
         * 
         * @param titlePosition the position for the border
         */
        public void setTitlePosition(int titlePosition) {
            switch (titlePosition) {
            case ABOVE_TOP:
            case TOP:
            case BELOW_TOP:
            case ABOVE_BOTTOM:
            case BOTTOM:
            case BELOW_BOTTOM:
            case DEFAULT_POSITION:
                this.titlePosition = titlePosition;
                break;
            default:
                throw new IllegalArgumentException(titlePosition + " is not a valid title position.");
            }
        }

        /**
         * Sets the title-justification of the titled border.
         * 
         * @param titleJustification the justification for the border
         */
        public void setTitleJustification(int titleJustification) {
            switch (titleJustification) {
            case DEFAULT_JUSTIFICATION:
            case LEFT:
            case CENTER:
            case RIGHT:
            case LEADING:
            case TRAILING:
                this.titleJustification = titleJustification;
                break;
            default:
                throw new IllegalArgumentException(titleJustification + " is not a valid title justification.");
            }
        }

        /**
         * Sets the title-font of the titled border.
         * 
         * @param titleFont the font for the border title
         */
        public void setTitleFont(Font titleFont) {
            this.titleFont = titleFont;
        }

        /**
         * Sets the title-color of the titled border.
         * 
         * @param titleColor the color for the border title
         */
        public void setTitleColor(Color titleColor) {
            this.titleColor = titleColor;
        }

        /**
         * Returns the minimum dimensions this border requires in order to fully display
         * the border and title.
         * 
         * @param c the component where this border will be drawn
         * @return the {@code Dimension} object
         */
        public Dimension getMinimumSize(Component c) {
            Insets insets = getBorderInsets(c);
            Dimension minSize = new Dimension(insets.right + insets.left, insets.top + insets.bottom);
            String title = getTitle();
            if ((title != null) && !title.isEmpty()) {
                JLabel label = getLabel(c);
                Dimension size = label.getPreferredSize();

                int position = getPosition();
                if ((position != ABOVE_TOP) && (position != BELOW_BOTTOM)) {
                    minSize.width += size.width;
                } else if (minSize.width < size.width) {
                    minSize.width += size.width;
                }
            }
            return minSize;
        }

        /**
         * Returns the baseline.
         *
         * @throws NullPointerException     {@inheritDoc}
         * @throws IllegalArgumentException {@inheritDoc}
         * @see javax.swing.JComponent#getBaseline(int, int)
         * @since 1.6
         */
        @Override
        public int getBaseline(Component c, int width, int height) {
            if (c == null) {
                throw new NullPointerException("Must supply non-null component");
            }
            if (width < 0) {
                throw new IllegalArgumentException("Width must be >= 0");
            }
            if (height < 0) {
                throw new IllegalArgumentException("Height must be >= 0");
            }
            Border border = getBorder();
            String title = getTitle();
            if ((title != null) && !title.isEmpty()) {
                int edge = (border instanceof CustomTitledBorder) ? 0 : EDGE_SPACING;
                JLabel label = getLabel(c);
                Dimension size = label.getPreferredSize();
                Insets insets = getBorderInsets(border, c, new Insets(0, 0, 0, 0));

                int baseline = label.getBaseline(size.width, size.height);
                switch (getPosition()) {
                case ABOVE_TOP:
                    return baseline;
                case TOP:
                    insets.top = edge + (insets.top - size.height) / 2;
                    return (insets.top < edge) ? baseline : baseline + insets.top;
                case BELOW_TOP:
                    return baseline + insets.top + edge;
                case ABOVE_BOTTOM:
                    return baseline + height - size.height - insets.bottom - edge;
                case BOTTOM:
                    insets.bottom = edge + (insets.bottom - size.height) / 2;
                    return (insets.bottom < edge) ? baseline + height - size.height
                            : baseline + height - size.height + insets.bottom;
                case BELOW_BOTTOM:
                    return baseline + height - size.height;
                }
            }
            return -1;
        }

        /**
         * Returns an enum indicating how the baseline of the border changes as the size
         * changes.
         *
         * @throws NullPointerException {@inheritDoc}
         * @see javax.swing.JComponent#getBaseline(int, int)
         * @since 1.6
         */
        @Override
        public Component.BaselineResizeBehavior getBaselineResizeBehavior(Component c) {
            super.getBaselineResizeBehavior(c);
            switch (getPosition()) {
            case CustomTitledBorder.ABOVE_TOP:
            case CustomTitledBorder.TOP:
            case CustomTitledBorder.BELOW_TOP:
                return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
            case CustomTitledBorder.ABOVE_BOTTOM:
            case CustomTitledBorder.BOTTOM:
            case CustomTitledBorder.BELOW_BOTTOM:
                return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT;
            }
            return Component.BaselineResizeBehavior.OTHER;
        }

        private int getPosition() {
            int position = getTitlePosition();
            if (position != DEFAULT_POSITION) {
                return position;
            }
            Object value = UIManager.get("TitledBorder.position");
            if (value instanceof Integer) {
                int i = (Integer) value;
                if ((0 < i) && (i <= 6)) {
                    return i;
                }
            } else if (value instanceof String) {
                String s = (String) value;
                if (s.equalsIgnoreCase("ABOVE_TOP")) {
                    return ABOVE_TOP;
                }
                if (s.equalsIgnoreCase("TOP")) {
                    return TOP;
                }
                if (s.equalsIgnoreCase("BELOW_TOP")) {
                    return BELOW_TOP;
                }
                if (s.equalsIgnoreCase("ABOVE_BOTTOM")) {
                    return ABOVE_BOTTOM;
                }
                if (s.equalsIgnoreCase("BOTTOM")) {
                    return BOTTOM;
                }
                if (s.equalsIgnoreCase("BELOW_BOTTOM")) {
                    return BELOW_BOTTOM;
                }
            }
            return TOP;
        }

        private int getJustification(Component c) {
            int justification = getTitleJustification();
            if ((justification == LEADING) || (justification == DEFAULT_JUSTIFICATION)) {
                return c.getComponentOrientation().isLeftToRight() ? LEFT : RIGHT;
            }
            if (justification == TRAILING) {
                return c.getComponentOrientation().isLeftToRight() ? RIGHT : LEFT;
            }
            return justification;
        }

        protected Font getFont(Component c) {
            Font font = getTitleFont();
            if (font != null) {
                return font;
            }
            if (c != null) {
                font = c.getFont();
                if (font != null) {
                    return font;
                }
            }
            return new Font(Font.DIALOG, Font.PLAIN, 12);
        }

        private Color getColor(Component c) {
            Color color = getTitleColor();
            if (color != null) {
                return color;
            }
            return (c != null) ? c.getForeground() : null;
        }

        private JLabel getLabel(Component c) {
            // this.label.setText(getTitle());
            this.label.setFont(getFont(c));
            this.label.setForeground(getColor(c));
            this.label.setComponentOrientation(c.getComponentOrientation());
            this.label.setEnabled(c.isEnabled());
            return this.label;
        }

        private static Insets getBorderInsets(Border border, Component c, Insets insets) {
            if (border == null) {
                insets.set(0, 0, 0, 0);
            } else if (border instanceof AbstractBorder) {
                AbstractBorder ab = (AbstractBorder) border;
                insets = ab.getBorderInsets(c, insets);
            } else {
                Insets i = border.getBorderInsets(c);
                insets.set(i.top, i.left, i.bottom, i.right);
            }
            return insets;
        }

    }

}

那么:

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {

        JFrame frame = new JFrame("Example");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel container = new JPanel();

        container.add(new JButton("A"));
        container.setBorder(IconTitleBorderFactory.create(leftLabel -> {
            leftLabel.setText("Information");
        }, rightLabel -> {
            rightLabel.setIcon(UIManager.getIcon("Tree.openIcon"));
        }));

        frame.setContentPane(container);

        frame.pack();
        frame.setSize(300, 300);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    });
}

产生:

enter image description here

注意:标签仅用于绘画。他们不在屏幕上。添加侦听器、工具提示或 getLocation() 对它们不起作用。