java 如何在Swing中创建一个圆角和框形阴影的JPanel?

bqjvbblv  于 2023-05-12  发布在  Java
关注(0)|答案(1)|浏览(202)

我正在做一个应用程序,我得出的结论是,我想让面板既有一个盒子的阴影和圆角,我已经通过了一堆已经回答的问题,但我没有成功。
我有:

JPanel panel = new JPanel() {
                @Override
                protected void paintComponent(Graphics g) {
                    super.setBorder(new DropShadowBorder());
                    super.paintComponent(g);
                    Graphics2D graphics = (Graphics2D) g;
                    graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    graphics.setColor(Color.white);
                    graphics.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 10, 10);
                }
            };

这导致:

我想要的是

请帮帮忙

jq6vz3qz

jq6vz3qz1#

实际上,这是非常复杂的,至少如果你想让它看起来“酷”的话。
在我开始之前,我不会使用Border,你可以看看有没有一种方法可以使我的地址栏的JTextField更大和更弯曲的原因。
通常,我使用JH Labs image filters来生成模糊的阴影,但是对于以下内容,我将其删除,以便您可以在没有依赖项的情况下运行它。
首先,您需要一些“支持”功能。

public class ImageUtilities {

    public static void applyQualityRenderingHints(Graphics2D g2d) {
        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    }

    public static BufferedImage createCompatibleImage(int width, int height) {
        return createCompatibleImage(width, height, Transparency.TRANSLUCENT);
    }

    public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
        BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
        image.coerceData(true);
        return image;
    }

    public static BufferedImage createCompatibleImage(BufferedImage image) {
        return createCompatibleImage(image, image.getWidth(), image.getHeight());
    }

    public static BufferedImage createCompatibleImage(BufferedImage image,
            int width, int height) {
        return getGraphicsConfiguration().createCompatibleImage(width, height, image.getTransparency());
    }

    public static GraphicsConfiguration getGraphicsConfiguration() {
        return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    }

    public static BufferedImage generateMask(BufferedImage imgSource, Color color, float alpha) {
        int imgWidth = imgSource.getWidth();
        int imgHeight = imgSource.getHeight();

        BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
        Graphics2D g2 = imgBlur.createGraphics();
        applyQualityRenderingHints(g2);

        g2.drawImage(imgSource, 0, 0, null);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
        g2.setColor(color);

        g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
        g2.dispose();

        return imgBlur;
    }

    public static BufferedImage generateBlur(BufferedImage imgSource, int size, Color color, float alpha) {
        //GaussianFilter filter = new GaussianFilter(size);

        int imgWidth = imgSource.getWidth();
        int imgHeight = imgSource.getHeight();

        BufferedImage imgBlur = createCompatibleImage(imgWidth, imgHeight);
        Graphics2D g2 = imgBlur.createGraphics();
        applyQualityRenderingHints(g2);

        g2.drawImage(imgSource, 0, 0, null);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
        g2.setColor(color);

        g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
        g2.dispose();

        //imgBlur = filter.filter(imgBlur, null);

        return imgBlur;
    }

    public static BufferedImage applyShadow(Shape shape, int size, Color backgroundColor, Color shadowColor, float alpha) {
        BufferedImage sourceImage = createCompatibleImage(shape.getBounds().width, shape.getBounds().height);
        Graphics2D g2d = sourceImage.createGraphics();
        applyQualityRenderingHints(g2d);
        g2d.translate(-shape.getBounds().getX(), -shape.getBounds().getY());
        g2d.setColor(backgroundColor);
        g2d.fill(shape);
        g2d.dispose();
        return applyShadow(sourceImage, size, shadowColor, alpha);
    }
    
    public static BufferedImage applyShadow(BufferedImage imgSource, int size, Color color, float alpha) {
        BufferedImage result = createCompatibleImage(imgSource, imgSource.getWidth() + (size * 2), imgSource.getHeight() + (size * 2));
        Graphics2D g2d = result.createGraphics();
        g2d.drawImage(generateShadow(imgSource, size, color, alpha), size, size, null);
        g2d.drawImage(imgSource, 0, 0, null);
        g2d.dispose();

        return result;
    }

    public static BufferedImage generateShadow(BufferedImage imgSource, int size, Color color, float alpha) {
        int imgWidth = imgSource.getWidth() + (size * 2);
        int imgHeight = imgSource.getHeight() + (size * 2);

        BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight);
        Graphics2D g2 = imgMask.createGraphics();
        applyQualityRenderingHints(g2);

        int x = Math.round((imgWidth - imgSource.getWidth()) / 2f);
        int y = Math.round((imgHeight - imgSource.getHeight()) / 2f);
        g2.drawImage(imgSource, x, y, null);
        g2.dispose();

        // ---- Blur here ---
        BufferedImage imgGlow = generateBlur(imgMask, (size * 2), color, alpha);
        return imgGlow;
    }

    public static Image applyMask(BufferedImage sourceImage, BufferedImage maskImage) {
        return applyMask(sourceImage, maskImage, AlphaComposite.DST_IN);
    }

    public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
        BufferedImage maskedImage = null;
        if (sourceImage != null) {

            int width = maskImage.getWidth(null);
            int height = maskImage.getHeight(null);

            maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D mg = maskedImage.createGraphics();

            int x = (width - sourceImage.getWidth(null)) / 2;
            int y = (height - sourceImage.getHeight(null)) / 2;

            mg.drawImage(sourceImage, x, y, null);
            mg.setComposite(AlphaComposite.getInstance(method));

            mg.drawImage(maskImage, 0, 0, null);

            mg.dispose();
        }
        return maskedImage;
    }
}

