带圆角的边框 &透明度 [英] Border with rounded corners & transparency

查看:39
本文介绍了带圆角的边框 &透明度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下屏幕截图显示了对 TextBubbleBorder1 的测试.我想让矩形外的组件的角完全透明&显示其下方的任何组件.我找到了一种方法,通过在 Graphics2D 实例上设置 Clip(表示圆角外的区域)来将标签的 BG 颜色限制为在边框内",并且调用 clearRect().这可以在 Label 1 中看到.

但是,当父面板上有红色 BG(或任何非标准颜色)时,您可以看到这种方法的缺点.角默认为默认面板颜色(在 Panel 2 中最容易看到).

最终我希望这适用于父容器中的非标准颜色,但部分灵感来自 的公认答案中修复.仅当包含剪辑错误修复"时,才应将其视为解决方案.

<小时>

//绘制父的BG颜色,剪辑之外的所有地方//文本气泡.

在正确显示源代码的代码中看到这一点:

import java.awt.*;导入 java.awt.image.*;导入 java.awt.geom.*;导入 javax.swing.*;导入 javax.swing.border.*;公共类 BorderTest {公共静态无效主(字符串 [] args){可运行 r = 新可运行(){@覆盖公共无效运行(){JPanel gui = new JPanel(new GridLayout(2,0,5,5));gui.setBorder(new EmptyBorder(10,10,10,10));gui.setBackground(Color.RED);AbstractBorder brdrLeft = new TextBubbleBorder(Color.BLACK,2,16,16);AbstractBorder brdrRight = new TextBubbleBorder(Color.BLACK,2,16,16,false);JLabel l1 = new JLabel("标签 1");l1.setBorder(brdrRight);gui.add(l1);JLabel l2 = new JLabel("标签 2");l2.setBorder(brdrLeft);l2.setBackground(Color.YELLOW);l2.setOpaque(真);gui.add(l2);JPanel p1 = new JPanel();p1.add(new JLabel("面板 1"));p1.setBorder(brdrRight);p1.setOpaque(false);gui.add(p1);JPanel p2 = new JPanel();p2.add(new JLabel("面板 2"));p2.setBorder(brdrLeft);gui.add(p2);JOptionPane.showMessageDialog(null, gui);}};//应该在 EDT 上创建和更新 Swing GUI//http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.htmlSwingUtilities.invokeLater(r);}}类 TextBubbleBorder 扩展 AbstractBorder {私人颜色颜色;私有整数厚度 = 4;私有整数半径 = 8;私有 int 指针大小 = 7;私人插图 insets = null;private BasicStroke stroke = null;私人 intstrokePad;私有 int pointerPad = 4;私有布尔左 = 真;RenderingHints 提示;文本气泡边框(颜色颜色) {这(颜色,4、8、7);}文本气泡边框(颜色颜色,整数厚度,整数半径,整数指针大小){this.thickness = 厚度;this.radii = 半径;this.pointerSize = 指针大小;this.color = 颜色;中风 = 新的 BasicStroke(thickness);strokePad = 厚度/2;提示 = 新的渲染提示(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);int pad = radii +strokePad;int bottomPad = pad + pointerSize + strokePad;insets = new Insets(pad, pad, bottomPad, pad);}文本气泡边框(颜色颜色,整数厚度,整数半径,整数指针大小,布尔左){这(颜色,厚度,半径,指针大小);this.left = 左;}@覆盖公共插入 getBorderInsets(组件 c){返回插图;}@覆盖public Insets getBorderInsets(Component c, Insets insets) {返回 getBorderInsets(c);}@覆盖公共无效paintBorder(组分 c,图形 g,整数 x, 整数 y,整数宽度,整数高度){Graphics2D g2 = (Graphics2D) g;int bottomLineY = 高度 - 厚度 - 指针大小;RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(0 + 笔画板,0 + 笔画板,宽度 - 厚度,底线Y,半径,半径);多边形指针 = new Polygon();如果(左){//左点指针.addPoint(strokePad + radii + pointerPad,底线Y);//正确的点指针.addPoint(strokePad + radii + pointerPad + pointerSize,底线Y);//底部点指针.addPoint(strokePad + radii + pointerPad + (pointerSize/2),高度 - strokePad);} 别的 {//左点指针.addPoint(宽度 - (strokePad + radii + pointerPad),底线Y);//正确的点指针.addPoint(宽度 - (strokePad + radii + pointerPad + pointerSize),底线Y);//底部点指针.addPoint(宽度 - (strokePad + radii + pointerPad + (pointerSize/2)),高度 - strokePad);}面积=新面积(泡泡);area.add(new Area(pointer));g2.setRenderingHints(提示);//绘制父级的 BG 颜色,在剪辑之外的任何地方//文本气泡.组件父 = c.getParent();如果(父母!=空){颜色 bg = parent.getBackground();矩形 rect = new Rectangle(0,0,width, height);区域 borderRegion = 新区域(矩形);borderRegion.subtract(area);g2.setClip(borderRegion);g2.setColor(bg);g2.fillRect(0, 0, width, height);g2.setClip(null);}g2.setColor(颜色);g2.setStroke(stroke);g2.draw(区域);}}

The following screenshot shows a test of TextBubbleBorder1. I would like to make the corners of the component that are outside the rectangle to be entirely transparent & show whatever component is beneath it. I found a way to restrict the BG color of a label to 'inside the border' by setting a Clip (representing the area outside the rounded corners) on the Graphics2D instance and calling clearRect(). That can be seen in Label 1.

However you can see the downside of this approach when there is a red BG (or any non-standard color) on the parent panel. The corners default to the default panel color (easiest to see in Panel 2).

Ultimately I would like this to work for a non-standard color in the parent container, but it was partly inspired by What do I need to do to replicate this component with gradient paint?

Does anybody know a way to get those corners transparent?

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;

public class BorderTest {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new GridLayout(1,0,5,5));
                gui.setBorder(new EmptyBorder(10,10,10,10));
                gui.setBackground(Color.RED);

                AbstractBorder brdr = new TextBubbleBorder(Color.BLACK,2,16,0);

                JLabel l1 = new JLabel("Label 1");
                l1.setBorder(brdr);
                gui.add(l1);

                JLabel l2 = new JLabel("Label 2");
                l2.setBorder(brdr);
                l2.setBackground(Color.YELLOW);
                l2.setOpaque(true);
                gui.add(l2);

                JPanel p1 = new JPanel();
                p1.add(new JLabel("Panel 1"));
                p1.setBorder(brdr);
                p1.setOpaque(false);
                gui.add(p1);

                JPanel p2 = new JPanel();
                p2.add(new JLabel("Panel 2"));
                p2.setBorder(brdr);
                gui.add(p2);

                JOptionPane.showMessageDialog(null, gui);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }

}

