有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java Swing将透明性应用于透明JPanel上的组件

我正在努力创建一个支持透明性的JPanel,并且遇到了一个问题,我不确定如何将相同级别的透明性应用于添加到此面板的所有Component。到目前为止,我的代码是:

package de.uebertreiberman.project.swing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class JTransparancyPanel extends JPanel {

    float opacity = 1.0f;

    /**Constructor for JTransparentPanel
     */
    public JTransparancyPanel()
    {
        super();
        this.setOpaque(false);
    }

    /**Getter for opacity value of panel
     * 
     * @return float containing opacity value of frame (0-1)
     */
    public float getOpacity()
    {
        return opacity;
    }

    /**Setter for opacity value of panel
     * 
     * @param value as float for opacity of frame (0-1)
     */
    public void setOpacity(float value)
    {
        opacity = value;
        repaint();
    }

    /**Converts opacity value (0-1) to opacity color (0-255)
     * 
     * @param opacity as float opacity value (0-1)
     * @return integer containing converted opacity value (0-255)
     */
    public static int getOpacityColor(float opacity)
    {
        return (int)(opacity * 255);
    }

    /**Converts opacity color (0-255) to opacity value (0-1)
     * 
     * @param opacity as integer value (0-255)
     * @return float containing converted opacity value (0-1)
     */
    public static float getOpacityValue(int opacity)
    {
        //Returns more or less the correct, capped value
        //Just ignore it, it works, leave it :D
        return capFloat((3.9216f*opacity)/1000f, 0.0f, 1.0f);
    }

    /**Returns float capped between minimum and maximum value
     * 
     * @param value as original value
     * @param min as minimum cap value
     * @param max as maximum cap value
     * @return float containing capped value
     */
    public static float capFloat(float value, float min, float max)
    {
        if(value < min) value = min;
            else if(value > max) value = max;

        return value;
    }

    /**Merges color and opacity to new color
     * 
     * @param bg as color for old color, only RGB will be used from that
     * @return color with RGB from bg and A from opacity of frame
     */
    Color getTransparencyColor(Color bg)
    {
        return new Color(getOpacityValue(bg.getRed()), getOpacityValue(bg.getGreen()), getOpacityValue(bg.getBlue()), opacity);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        //Draw transparent background before painting other Components
        g.setColor(getTransparencyColor(getBackground()));
        Rectangle r = g.getClipBounds();
        g.fillRect(r.x, r.y, r.width, r.height);

        //Paint other components
        super.paintComponent(g);
    }
}

最重要的部分基本上是在最后,我对paintComponent(Graphics g)方法进行了介绍

我只是取backgroundcolor,对它应用透明度并设置它

现在我想让这个面板的所有子组件也变得透明,我不太确定这样做最有效的方法是什么

你有什么建议


共 (1) 个答案

  1. # 1 楼答案

    我找到了一个解决方案——基本上就是我在评论中提到的:面板并没有真正画在屏幕上。取而代之的是,它被绘制成一个图像,并且这个图像被绘制成适当的AlphaComposite

    OpacityPanel

    (滑块可用于设置面板的不透明度)

    尽管这个解决方案简单、通用,并且基本上可以处理所有子组件,但有一点我不喜欢:需要调整RepaintManager。为了确保应用了面板的不透明度(并且子组件不是独立绘制的,并且是完全不透明度的),重绘管理器必须在重绘子组件时触发整个组件的重绘。我认为应该有没有这种解决方法的解决方案(例如,这可能是在面板上覆盖getGaphics可能是合适的罕见情况之一),但没有效果。也许通常的嫌疑犯(camickr、气垫船等)会找到更优雅、简洁的解决方案

    在此之前,以下是作为MCVE的代码:

    import java.awt.AlphaComposite;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    
    import javax.swing.JButton;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JSlider;
    import javax.swing.JTree;
    import javax.swing.RepaintManager;
    import javax.swing.SwingUtilities;
    
    public class TransparencyPanelTest
    {
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    
        private static void createAndShowGui()
        {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.getContentPane().setLayout(new BorderLayout());
    
            OpacityPanel opacityPanel = new OpacityPanel();
    
            opacityPanel.setLayout(new BorderLayout());
            opacityPanel.add(new JLabel("Label"), BorderLayout.NORTH);
            opacityPanel.add(new JTree(), BorderLayout.CENTER);
            opacityPanel.add(new JButton("Button"), BorderLayout.SOUTH);
    
            f.getContentPane().add(opacityPanel, BorderLayout.CENTER);
    
            JSlider slider = new JSlider(0, 100, 50);
            slider.addChangeListener(e -> 
                opacityPanel.setOpacity(slider.getValue() / 100.0f));
            f.getContentPane().add(slider, BorderLayout.SOUTH);
    
            f.setSize(500,500);
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
    }
    
    class OpacityPanel extends JPanel
    {
        static
        {
            RepaintManager.setCurrentManager(new RepaintManager()
            {
                @Override
                public void addDirtyRegion(
                    JComponent c, int x, int y, int w, int h)
                {
                    Component cc = c;
                    while (cc != null)
                    {
                        if (cc instanceof OpacityPanel)
                        {
                            OpacityPanel p = (OpacityPanel)cc;
                            super.addDirtyRegion(
                                p, 0, 0, p.getWidth(), p.getHeight());
                        }
                        cc = cc.getParent();
                    }
                    super.addDirtyRegion(c, x, y, w, h);
                }
            });
        }
        private float opacity = 0.5f;
        private BufferedImage image;
    
        public OpacityPanel()
        {
            setOpaque(false);
        }
    
        public void setOpacity(float opacity)
        {
            this.opacity = Math.max(0.0f, Math.min(1.0f, opacity));
            repaint();
        }
    
        private void updateImage()
        {
            int w = Math.min(1, getWidth());
            int h = Math.min(1, getHeight());
            if (image == null || image.getWidth() != w || image.getHeight() != h)
            {
                image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            }
            Graphics2D g = image.createGraphics();
            g.setColor(new Color(0,0,0,0));
            g.setComposite(AlphaComposite.SrcOver);
            g.fillRect(0, 0, w, h);
            g.dispose();
        }
    
        @Override
        protected void paintComponent(Graphics gr)
        {
            updateImage();
            Graphics2D imageGraphics = image.createGraphics();
            super.paintComponent(imageGraphics);
            imageGraphics.dispose();
    
            Graphics2D g = (Graphics2D) gr;
            g.setComposite(AlphaComposite.getInstance(
                AlphaComposite.SRC_OVER, opacity));
            g.drawImage(image, 0, 0, null);
        }
    
    }