1

假设我有一个 JPanel,上面通过 绘制了一个图像作为背景paintComponent(),这个面板包含一些带有图标的按钮。这些按钮没有自己的背景,并且“继承”了面板的背景。我知道如何使用 使按钮的图标半透明AlphaComposite,但我怎样才能获得按钮的背景图像(这是JPanel 背景图像的一部分,因为按钮是不透明的并且被绘制在面板的背景上)并使其透明,而不是图标?我什至不知道这是否可能......

以下代码只是使按钮的图标透明。

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.image.BufferedImage;

import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestPanel extends JPanel {

    private final ImageIcon icon = new ImageIcon(getClass().getResource("path\\to\\image\\file"));
    private BufferedImage img;

    public TestPanel() {

        try {
            img = ImageIO.read(new File("path\\to\\background\\image"));
        } catch (IOException ex) {}

        ImageIcon fadedIcon = getTranslucentImageIcon(icon, 0.5f);
        JButton button = new JButton(fadedIcon);
        button.setRolloverIcon(icon);
        button.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        button.setOpaque(false);
        button.setContentAreaFilled(false);
        button.setFocusPainted(false);
        this.add(button);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, null);
    }

    @Override
    public Dimension getPreferredSize() {
        if (img != null) {
          return new Dimension(img.getWidth(), img.getHeight());
        }
        return super.getPreferredSize();
    }

    private BufferedImage getTranslucentImage(BufferedImage oldImg, float alpha) {
        int w = oldImg.getWidth();
        int h = oldImg.getHeight();
        BufferedImage newImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
        Graphics2D g2d = newImg.createGraphics();
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
        g2d.drawImage(oldImg, null, 0, 0);
        g2d.dispose();
        return newImg;
    }

    private ImageIcon getTranslucentImageIcon(Icon oldIcon, float alpha) {
        int w = oldIcon.getIconWidth();
        int h = oldIcon.getIconHeight();
        BufferedImage oldImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) oldImg.getGraphics();
        oldIcon.paintIcon(null, g2d, 0, 0);
        BufferedImage newImg = getTranslucentImage(oldImg, alpha);
        g2d.dispose();
        return new ImageIcon(newImg);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPanel());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }

}

您只需要 2 张图像来重现它(背景图像应该更大以使我的观点更清楚)。

PS我还想知道我是否正确地做整个事情(更具体的方法getTranslucentImagegetTranslucentImageIcon),或者是否有更好的方法来做到这一点。

4

1 回答 1

3

我会把它放在这里,因为注释不适合格式化。

至于你的“半透明”方法,它们对我来说似乎很好。我可能做的唯一改变是创建一个兼容的缓冲图像。这将(除其他外)确保颜色模型相同并使其渲染速度更快......

protected BufferedImage createCompatibleImage(int width, int height, int transparency) {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gs = ge.getDefaultScreenDevice();
    GraphicsConfiguration gc = gs.getDefaultConfiguration();
    return gc.createCompatibleImage(width, height, transparency);
}

private BufferedImage getTranslucentImage(BufferedImage oldImg, float alpha) {
    int w = oldImg.getWidth();
    int h = oldImg.getHeight();
    BufferedImage newImg = createCompatibleImage(w, h, Transparency.TRANSLUCENT);
    Graphics2D g2d = newImg.createGraphics();
    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
    g2d.drawImage(oldImg, null, 0, 0);
    g2d.dispose();
    return newImg;
}

更新了扩展答案

我为了实现你想要的,你需要一个干净的父组件版本。那是没有任何孩子的副本。然后,您需要调整大小并将此副本绘制到屏幕外缓冲区(如缓冲图像),然后提取您想要的图像部分(或根据您的要求绘制子图像)。

坦率地说。你正在做的只是更容易......

于 2012-09-25T22:56:23.100 回答