【问题标题】:Applying colour to the transparent area of a JButton image - but not that of its container将颜色应用于 JButton 图像的透明区域 - 但不是其容器的透明区域
【发布时间】:2016-03-29 03:34:58
【问题描述】:

我有一个使用带有透明区域的圆形 PNG 图像构建的圆形 JButton。

我想用给定的颜色填充 JButton 图像的透明区域 - 但不是包含 JButton 的 JPanel 的不透明背景颜色。我想在 Java 中以编程方式执行此操作,而不是从图形包中提供预先着色的图像。

我已经了解了下面的代码,它只是允许不透明面板的橙色背景为透明区域着色。不过,我不知道如何将面板背景保持为橙色,但用蓝色(或用于翻转和按下效果的其他颜色)填充图像透明度。

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.DefaultButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class App extends JFrame implements ActionListener
{
    public App()
    {
       super();
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       setContentPane(makeContentPane());
    }

    private final JPanel makeContentPane()
    {
        JPanel contentPane = new JPanel();
        BufferedImage bi = null;
        try
        {
            bi = ImageIO.read(new URL("http://features.advisorwebsites.com/sites/default/files/users/AdvisorWebsitesFeatures/icones/1384148625_twitter_circle_gray.png"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        ImageIcon icon = new ImageIcon(bi);
        MyButton myButton = new MyButton(icon);
        myButton.addActionListener(this);
        contentPane.add(myButton);
        contentPane.setBackground(Color.ORANGE);
        contentPane.setOpaque(true);
        return contentPane;
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                App app = new App();
                app.pack();
                app.setVisible(true);
            }
        });
    }

    class MyButton extends JButton
    {
        public MyButton(ImageIcon icon)
        {
            super(icon);
            setMargin(new Insets(0, 0, 0, 0));
            setFocusable(false);
            setContentAreaFilled(false);
            setBorderPainted(false);
            setModel(new DefaultButtonModel());
            setCursor(new Cursor(Cursor.HAND_CURSOR));
        }
    }

    @Override
    public void actionPerformed(ActionEvent arg0)
    {
        System.out.println("You clicked me");
    }
}

我猜我可能需要对我的透明图像应用 Graphics2D 转换来创建一组三个新图像(用于我的 JButton 的正常、翻转和按下状态)。这是正确的前进方式吗?如果是,您能否为我提供一个代码示例来说明我所缺少的部分?

谢谢

【问题讨论】:

  • 你也可以发布你的图片吗?
  • 尝试覆盖 paintComponent() 并绘制一个绿色椭圆,可能会成功

标签: java swing


【解决方案1】:

尝试在您的自定义JButton 中覆盖paintComponent()

这是我尝试过的

class MyButton extends JButton {

        public MyButton(ImageIcon icon) {
            super(icon);
            setMargin(new Insets(0, 0, 0, 0));
            setFocusable(false);
            setContentAreaFilled(false);
            setBorderPainted(false);
            setModel(new DefaultButtonModel());
            setCursor(new Cursor(Cursor.HAND_CURSOR));

        }

        public void paintComponent(Graphics g) {
            g.setColor(Color.green);
            g.fillOval(0, 0, this.getWidth(), this.getHeight());
            super.paintComponent(g);

        }

    }

结果如下:

编辑:

要让它根据鼠标移动来改变颜色,你需要向 JButton 添加一个 MouseListener 并在类中添加一个 Color 属性,当触​​发 MouseEvent 时你会改变颜色。另外不要忘记在paintComponent()中将图形设置为该颜色

class MyButton extends JButton {

        Color color = Color.GREEN;

        public MyButton(ImageIcon icon) {
            super(icon);
            setMargin(new Insets(0, 0, 0, 0));
            setFocusable(false);
            setContentAreaFilled(false);
            setBorderPainted(false);
            setModel(new DefaultButtonModel());
            setCursor(new Cursor(Cursor.HAND_CURSOR));
            this.addMouseListener(new MouseListener() {

                @Override
                public void mouseClicked(MouseEvent e) {

                }

                @Override
                public void mousePressed(MouseEvent e) {
                    color=Color.RED;
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    color=Color.BLUE;
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    color=Color.BLUE;
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    color=Color.GREEN;
                }
            });

        }

