java - 自定义形状的透明按钮

标签 java swing jbutton bufferedimage imageicon

我发现了两种不适合我的解决方案。第一个涉及透明度。我更喜欢第二个,因为它看起来更干净。目标是使用具有透明度的图像创建自定义形状的按钮。我想忽略透明部分,仅在单击图像的非透明部分时执行操作。

第一个代码来自这里 http://java.macteki.com/2012/07/custom-shape-buttons.html 。顺便问一下,下面代码中的 0x00ffffff 有何意义?

//********** BEGIN OF IMAGE BUTTON CODE ****************
      // The following is the actual code to create a image button
      // you may use any transparent image file, just change "a.png" below
      final BufferedImage image = ImageIO.read(new File("a.png"));
      ImageIcon icon = new ImageIcon(image);

      jLabel1 = new javax.swing.JLabel(icon);
      jLabel1.addMouseListener(new MouseAdapter()
      {
      public void mouseClicked(MouseEvent e)
      {
      boolean transparent = (image.getRGB(e.getX(),e.getY()) & 0x00ffffff)!=0;
     if (!transparent) {
      // write your button handler here
       System.out.println("button pressed");
      } else {
        System.out.println("else");
      }
      }
      }

      );
      //********** END OF IMAGE BUTTON CODE ****************
      // add the button to the panel so that it becomes visible

它适用于他的测试图像,但不适用于我的任何图像。我什至拿了他的,只是改变了gimp中A的颜色,导出到a2.png,但它不起作用。它将所有区域注册为 elseif (!transparent) 从不触发。

此图像有效: This image works 该图像不起作用: This image does not work

我更喜欢的第二个代码来自这里 Creating a custom button in Java with JButton 。该图像适用于按钮,但在框中的任何位置(包括透明区域)的单击都将记录为单击。我希望它仅在您单击非透明区域(或本例中的 A)时才起作用。

BufferedImage startButton = ImageIO.read(new File("a2.png"));       
        jButton1 = new javax.swing.JButton(new ImageIcon(startButton));  
        jButton1.setBorder(BorderFactory.createEmptyBorder());
        jButton1.setContentAreaFilled(false);
        jButton1.setFocusable(false);

这是我尝试根据 Guillame 的示例使用的代码

private void initComponents() throws IOException {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        final BufferedImage image = ImageIO.read(getClass().getResource("/images/a.png"));
        jButton1 = new JButton(new ImageIcon(image)) {
             @Override
             public boolean contains(int x, int y) {
                 Rectangle viewRect = getBounds();
                 Insets insets = getInsets();
                 viewRect.x += insets.left;
                 viewRect.y += insets.top;
                 viewRect.width -= insets.left + insets.right;
                 viewRect.height -= insets.top + insets.bottom;
                 Rectangle iconR = new Rectangle();
                 SwingUtilities.layoutCompoundLabel(this, this.getFontMetrics(this.getFont()), this.getText(), this.getIcon(),
                         this.getVerticalAlignment(), this.getHorizontalAlignment(), this.getVerticalTextPosition(),
                         this.getHorizontalTextPosition(), viewRect, iconR, new Rectangle(), this.getIconTextGap());
                 if (!iconR.contains(x, y)) {
                     return false;
                 }
                 x -= iconR.x;
                 y -= iconR.y;
                 Color c = new Color(image.getRGB(x, y), true);
                 return c.getAlpha() != 0 && (c.getRed() < 255 || c.getGreen() < 255 || c.getBlue() < 255);
             }
         };

        jButton1.setContentAreaFilled(false); 
        jButton1.setFocusPainted(false);            
        jButton1.setRolloverEnabled(false);       
        jButton1.setBorderPainted(false);

        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(72, 72, 72)
                .addComponent(jButton1)
                .addContainerGap(255, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(193, Short.MAX_VALUE)
                .addComponent(jButton1)
                .addGap(84, 84, 84))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

最佳答案

您需要重写JButtoncontains(int,int) 方法才能使第二个方法起作用。现在最困难的部分是确定您是否位于图像的相关部分。 在这种情况下,我假设完全透明的像素不相关,并且白色像素也不相关。由您选择不同的实现:

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

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

public class TestTransparentButton {

    protected void createAndShowGUI() throws MalformedURLException, IOException {
        JFrame frame = new JFrame("Test button");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final BufferedImage image = ImageIO.read(new URL("/image/7D547.png"));
        final JButton button = new JButton(new ImageIcon(image)) {
            @Override
            public boolean contains(int x, int y) {
                Rectangle viewRect = getBounds();
                Insets insets = getInsets();
                viewRect.x = insets.left;
                viewRect.y = insets.top;
                viewRect.width -= insets.left + insets.right;
                viewRect.height -= insets.top + insets.bottom;
                Rectangle iconR = new Rectangle();
                SwingUtilities.layoutCompoundLabel(this, this.getFontMetrics(this.getFont()), this.getText(), this.getIcon(),
                        this.getVerticalAlignment(), this.getHorizontalAlignment(), this.getVerticalTextPosition(),
                        this.getHorizontalTextPosition(), viewRect, iconR, new Rectangle(), this.getIconTextGap());
                if (!iconR.contains(x, y)) {
                    return false;
                }
                x -= iconR.x;
                y -= iconR.y;
                Color c = new Color(image.getRGB(x, y), true);
                return c.getAlpha() != 0 && (c.getRed() < 255 || c.getGreen() < 255 || c.getBlue() < 255);
            }
        };
        button.setContentAreaFilled(false);
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(button, "You clicked on the button");
            }
        });
        frame.add(button);
        frame.setSize(200, 200);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new TestTransparentButton().createAndShowGUI();
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

    }

}

关于java - 自定义形状的透明按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14362885/

相关文章:

java - IntelliJ IDEA 中的 Eclipse 运行应用程序配置

java - 使用triangle_strip模式处理形状的纹理

java - 将字体应用于 JTextArea 会导致 gui 崩溃吗?

java - 如何在 keyTyped 事件发生时更改 JButton 颜色?

Java Swing 保留按钮的外观和感觉,但保留背景颜色

java - 获取示例程序或教程以备份 android 中的所有内容?

java - 如果在字符串中找不到特定字符,如何减去 -1

java - 如何在 JTextPane 上添加不同颜色的文本

java - 在 java netbeans 中构建后,构造函数中调用的方法不起作用

java - JButton 子类不改变透明度