从包含透明像素的图像创建自定义JButton

Ada*_*ith 7 java icons swing jbutton imageicon

阅读编辑2,了解我实际上缺少的内容

我目前正在尝试使用在photoshop中创建的具有alpha参数的图像创建一些自定义JButton.

到目前为止,覆盖paint()方法来绘制图像已经起到了绘制按钮以显示正确图像的意义.不过,我想通过使其形状(可点击区域)与图像上的可见像素相同来改进它(现在,如果我绘制按钮的边框,它就是一个正方形).

有没有一种简单的方法可以做到这一点,还是我必须解析图像并找到alpha像素来制作自定义边框?

我必须覆盖哪些方法才能使其按照我想要的方式工作?

另外,我将在稍后提出的另一个问题是:使用某种算法来更改图像的颜色会更好,这样看起来当人们点击它时它被点击或者我最好创建第二个按钮处于活动状态时图像和绘图?

编辑:我刚刚读到一些其他问题,我应该重新定义paintComponent()而不是paint(),我想知道为什么重新定义paint()工作正常?

编辑2:我改变了一切,以确保我的JButton是使用带图标的默认构造函数创建的.我要做的是获取点击注册位置的X和Y位置并抓住该位置的图标像素并检查其alpha通道以查看它是否为0(如果是,则不执行任何操作,否则执行此操作应该采取的行动).

问题是,alpha通道始终返回255(蓝色,红色和绿色在透明像素上为238).在其他像素上,一切都返回它应该返回的值.

这是一个示例(如果需要,可以使用另一个图像尝试)重新创建我的问题:

public class TestAlphaPixels extends JFrame
{
  private final File FILECLOSEBUTTON = new File("img\\boutonrondX.png");  //My round button with transparent corners
  private JButton closeButton = new JButton(); //Creating it empty to be able to place it and resize the image after the button size is known


  public TestAlphaPixels() throws IOException
  {
    setLayout(null);
    setSize(150, 150);

    closeButton.setSize(100, 100);
    closeButton.setContentAreaFilled(false);
    closeButton.setBorderPainted(false);

    add(closeButton);

    closeButton.addMouseListener(new MouseListener()
      {

        public void mouseClicked(MouseEvent e)
        {
        }

        public void mousePressed(MouseEvent e)
        {
        }

        public void mouseReleased(MouseEvent e)
        {
          System.out.println("Alpha value of pixel (" + e.getX() + ", " + e.getY() + ") is: " + clickAlphaValue(closeButton.getIcon(), e.getX(), e.getY()));
        }

        public void mouseEntered(MouseEvent e)
        {
        }

        public void mouseExited(MouseEvent e)
        {
        }
      });
    Image imgCloseButton = ImageIO.read(FILECLOSEBUTTON);

    //Resize the image to fit the button
    Image newImg = imgCloseButton.getScaledInstance((int)closeButton.getSize().getWidth(), (int)closeButton.getSize().getHeight(), java.awt.Image.SCALE_SMOOTH);
    closeButton.setIcon(new ImageIcon(newImg));


  }

