简体   繁体   English

将背景图像添加到带有圆角的JPanel

[英]Add a background image to JPanel with rounded corners

I've just recently extended JPanel for use in a project which we want to appear to be more "3D". 我刚刚将JPanel扩展用于我们希望看起来更“3D”的项目中。 That's my bosses' way of requiring shadowing and rounded corners on components. 这是我的老板要求在组件上留下阴影和圆角的方式。 That's been accomplished as shown on many online examples. 这已经完成,如许多在线示例所示。 I did it like this: 我是这样做的:

public class RoundedPanel extends JPanel
{
    protected int _strokeSize = 1;
    protected Color _shadowColor = Color.BLACK;
    protected boolean _shadowed = true;
    protected boolean _highQuality = true;
    protected Dimension _arcs = new Dimension(30, 30);
    protected int _shadowGap = 5;
    protected int _shadowOffset = 4;
    protected int _shadowAlpha = 150;

    protected Color _backgroundColor = Color.LIGHT_GRAY;

    public RoundedPanel()
    {
        super();
        setOpaque(false);
    }

    @Override
    public void setBackground(Color c)
    {
        _backgroundColor = c;
    }

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

        int width = getWidth();
        int height = getHeight();
        int shadowGap = this._shadowGap;
        Color shadowColorA = new Color(_shadowColor.getRed(), _shadowColor.getGreen(), _shadowColor.getBlue(), _shadowAlpha);
        Graphics2D graphics = (Graphics2D) g;

        if(_highQuality)
        {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }

        if(_shadowed)
        {
            graphics.setColor(shadowColorA);
            graphics.fillRoundRect(_shadowOffset, _shadowOffset, width - _strokeSize - _shadowOffset,
                    height - _strokeSize - _shadowOffset, _arcs.width, _arcs.height);
        }
        else
        {
            _shadowGap = 1;
        }

        graphics.setColor(_backgroundColor);
        graphics.fillRoundRect(0,  0, width - shadowGap, height - shadowGap, _arcs.width, _arcs.height);
        graphics.setStroke(new BasicStroke(_strokeSize));
        graphics.setColor(getForeground());
        graphics.drawRoundRect(0,  0, width - shadowGap, height - shadowGap, _arcs.width, _arcs.height);
        graphics.setStroke(new BasicStroke());
    }
}

I am creating a test frame with the following code: 我正在使用以下代码创建一个测试框架:

public class UITest
{
    private static JFrame mainFrame;
    private static ImagePanel mainPanel;

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                mainFrame = new JFrame();
                mainFrame.setVisible(true);

                try
                {
                    mainPanel = new ImagePanel(ImageIO.read(this.getClass().getResource("/content/diamondPlate_Light.jpg")));
                    //mainPanel.setBounds(0, 0, 800, 600);
                }
                catch(IOException e)
                {

                }
                mainPanel.setLayout(null);

                RoundedPanel rPanel = new RoundedPanel();
                rPanel.setBounds(10, 10, 200, 200);
                rPanel.setBackground(new Color(168, 181, 224));

                mainPanel.add(rPanel);

                rPanel = new RoundedPanel();
                rPanel.setBounds(220, 10, 560, 200);
                rPanel.setBackground(new Color(168, 224, 168));

                mainPanel.add(rPanel);

                rPanel = new RoundedPanel();
                rPanel.setBounds(10, 220, 770, 300);
                rPanel.setBackground(new Color(224, 168, 168));

                mainPanel.add(rPanel);

                mainFrame.setSize(800, 600);
                mainFrame.getContentPane().add(mainPanel);
            }
        });
    }
}