class TextBubbleBorder extends AbstractBorder {

    private Color color;
    private int thickness = 4;
    private int radii = 8;
    private int pointerSize = 7;
    private Insets insets = null;
    private BasicStroke stroke = null;
    private int strokePad;
    private int pointerPad = 4;
    RenderingHints hints;

    TextBubbleBorder(
            Color color) {
        new TextBubbleBorder(color, 4, 8, 7);
    }

    TextBubbleBorder(
            Color color, int thickness, int radii, int pointerSize) {
        this.thickness = thickness;
        this.radii = radii;
        this.pointerSize = pointerSize;
        this.color = color;

        stroke = new BasicStroke(thickness);
        strokePad = thickness / 2;

        hints = new RenderingHints(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        int pad = radii + strokePad;
        int bottomPad = pad + pointerSize + strokePad;
        insets = new Insets(pad, pad, bottomPad, pad);
    }

    @Override
    public Insets getBorderInsets(Component c) {
        return insets;
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        return getBorderInsets(c);
    }

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

        Graphics2D g2 = (Graphics2D) g;

        int bottomLineY = height - thickness - pointerSize;

        RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
                0 + strokePad,
                0 + strokePad,
                width - thickness,
                bottomLineY,
                radii,
                radii);

        Polygon pointer = new Polygon();

        // left point
        pointer.addPoint(
                strokePad + radii + pointerPad,
                bottomLineY);
        // right point
        pointer.addPoint(
                strokePad + radii + pointerPad + pointerSize,
                bottomLineY);
        // bottom point
        pointer.addPoint(
                strokePad + radii + pointerPad + (pointerSize / 2),
                height - strokePad);

        Area area = new Area(bubble);
        area.add(new Area(pointer));

        g2.setRenderingHints(hints);

        Area spareSpace = new Area(new Rectangle(0, 0, width, height));
        spareSpace.subtract(area);
        g2.setClip(spareSpace);
        g2.clearRect(0, 0, width, height);
        g2.setClip(null);

        g2.setColor(color);
        g2.setStroke(stroke);
        g2.draw(area);
    }
}

  1. While the TextBubbleBorder was devised for Internal padding for JTextArea with background Image (& ended up using a JLabel since the text area was a mess for the reasons mentioned above), by specifying a pointerSize of 0 we end up with a 'rounded rectangle' instead.