这是一个相对简单的工作很多功能-它产生一个阴影从提供的图像或形状。它通过图像掩蔽过程来实现这一点。
我们来做个快速测试。。

public class TestPane extends JPanel {

    public TestPane() {
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        
        int size = Math.min(getWidth(), getHeight()) / 2;
        
        RoundRectangle2D border = new RoundRectangle2D.Double(0, 0, size, size, 20, 20);
        ImageUtilities.applyQualityRenderingHints(g2d);
        g2d.drawImage(ImageUtilities.applyShadow(border, 2, getBackground(), Color.BLACK, 0.25f), 5, 5, this);
        g2d.setColor(Color.DARK_GRAY);
        g2d.translate(5, 5);
        g2d.draw(border);
        g2d.dispose();
    }

}

现在,这将产生...

好了,任务完成!
好吧,不完全是。我们真正需要的是一个“复合”组件。这是一个,它将包含和管理圆形边框和阴影,但也允许使用添加组件,这不会“溢出”边框,也许像...

public class RoundedShadowPane extends JPanel {

    private double cornerRadius = 20;
    private int shadowSize = 5;
    private Color shadowColor = Color.BLACK;
    private float shadowAlpha = 0.25f;

    private JComponent contentPane;

    public RoundedShadowPane() {
        setOpaque(false);
        int shadowSize = getShadowSize();
        int cornerRadius = (int) getCornerRadius() / 4;
        setBorder(new EmptyBorder(
                shadowSize + cornerRadius, 
                shadowSize + cornerRadius, 
                shadowSize + cornerRadius + shadowSize, 
                shadowSize + cornerRadius + shadowSize
        ));
        setLayout(new BorderLayout());
        add(getContentPane());
    }

    public JComponent getContentPane() {
        if (contentPane == null) {
            contentPane = new JPanel();
        }
        return contentPane;
    }

    public void setContentPane(JComponent contentPane) {
        if (this.contentPane != null) {
            remove(this.contentPane);
        }
        this.contentPane = contentPane;
        this.setBackground(this.contentPane.getBackground());
        add(this.contentPane);
    }

    public double getCornerRadius() {
        return cornerRadius;
    }

    public int getShadowSize() {
        return shadowSize;
    }

    public Color getShadowColor() {
        return shadowColor;
    }

    public float getShadowAlpha() {
        return shadowAlpha;
    }
   
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.MAGENTA);
        g2d.fillRect(0, 0, getWidth(), getHeight());

        double cornerRadius = getCornerRadius();
        double cornerInsets = cornerRadius / 4d;

        int width = getWidth();
        int height = getHeight();
        Insets insets = getInsets();
        insets.left -= cornerInsets;
        insets.right -= cornerInsets;
        insets.top -= cornerInsets;
        insets.bottom -= cornerInsets;

        width -= insets.left + insets.right;
        height -= insets.top + insets.bottom;

        RoundRectangle2D border = new RoundRectangle2D.Double(0, 0, width, height, cornerRadius, cornerRadius);
        ImageUtilities.applyQualityRenderingHints(g2d);
        g2d.drawImage(
                ImageUtilities.applyShadow(
                        border, getShadowSize(), 
                        getBackground(), 
                        getShadowColor(), 
                        getShadowAlpha()
                ), 
                insets.left, 
                insets.top, 
                this
        );
        g2d.setColor(Color.DARK_GRAY);
        g2d.translate(insets.left, insets.top);
        g2d.draw(border);
        g2d.dispose();
    }

}

这有点复杂,重要的是要注意他们是一个单独的contentPane,所有其他组件都应该添加到其中。
比如...

public class TestPane extends JPanel {
    public TestPane() {
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        
        RoundedShadowPane shadowPane = new RoundedShadowPane();
        shadowPane.getContentPane().add(new JLabel("Everything is normal here"));
        
        gbc.gridx = 0;
        gbc.gridy = 0;
        add(shadowPane, gbc);
        
        shadowPane = new RoundedShadowPane();
        JPanel contentPane = new JPanel();
        contentPane.setBackground(Color.GREEN);
        shadowPane.setContentPane(contentPane);
        shadowPane.getContentPane().add(new JLabel("Envy with green"));
        
        gbc.gridx = 1;
        add(shadowPane, gbc);

        shadowPane = new RoundedShadowPane();
        contentPane = new JPanel();
        contentPane.setBackground(Color.BLUE);
        shadowPane.setContentPane(contentPane);
        shadowPane.getContentPane().add(new JLabel("Why so blue?"));
        
        gbc.gridy = 1;
        gbc.gridx = 0;
        add(shadowPane, gbc);
        
        shadowPane = new RoundedShadowPane();
        contentPane = new JPanel();
        contentPane.setBackground(Color.RED);
        shadowPane.setContentPane(contentPane);
        shadowPane.getContentPane().add(new JLabel("Roses are red"));
        
        gbc.gridx = 1;
        add(shadowPane, gbc);
    }
}

现在,一个聪明的人应该意识到,你实际上可以画RoundedRectangle两次,一次是阴影,一次是填充,这将是一个完全有效的方法,除了,我会包括模糊阴影,因为它“看起来”更好(恕我直言)
有没有办法可以模糊投影?
如前所述,答案是基于JPanel投影,它使用JH Labs image filters来产生模糊。
如果你想重新启用模糊,那么你需要从JH Labs下载Filters.jar,并将其链接到你的项目(不打算描述如何做到这一点)。
完成后,修改ImageUtilities类的generateBlur方法以恢复

GaussianFilter filter = new GaussianFilter(size);

imgBlur = filter.filter(imgBlur, null);

将再次实施线条和模糊。

相关问题