        @Override
        public void paintComponent(Graphics g) {
            g.setColor(color);
            g.fillOval(0, 0, this.getWidth(), this.getHeight());
            super.paintComponent(g);

        }

    }

【讨论】:

  • 这当然是我想要的“正常”状态的效果。只是为了一个完整的答案,有什么方法可以应用您的解决方案,以便我可以为 JButton 的“翻转”和“按下”状态获得不同的颜色?
【解决方案2】:

好的,这比您所要求的要多一点,但它演示了一种方法,您可以通过AlphaComposite 的魔力根据图像的 alpha 生成与图像形状相匹配的形状。 ..

所以,基本上,我们将把左边的原始图像变成右边的图像......

  • 首先,我们加载原始图像
  • 接下来,我们创建一个我们想要实现的形状的蒙版(在本例中为圆形)
  • 接下来,我们将两张图片一起蒙版,这样原始图片就被裁剪到蒙版中(第二张)
  • 然后我们创建一个新蒙版,用我们想要用作轮廓的颜色填充它
  • 然后我们用“轮廓”图像对第一个蒙版图像进行蒙版,这基本上就像一个千篇一律的工具,用“块”图像切割第一个蒙版图像的形状。
  • 我们采用这种“轮廓”形状,然后稍微放大
  • 最后,我们将它们结合起来。

此示例生成两个图像,一个“正常”和一个“翻转”,可以轻松应用于 JButton,例如...

正常...

翻滚……

现在,如果出于某种原因,您想知道按钮何时“滚动”,您可以简单地将ChangeListener 添加到ButtonModel,例如...

JButton btn = new JButton(new ImageIcon(normal));
btn.setRolloverIcon(new ImageIcon(rollOver));
btn.setRolloverEnabled(true);
btn.getModel().addChangeListener(new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
        ButtonModel model = (ButtonModel) e.getSource();
        System.out.println("Change: " + model.isRollover());
    }
});

还有可运行的例子……

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class JavaApplication24 {

    public static void main(String[] args) {
        new JavaApplication24();
    }

    public JavaApplication24() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(JavaApplication24.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() throws IOException {
            setLayout(new GridBagLayout());
            BufferedImage source = ImageIO.read(...));

            // This the shape we want the source to be clipped to
            int size = Math.min(source.getWidth(), source.getHeight());
            BufferedImage mask = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
            Graphics2D maskg = mask.createGraphics();
            applyQualityRenderingHints(maskg);
            maskg.setColor(Color.WHITE);
            maskg.fillOval((source.getWidth() - size) / 2, (source.getHeight() - size) / 2, size, size);
            maskg.dispose();

            // This will mask the source to the shape we've defined
            BufferedImage masked = applyMask(source, mask, AlphaComposite.DST_ATOP);

            BufferedImage normal = makeOutline(masked, Color.BLACK);
            BufferedImage rollOver = makeOutline(masked, Color.RED);

            JButton btn = new JButton(new ImageIcon(normal));
            btn.setRolloverIcon(new ImageIcon(rollOver));
            btn.setRolloverEnabled(true);
            btn.getModel().addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    ButtonModel model = (ButtonModel) e.getSource();
                    System.out.println("Change: " + model.isRollover());
                }
            });
            add(btn);
        }

        protected BufferedImage makeOutline(BufferedImage original, Color color) {

            // This generates a image which is completely filled with the provided color
            BufferedImage outline = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D outlineg = outline.createGraphics();
            applyQualityRenderingHints(outlineg);
            outlineg.setColor(color);
            outlineg.fillRect(0, 0, outline.getWidth(), outline.getHeight());
            outlineg.dispose();

            // This applies a AlphaComposite to mask the outline with the shape
            // of the original image
            outline = applyMask(original, outline, AlphaComposite.SRC_ATOP);

            // Now we make it slightly larger...
            double scale = 1.05;
            outline = getScaledInstanceToFit(outline, scale);

            // And we combine the images
            outlineg = outline.createGraphics();
            int x = (outline.getWidth() - original.getWidth()) / 2;
            int y = (outline.getHeight() - original.getHeight()) / 2;
            outlineg.drawImage(original, x, y, this);
            outlineg.dispose();

            return outline;

        }

        public BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage) {

            return applyMask(sourceImage, maskImage, AlphaComposite.DST_IN);

        }

        public 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();
                applyQualityRenderingHints(mg);

                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 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);
