如何创建复杂形状的按钮?

6

我有一个带有图片覆盖的框架,当某人点击图像中的不同对象时,我希望它会像按钮一样执行某些操作。
问题是,这些对象不是简单的形状,所以我考虑在这些对象的形状上绘制自己的不可见按钮。

这是否可能?还是有更好的方法来完成这件事?

-谢谢


1
我会关注这个的。我之前在安卓上尝试过类似的东西,最终只能用透明按钮覆盖在奇怪的形状上来实现。 - sealz
它将充当一个按钮并执行某些操作。例如,就像电视的虚拟遥控器一样。 - mKorbel
1
请参考此处展示的方法(https://dev59.com/Tmgv5IYBdhLWcg3wFs2l)。 - trashgod
4个回答

3

概念:具有圆形和多边形分派区域的不可见按钮

首先,您需要定义一个类来定义不可见按钮,该类扩展了javax.swing.AbstractButton,以便它仍然是一个完全功能的按钮,您可以添加监听器。

public abstract class InvisibleButton extends AbstractButton {

    public abstract boolean contains(Point point);

    @Override
    public boolean isVisible() {
        return false;
    }
}

当然,你会想要实现该类。这里有两个示例:一个使用多边形表示复杂形状,另一个使用圆形。

public class PolygonalButton extends InvisibleButton {

    private Polygon area = null;

    public PolygonalButton(Polygon area) {
        this.area = area;
    }

    @Override
    public boolean contains(Point point) {
        return area.contains(point);
    }
}

public class CircularButton extends InvisibleButton {

    private int x;
    private int y;
    private double radius;

    public CircularButton(int x, int y, double radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public boolean contains(Point point) {
        double dx = x - point.x;
        double dy = y - point.y;
        return Math.sqrt(dx * dx + dy * dy) <= radius;
    }
}

最后,您需要实现一个容器来处理所有这些按钮,但是您应该使用面板而不是框架。您不必钩取每个单独的监听器,只需覆盖框架的事件处理程序并将其传递到必要的按钮即可。

public class InvisibleButtonImagePanel extends JPanel {

    private BufferedImage image = null;
    private List<InvisibleButton> buttons = new ArrayList<>();

    public InvisibleButtonImagePanel(BufferedImage image) {
        this.image = image;
    }

    public void add(InvisibleButton button) {
        buttons.add(button);
    }

    public void remove(InvisibleButton button) {
        buttons.remove(button);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(image.getWidth(), image.getHeight());
    }

    @Override
    public void processKeyEvent(KeyEvent event) {
        for (InvisibleButton button : buttons) {
            if (button.isFocusOwner()) {
                button.dispatchEvent(event);
            }
        }
        super.processKeyEvent(event);
    }

    @Override
    public void processMouseEvent(MouseEvent event) {
        for (InvisibleButton button : buttons) {
            if (button.contains(event.getPoint())) {
                button.dispatchEvent(event);
            }
        }
        super.processMouseEvent(event);
    }

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

您可能希望将面板重命名为更简洁的名称,并且可能需要实现自己的高级图像代码,但这就是它背后的基本思想。


不错的回答,但我要提醒OP避免使用java.awt组件,推荐使用Swing。 - William Morrison
哦哇,我完全没有注意到这个问题被标记为“swing”。我会重新写这个答案。 - FThompson

2

你能通过坐标跟踪用户的鼠标位置吗?

 PointerInfo a = MouseInfo.getPointerInfo();
        Point b  = a.getLocation();
        int x = (int)b.getX();
        int y = (int)b.getY();

现在编写一个 ActionPerformed 方法并测试 x 和 y 是否等于例如 200、300 时执行此操作。这样,当用户单击某个位置(您瞄准的区域)时,它将重定向到该方法。


2

定义一个区域的接口,例如:

//represents any clickable area.
public interface IButton{
    boolean contains(int x, int y);
}

如果您想要一个圆形区域可点击,请定义一个类,检查x、y坐标是否在某个位置的一定距离内。

public class CircleButton implements IButton{
    Point center;
    double radius;   
    public CircleButton(int x, int y, double radius){
        this.center = new Point(x,y);
        this.radius = radius;
    }
    //check if x,y coords are within a radius 
    //from the center of this circle button
    public boolean contains(int x, int y){
        double dx = x-center.x;
        double dy = y-center.y;
        return (Math.sqrt(dx*dx+dy*dy) <= radius);
    }
}

创建一个IButtons列表。您将对其进行迭代,以查看用户是否单击了其中一个不可见按钮。
List<IButton> buttons = new List<IButton>();
buttons.add(new CircleButton(100,100,200);

每次有人点击你的框架时,使用鼠标点击的位置来迭代隐藏按钮。
public void mouseReleased(MouseEvent e){
    for(IButton b : buttons){
       if(b.contains(evt.getX(),e.getY()){
           //do something depending on what button was clicked.
       }
    }
} 

你可以轻松地看到如何定义不可见的矩形按钮,甚至是不规则多边形。你只需要正确实现contains方法即可。

2
我希望每次有人点击图像中的不同对象时,它都会充当按钮并执行某些操作。
您可以创建一个Shape对象的ArrayList。然后将MouseListener添加到包含图像的组件中。每当生成mousePressed事件时,您就循环遍历ArrayList,并使用组件的containts(...)方法来确定用户是否单击了形状坐标。
请查看Playing With Shapes。该代码对您的直接问题没有帮助,但它会给您一些可以定义的Shapes类型的想法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接