解决方案

N.B. There is a clipping bug in this code, which is fixed in the accepted answer to paintComponent() is drawing on other components. This should only be considered as a solution if the 'clipping bug fix' is incorporated.


// Paint the BG color of the parent, everywhere outside the clip
// of the text bubble.

See this point in the code for the source that shows correctly as:

import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;

public class BorderTest {

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new GridLayout(2,0,5,5));
                gui.setBorder(new EmptyBorder(10,10,10,10));
                gui.setBackground(Color.RED);

                AbstractBorder brdrLeft = new TextBubbleBorder(Color.BLACK,2,16,16);
                AbstractBorder brdrRight = new TextBubbleBorder(Color.BLACK,2,16,16,false);

                JLabel l1 = new JLabel("Label 1");
                l1.setBorder(brdrRight);
                gui.add(l1);

                JLabel l2 = new JLabel("Label 2");
                l2.setBorder(brdrLeft);
                l2.setBackground(Color.YELLOW);
                l2.setOpaque(true);
                gui.add(l2);

                JPanel p1 = new JPanel();
                p1.add(new JLabel("Panel 1"));
                p1.setBorder(brdrRight);
                p1.setOpaque(false);
                gui.add(p1);

                JPanel p2 = new JPanel();
                p2.add(new JLabel("Panel 2"));
                p2.setBorder(brdrLeft);
                gui.add(p2);

                JOptionPane.showMessageDialog(null, gui);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }

}

class TextBubbleBorder extends AbstractBorder {

    private Color color;
    private int thickness = 4;
    private int radii = 8;
    private int pointerSize = 7;
    private Insets insets = null;
    private BasicStroke stroke = null;
    private int strokePad;
    private int pointerPad = 4;
    private boolean left = true;
    RenderingHints hints;

    TextBubbleBorder(
            Color color) {
        this(color, 4, 8, 7);
    }

    TextBubbleBorder(
            Color color, int thickness, int radii, int pointerSize) {
        this.thickness = thickness;
        this.radii = radii;
        this.pointerSize = pointerSize;
        this.color = color;

        stroke = new BasicStroke(thickness);
        strokePad = thickness / 2;

        hints = new RenderingHints(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        int pad = radii + strokePad;
        int bottomPad = pad + pointerSize + strokePad;
        insets = new Insets(pad, pad, bottomPad, pad);
    }

    TextBubbleBorder(
            Color color, int thickness, int radii, int pointerSize, boolean left) {
        this(color, thickness, radii, pointerSize);
        this.left = left;
    }

    @Override
    public Insets getBorderInsets(Component c) {
        return insets;
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        return getBorderInsets(c);
    }

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

        Graphics2D g2 = (Graphics2D) g;

        int bottomLineY = height - thickness - pointerSize;

        RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
                0 + strokePad,
                0 + strokePad,
                width - thickness,
                bottomLineY,
                radii,
                radii);

        Polygon pointer = new Polygon();

        if (left) {
            // left point
            pointer.addPoint(
                    strokePad + radii + pointerPad,
                    bottomLineY);
            // right point
            pointer.addPoint(
                    strokePad + radii + pointerPad + pointerSize,
                    bottomLineY);
            // bottom point
            pointer.addPoint(
                    strokePad + radii + pointerPad + (pointerSize / 2),
                    height - strokePad);
        } else {
            // left point
            pointer.addPoint(
                    width - (strokePad + radii + pointerPad),
                    bottomLineY);
            // right point
            pointer.addPoint(
                    width - (strokePad + radii + pointerPad + pointerSize),
                    bottomLineY);
            // bottom point
            pointer.addPoint(
                    width - (strokePad + radii + pointerPad + (pointerSize / 2)),
                    height - strokePad);
        }

        Area area = new Area(bubble);
        area.add(new Area(pointer));

        g2.setRenderingHints(hints);

        // Paint the BG color of the parent, everywhere outside the clip
        // of the text bubble.
        Component parent  = c.getParent();
        if (parent!=null) {
            Color bg = parent.getBackground();
            Rectangle rect = new Rectangle(0,0,width, height);
            Area borderRegion = new Area(rect);
            borderRegion.subtract(area);
            g2.setClip(borderRegion);
            g2.setColor(bg);
            g2.fillRect(0, 0, width, height);
            g2.setClip(null);
        }

        g2.setColor(color);
        g2.setStroke(stroke);
        g2.draw(area);
    }
}

这篇关于带圆角的边框 &amp;透明度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