  private int clickAlphaValue(Icon icon, int posX, int posY) 
  {
    int width = icon.getIconWidth();
    int height = icon.getIconHeight();

    BufferedImage tempImage = (BufferedImage)createImage(width, height);
    Graphics2D g = tempImage.createGraphics();

    icon.paintIcon(null, g, 0, 0);

    g.dispose();

    int alpha = (tempImage.getRGB(posX, posY) >> 24) & 0x000000FF;

    return alpha;
  } 
  public static void main(String[] args)
  {
    try
    {
      TestAlphaPixels testAlphaPixels = new TestAlphaPixels();
      testAlphaPixels.setVisible(true);
      testAlphaPixels.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    catch(IOException ioe)
    {
      ioe.printStackTrace();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

此示例实际显示的内容

这只是一个疯狂的猜测,但有可能当我的图像被转换为​​Icon时,它会丢失其Alpha属性,因此不会返回正确的值吗?无论如何,如果有人能真正帮助我并告诉我应该改变什么以获得正确的价值,我真的很感激.

我猜这是因为当我用原始图像尝试它时,alpha通道的值很好,但我实际上不能使用那个BufferedImage,因为我调整了它的大小,所以我实际上得到了原始大小的图像的通道值...

Ale*_*exR 6

我认为你走错了路.您不必覆盖paint()和paintComponent()方法.JButton已经"知道"仅显示图像:

ImageIcon cup = new ImageIcon("images/cup.gif");
JButton button2 = new JButton(cup);
Run Code Online (Sandbox Code Playgroud)

请参阅以下教程,例如:http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JButton.html

此外,秋千是完全定制的.您可以控制不透明度,边框,颜色等.您可能应该覆盖一些提到的方法来更改功能.但在大多数情况下,有更好,更简单的解决方案.


Ada*_*ith 5

由于多个答案中都有好的要素,但是没有一个答案是一个完整的问题,因此我将回答自己的问题,以便其他遇到相同问题的人也可以尝试类似的方法。

我使用扩展JButton的新类创建了按钮,该类具有使用BufferedImage作为参数而不是图标的新构造函数。这样做的原因是,当我执行诸如myButton.getIcon()之类的操作时,它将返回一个Icon,然后我必须对其进行各种操作才能使它成为正确大小的BufferedImage,并且最终不起作用无论如何,因为似乎对Icon的第一次转换使它丢失了像素中的alpha数据,所以我无法检查用户是否单击了透明像素。

所以我为构造函数做了这样的事情:

public class MyButton extends JButton
{
   private BufferedImage bufImg;

   public MyButton(BufferedImage bufImg)
   {
      super(new ImageIcon(bufImg));
      this.bufImg = bufImg;
   }
 }
Run Code Online (Sandbox Code Playgroud)

然后,我为我的bufImg创建了一个访问器,该访问器使用getSize()方法将图像调整为适合JButton的大小,然后返回调整为正确大小的图像。我在getBufImg()访问器中进行了转换,因为在调整窗口大小时图像大小可能会改变。调用getBufImg()时,通常是因为您单击了按钮,因此当前未调整窗口大小。

像这样的东西会以正确的尺寸返回图像:

 public BufferedImage getBufImg()
    {
      BufferedImage newImg = new BufferedImage(getSize().getWidth(), getSize().getHeight(), BufferedImage.TYPE_INT_ARGB); //Create a new buffered image the right size
      Graphics2D g2d = newImg.createGraphics();
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

      g2d.drawImage(bufImg, 0, 0, getSize().getWidth(), getSize().getHeight(), null);
      g2d.dispose();

      return newImg;
    }
Run Code Online (Sandbox Code Playgroud)

使用该缓冲图像,然后可以编写如下方法:

  private int clickAlphaValue(BufferedImage bufImg, int posX, int posY) 
  {
    int alpha;

    alpha = (bufImg.getRGB(posX, posY) >>24) & 0x000000FF; //Gets the bit that contains alpha information

    return alpha;
  }
Run Code Online (Sandbox Code Playgroud)

调用实现MouseListener的按钮,如下所示:

myButton.addMouseListener(new MouseListener()
    {

    public void mouseClicked(MouseEvent e)
    {
    }

    public void mousePressed(MouseEvent e)
    {
    }

    public void mouseReleased(MouseEvent e)
    {
      if(clickAlphaValue(((myButton)e.getSource()).getBufImg(), e.getX(), e.getY()) != 0) //If alpha is not set to 0
        System.exit(0); //Or other things you want your button to do
    }

    public void mouseEntered(MouseEvent e)
    {
    }

    public void mouseExited(MouseEvent e)
    {
    }
  });
Run Code Online (Sandbox Code Playgroud)

瞧!仅当您单击非透明像素时,该按钮才会执行操作。

感谢大家的帮助,我无法独自提出这个解决方案。