And it results in this (sans the background image of the JFrame 's contentPane : 它导致了这个(没有JFramecontentPane的背景图片:

面板

What I would really like to do is generate the red, green, and blue panels with the rounded corners, but filled by a different image instead of the Color . 我真正想做的是生成带有圆角的红色,绿色和蓝色面板,但是用不同的图像而不是Color填充。 I still want the properly rounded corners, but I'm unsure of how to do this. 我仍然想要正确的圆角,但我不确定如何做到这一点。

If I've got a large texture, can I simply "clip" a piece of it out in the size and shape of the RoundedPanel ? 如果我有一个大的纹理,我可以简单地“剪切”它的一部分在RoundedPanel的大小和形状? I need to evaluate this, since it just occurred to me as I typed, but if I can create a piece of geometry like what is used in graphics.fillRoundRect(...) and then clip the image, this could work. 我需要对此进行评估,因为它只是在我输入时发生的,但是如果我可以像在graphics.fillRoundRect(...)使用的那样创建一个几何体,然后剪切图像,这可能会起作用。

Are there any other ways of doing this that I'm missing? 有没有其他方法可以做到这一点,我错过了? I'd appreciate any feedback you might be able to offer. 我很感激您提供的任何反馈。 Thanks. 谢谢。

Edit: 编辑:

Based upon the idea in the selected solution below, I've got the following results: 基于以下所选解决方案中的想法,我得到以下结果:

面板

It needs to be whipped into shape for production and the background images are poorly chosen, but as a demo, the following RoundedPanel code gets us to the above results: 需要将其打造成生产形状并且背景图像选择不当,但作为演示,以下RoundedPanel代码将我们带到上面的结果:

public class RoundedPanel extends JPanel
{
    protected int strokeSize = 1;
    protected Color _shadowColor = Color.BLACK;
    protected boolean shadowed = true;
    protected boolean _highQuality = true;
    protected Dimension _arcs = new Dimension(30, 30);
    protected int _shadowGap = 5;
    protected int _shadowOffset = 4;
    protected int _shadowAlpha = 150;

    protected Color _backgroundColor = Color.LIGHT_GRAY;
    protected BufferedImage image = null;

    public RoundedPanel(BufferedImage img)
    {
        super();
        setOpaque(false);

        if(img != null)
        {
            image = img;
        }
    }

    @Override
    public void setBackground(Color c)
    {
        _backgroundColor = c;
    }

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

        int width = getWidth();
        int height = getHeight();
        int shadowGap = this._shadowGap;
        Color shadowColorA = new Color(_shadowColor.getRed(), _shadowColor.getGreen(), _shadowColor.getBlue(), _shadowAlpha);
        Graphics2D graphics = (Graphics2D) g;

        if(_highQuality)
        {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }

        if(shadowed)
        {
            graphics.setColor(shadowColorA);
            graphics.fillRoundRect(_shadowOffset, _shadowOffset, width - strokeSize - _shadowOffset,
                    height - strokeSize - _shadowOffset, _arcs.width, _arcs.height);
        }
        else
        {
            _shadowGap = 1;
        }

        RoundRectangle2D.Float rr = new RoundRectangle2D.Float(0, 0, (width - shadowGap), (height - shadowGap), _arcs.width, _arcs.height);

        Shape clipShape = graphics.getClip();

        if(image == null)
        {
            graphics.setColor(_backgroundColor);
            graphics.fill(rr);
        }
        else
        {
            RoundRectangle2D.Float rr2 =  new RoundRectangle2D.Float(0, 0, (width - strokeSize - shadowGap), (height - strokeSize - shadowGap), _arcs.width, _arcs.height);

            graphics.setClip(rr2);
            graphics.drawImage(this.image, 0, 0, null);
            graphics.setClip(clipShape);
        }

        graphics.setColor(getForeground());
        graphics.setStroke(new BasicStroke(strokeSize));
        graphics.draw(rr);
        graphics.setStroke(new BasicStroke());
    }
}

Thanks for the help. 谢谢您的帮助。

Try "clipping area" (see the g.setClip() call): 尝试“剪裁区域”(参见g.setClip()调用):

public static void main(String[] args) {
    JFrame f = new JFrame();
    f.setSize(new Dimension(600, 400));
    f.getContentPane().setLayout(null);
    RoundPanel rp = new RoundPanel();
    rp.setBounds(100, 50, 400, 300);
    f.getContentPane().add(rp);
    f.setVisible(true);
}

static class RoundPanel extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        // Prepare a red rectangle
        BufferedImage bi = new BufferedImage(400, 300, BufferedImage.TYPE_INT_ARGB);
        Graphics2D gb = bi.createGraphics();
        gb.setPaint(Color.RED);
        gb.fillRect(0, 0, 400, 300);
        gb.dispose();

        // Set a rounded clipping region:
        RoundRectangle2D r = new RoundRectangle2D.Float(0, 0, 400, 300, 20, 20);
        g.setClip(r);

        // Draw the rectangle (and see whether it has round corners)
        g.drawImage(bi, 0, 0, null);
    }
}

Beware of the restrictions mentioned in the API doc for Graphics.setClip : 请注意Graphics.setClip的API文档中提到的限制:

Sets the current clipping area to an arbitrary clip shape. 将当前剪切区域设置为任意剪辑形状。 Not all objects that implement the Shape interface can be used to set the clip. 并非所有实现Shape接口的对象都可用于设置剪辑。 The only Shape objects that are guaranteed to be supported are Shape objects that are obtained via the getClip method and via Rectangle objects. 唯一可以保证支持的Shape对象是通过getClip方法和Rectangle对象获得的Shape对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM