简体   繁体   English

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

[英]Java Swing - Applying transparancy to Components on transparent JPanel

I am working on creating a JPanel which supports transparency, and have come to the problem that I am not sure on how to apply the same level of transparency to all Component s added to this panel. 我正在创建一个支持透明性的JPanel ,但遇到的问题是我不确定如何对添加到此面板的所有Component应用相同级别的透明性。 My code so far: 到目前为止,我的代码:

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);
    }
}

The important part is basically at the end where I overwride the paintComponent(Graphics g) method. 重要的部分基本上是在最后我覆盖了paintComponent(Graphics g)方法的地方。

I just take the backgroundcolor , apply the transparency to it and set it. 我只是采用backgroundcolor ,对其应用透明度并进行设置。

Now I want to make all Component children of this panel become drawn transparent as well, and I'm not quite sure what would be the most effective way of doing this. 现在,我想使该面板的所有Component子项也都变得透明,并且我不确定这样做的最有效方法是什么。

What would you suggest? 你有什么建议?

I found a solution - basically what I already mentioned in the comments: The panel is not really painted on the screen. 我找到了一个解决方案-基本上就是我在评论中已经提到的解决方案:面板并未真正绘制在屏幕上。 Instead, it is painted into an image, and this image is painted with the appropriate AlphaComposite . 而是将其绘制为图像,并使用适当的AlphaComposite绘制该图像。

不透明度面板

(The slider may be used to set the opacity of the panel) (滑块可用于设置面板的不透明度)

Although this solution is simple, generic and should basically work with all child components, there's one thing that I don't like about it: The necessity to tweak the RepaintManager . 尽管此解决方案简单,通用,并且基本上可以与所有子组件一起使用,但是我不喜欢它一件事:调整RepaintManager的必要性。 In order to make sure that the opacity of the panel is applied (and the child components are not painted independently, and with their full opacity), the repaint manager has to trigger a repaint of the whole component whenever a child component was repainted. 为了确保应用面板的不透明度(子组件不会独立绘制,并且不具有完全的不透明度),每当重新绘制子组件时,重新绘制管理器都必须触发整个组件的重新绘制。 I thought that there should be solution without this workaround (eg that this might be one of the rare cases where overriding getGaphics on the panel might be appropriate), but no avail. 认为应该有没有此解决方法的解决方案(例如,这可能是在面板上重写getGaphics的少数情况之一),但无济于事。 Maybe the usual suspects (camickr, Hovercraft etc.) find a more elegant and concise solution. 也许通常的嫌疑人(camickr,气垫船等)找到了一个更简洁明了的解决方案。

Until then, here is the code as a MCVE: 在此之前,这里是作为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);
    }

}

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

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