简体   繁体   English

Java GUI构建器-如何制作不规则形状的按钮

[英]Java GUI builder - How to make an irregular shaped button

I have been working the the NetBeans GUI builder and all I want to do is have a picture (say a stick figure) and an action to only happen when i click the stick figure itself, not just its entire rectangle. 我一直在使用NetBeans GUI构建器,而我要做的就是拥有一张图片(比如一个简笔画),以及仅当我单击简笔画本身而不是整个矩形时才发生的动作。 I've googled for hours and I can't find anything, please help! 我已经搜索了几个小时,但找不到任何东西,请帮忙!

Edit: Mainly the question is how do I get it to ignore transparent pixels on the button? 编辑:主要的问题是如何使它忽略按钮上的透明像素?

package my.usefulness;

public class usefulness extends javax.swing.JFrame
{
    public usefulness()
    {
        initComponents();
    }
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jButton1 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setIcon(new javax.swing.ImageIcon("C:\\Users\\rando_000\\Desktop\\buttonImage.png")); // NOI18N
        jButton1.setBorderPainted(false);
        jButton1.setContentAreaFilled(false);
        jButton1.setFocusPainted(false);

        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(149, 149, 149)
                .addComponent(jButton1)
                .addContainerGap(200, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jButton1)
                .addGap(0, 237, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                
}

I was a bit curious about this myself so I tested out creating a new component type. 我自己对此有点好奇,所以我测试了创建新的组件类型。 I took the approach then when you click on this component it should check the mouse event location with the image pixel data, if the pixel is transparent then the mouse event should not be registered. 我采用的方法是,当您单击该组件时,它应该使用图像像素数据检查鼠标事件的位置,如果像素是透明的,则不应注册鼠标事件。 This implementation only processes mouse down events and class is far from complete but it should give you a good start! 此实现仅处理鼠标按下事件,并且类还远远没有完成,但是应该为您提供一个良好的开始! Checkout the TODO tags I put in there 检出我放入的TODO标签

public class TransparentImageButton extends JComponent implements MouseListener {

    private BufferedImage image = null;
    private File imageFile;
    private List<ActionListener> listeners;

    public TransparentImageButton(File imageFile) throws IOException {
        this.imageFile = imageFile;
        this.image = ImageIO.read(imageFile);
        this.addMouseListener(this);
        this.listeners = new ArrayList<ActionListener>();
    }

    public void addActionListener(ActionListener listener) {
        listeners.add(listener);
    }

    @Override
    protected void paintComponent(Graphics g) { 
        super.paintComponent(g);
        Rectangle r = getImageBounds();
        g.drawImage(image, r.x, r.y, r.width, r.height, this);
    }


    private Rectangle getImageBounds() {
        // TODO Add in proper handling if component size < image size.
        return new Rectangle((int)((getBounds().width-image.getWidth())/2), (int)((getBounds().height-image.getHeight())/2), image.getWidth(), image.getHeight());
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Add more action events?
    }

    @Override
    public void mousePressed(MouseEvent e) {
        Rectangle bounds = getImageBounds();
        if(bounds.contains(e.getPoint())) {
            int ix = e.getX()-bounds.x;
            int iy = e.getY()-bounds.y;
            int [] arr = image.getData().getPixel(ix, iy, new int[4]);
            // get the alpha for the current pixel
            if(arr[3] != 0) {
                // not transparent
                ActionEvent newActionEvent = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, imageFile.getName(), e.getWhen(), e.getModifiers());
                for(ActionListener listener : listeners) {
                    listener.actionPerformed(newActionEvent);
                }
            }
        } else {
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Add more action events?
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Add more action events?
    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Add more action events?
    }
} 

I tested it using this code: 我使用以下代码对其进行了测试:

public static void main(String[] args) throws FileNotFoundException, IOException {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(500, 400);
    frame.setLocationByPlatform(true);

    TransparentImageButton btn = new TransparentImageButton(new File("c:\\icon.png"));
    btn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Clicky!!");
        }
    });
    frame.getContentPane().add(btn);
    frame.setVisible(true);
}

And used this image: 并使用此图像:

样本按钮图片

There is no such thing as "irregular shaped button " , not that i know of anyways... you would have to make that yourself . 没有“不规则形状的按钮”之类的东西,反正我也不知道……您必须自己动手做。

The thing here is you may be confusing between an image and a java component. 这里的问题是您可能在图像和Java组件之间感到困惑。 What i mean is there is no way for java to determine what is the point of interest in your image , thats why the image is considered a rectangle .If you worked with flash , photoshop or any advanced drawing tool : then its kinda like the difference between a vector and an image . 我的意思是,java无法确定图像中的关注点,这就是为什么将图像视为矩形的原因。如果您使用Flash,Photoshop或任何高级绘图工具,那么它有点像区别在矢量和图像之间。

Anyways , to solve your problem , you can define a Poligon that has the same shape as your stick figure . 无论如何,要解决您的问题,您可以定义一个形状与棒状图形相同的Poligon。 To do that you define the Point s that make the Polygon , like so : 为此,您定义构成Polygon的Point,如下所示:

//a triangle for example 
int[] x = {100,50,150}; // the X postion of the points that form the polygon
int[] y = {100,200,200};// the y pos
Polygon pol = new Polygon(x,y,3) // 3 is number of points .

now inside the mouse event listener : 现在位于鼠标事件侦听器中:

 public void mouseClicked(MouseEvent evt){
{
  if(pol.contains(evt.getPoint()){
    // do w.e your button should do 
   }
}

now this way , if the mouse click event is inside the Polygon pol (which should be your stick figure ) , you then do what your button is intended to do 现在,如果鼠标单击事件在Polygon pol(应该是简笔画)内,则可以执行按钮打算执行的操作

Swing per se isn't capable of handling click events for non-rectangular shapes (as far as I know). 就我所知,Swing 本身无法处理非矩形形状的点击事件。 You could try to catch the mouse position on the click event and calculate if this xy-coordinate is inside you shape or not. 您可以尝试在click事件上捕获鼠标位置,并计算此xy坐标是否在您的形状内。

I don't know what your image looks like, but it guess it is some sort of figure on a transparent or at least uniform background. 我不知道您的图像是什么样子,但是它猜测它是透明或至少均匀背景上的某种图形。 If so, you could simply check if the pixel-color at that xy-coordinate is that specific background color or not. 如果是这样,您可以简单地检查xy坐标处的像素颜色是否为特定的背景颜色。

That way you have a simple and fast algorithm... I wouldn't say it's the best, but maybe good enough :) 这样,您就拥有了一个简单而快速的算法...我不会说这是最好的,但也许足够好:)

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

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