父对象具有背景图像时的圆角边框

Rounded borders when parent object has a background image

我正在尝试制作圆角边框。边界内应该是设置了边界的组件决定绘制的任何东西,边界外应该是"nothing";也就是说,它应该在那些地方绘制父组件的油漆。

我想得到什么:

我得到的是:

查看带有蓝色边框的容器的白色角。我需要摆脱他们。我正在尝试通过自定义 Border 来实现此目的:

public class RoundedLineBorder extends AbstractBorder {

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        Graphics2D g2 = (Graphics2D) g;            
        int arc = 20;

        RoundRectangle2D borderRect = new RoundRectangle2D.Double(
                0, 0, width - 1, height - 1, arc, arc);
        Rectangle fullRect = new Rectangle(
                0, 0, width, height);

        Area borderArea = new Area(borderRect);
        Area parentArea = new Area(fullRect);
        parentArea.subtract(borderArea);

        Component parent = c.getParent();
        if (parent != null) {
            g2.setColor(parent.getBackground());

            /* fill parent background color outside borders */
            g2.setClip(parentArea);
            g2.fillRect(fullRect);

            g2.setClip(null);
        }

        g2.setColor(Color.blue);

        /* draw borders */
        g2.draw(borderArea);
    }

}

这在父组件有纯色背景时工作正常,但如果它有背景图片 它当然没有。有没有办法获得在下面绘制的实际颜色 上述地点?

是否有更好的方法在不实际扩展 JPanel 的情况下实现圆角边框 并在 paintComponent?

中完成所有操作

it requires a tight coupling between the border and the component,

您可以创建一个容器组件来执行此操作,这样您就不需要自定义每个组件。

类似于:

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

public class RoundedBorderContainer extends JPanel implements Border
{
    private boolean componentWasOpaque;

    public RoundedBorderContainer(JComponent component)
    {
        setLayout( new BorderLayout() );
        add( component );

        componentWasOpaque = component.isOpaque();
        component.setOpaque( false );
        setOpaque( false );

        setBorder( this );
    }

    @Override
    public void paint(Graphics g)
    {
        Graphics2D g2 = (Graphics2D) g;
        int arc = 20;
        int width = getWidth();
        int height = getHeight();

        RoundRectangle2D borderRect = new RoundRectangle2D.Double(0, 0, width, height, arc, arc);
        g2.setClip(borderRect);

        super.paint(g);
        super.paintBorder(g);

        g2.setClip( null );
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        if (componentWasOpaque)
        {
            g.setColor(getComponent(0).getBackground());
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }

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

    @Override
    public boolean isBorderOpaque()
    {
        return false;
    }

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

        int arc = 20;
        RoundRectangle2D borderRect = new RoundRectangle2D.Double(0, 0, width - 1, height - 1, arc, arc);
        Rectangle fullRect = new Rectangle(0, 0, width, height);

        Area borderArea = new Area(borderRect);
        borderArea = new Area(borderRect);
        Area parentArea = new Area(fullRect);

        g2.setColor(Color.RED);

        g2.draw(borderArea);
    }

    private static void createAndShowGUI()
    {
        JLabel label = new JLabel( new ImageIcon("grass.jpg") );
        label.setLayout( new GridBagLayout() );

        JPanel panel = new JPanel();
        panel.setPreferredSize( new Dimension(100, 100) );
        panel.setBackground( Color.BLACK );

//        JLabel panel = new JLabel( new ImageIcon("???") );

        RoundedBorderContainer rbc = new RoundedBorderContainer(panel);
        label.add(rbc);

        JFrame frame = new JFrame("Rounded Border");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( label );
        frame.setLocationByPlatform( true );
//        frame.pack();
        frame.setSize(400, 400);
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}