//      g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        }

        public BufferedImage getScaledInstanceToFit(BufferedImage img, double scale) {
            int width = (int)(img.getWidth() * scale);
            int height = (int)(img.getHeight()* scale);
            return getScaledInstanceToFit(img, new Dimension(width, height));
        }

        public BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {

            double scaleFactor = getScaleFactorToFit(new Dimension(img.getWidth(), img.getHeight()), size);

            return getScaledInstance(img, scaleFactor);

        }

        public double getScaleFactorToFit(Dimension original, Dimension toFit) {

            double dScale = 1d;

            if (original != null && toFit != null) {

                double dScaleWidth = getScaleFactor(original.width, toFit.width);
                double dScaleHeight = getScaleFactor(original.height, toFit.height);

                dScale = Math.min(dScaleHeight, dScaleWidth);

            }

            return dScale;

        }

        public double getScaleFactor(int iMasterSize, int iTargetSize) {
            return (double) iTargetSize / (double) iMasterSize;
        }

        public BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
            return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
        }

        protected BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {

            BufferedImage imgScale = img;

            int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
            int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);

            if (dScaleFactor <= 1.0d) {
                imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
            } else {
                imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
            }

            return imgScale;

        }

        protected BufferedImage getScaledDownInstance(BufferedImage img,
                        int targetWidth,
                        int targetHeight,
                        Object hint,
                        boolean higherQuality) {

            int type = (img.getTransparency() == Transparency.OPAQUE)
                            ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;

            BufferedImage ret = (BufferedImage) img;

            if (targetHeight > 0 || targetWidth > 0) {

                int w, h;
                if (higherQuality) {
                    w = img.getWidth();
                    h = img.getHeight();
                } else {
                    w = targetWidth;
                    h = targetHeight;
                }

                do {
                    if (higherQuality && w > targetWidth) {
                        w /= 2;
                        if (w < targetWidth) {
                            w = targetWidth;
                        }
                    }

                    if (higherQuality && h > targetHeight) {
                        h /= 2;
                        if (h < targetHeight) {
                            h = targetHeight;
                        }
                    }

                    BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                    Graphics2D g2 = tmp.createGraphics();
                    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                    g2.drawImage(ret, 0, 0, w, h, null);
                    g2.dispose();

                    ret = tmp;

                } while (w != targetWidth || h != targetHeight);
            } else {
                ret = new BufferedImage(1, 1, type);
            }

            return ret;
        }

        protected BufferedImage getScaledUpInstance(BufferedImage img,
                        int targetWidth,
                        int targetHeight,
                        Object hint,
                        boolean higherQuality) {

            int type = BufferedImage.TYPE_INT_ARGB;

            BufferedImage ret = (BufferedImage) img;
            int w, h;
            if (higherQuality) {
                w = img.getWidth();
                h = img.getHeight();
            } else {
                w = targetWidth;
                h = targetHeight;
            }

            do {
                if (higherQuality && w < targetWidth) {
                    w *= 2;
                    if (w > targetWidth) {
                        w = targetWidth;
                    }
                }

                if (higherQuality && h < targetHeight) {
                    h *= 2;
                    if (h > targetHeight) {
                        h = targetHeight;
                    }
                }

                BufferedImage tmp = new BufferedImage(w, h, type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();

                ret = tmp;
                tmp = null;

            } while (w != targetWidth || h != targetHeight);
            return ret;
        }
    }

}

这段代码大量借鉴了我的个人图书馆代码,所以可能有点复杂;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    • 2013-01-02
    • 2011-03-22
    相关资源
    最近更新 更多