【问题标题】:How can i create a complex Button shape?如何创建复杂的按钮形状?
【发布时间】:2013-08-10 12:09:22
【问题描述】:

我有一个带有图像的框架,我希望每次有人单击图像中的不同对象时,它都会充当按钮并执行某些操作。
问题是,那些对象不是简单的形状,所以我在考虑以这些对象的形状绘制我自己的隐形按钮。

这可能吗?或者有什么更好的方法来完成这样的事情?

-谢谢

【问题讨论】:

  • 会关注这个。不久前,我在 android 上尝试了一些非常相似的东西,最终只在奇怪的形状上找到了隐形按钮:)
  • 它将充当按钮并执行某些操作。例如,类似于电视的虚拟遥控器
  • 另见here所示的方法。

标签: java image swing button paintcomponent


【解决方案1】:

概念:带有圆形和多边形调度区域的隐形按钮

首先,您需要一个定义不可见按钮的类,扩展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。
  • 哦,哇,我完全错过了用swing 标记的问题。我会重写这个答案。
【解决方案2】:

您可以通过坐标跟踪用户的鼠标位置吗?

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

现在放置一个 ActionPerformed 方法并测试 x 和 y = 例如200, 300 这样做。这样当用户点击一个点(你的目标区域)时,它会将他重定向到一个方法。

【讨论】:

    【解决方案3】:

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

    //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);
        }
    }
    

    创建一个 IButton 列表。您将遍历这些以查看用户是否单击了您的某个不可见按钮。

    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 方法即可。

    【讨论】:

      【解决方案4】:

      而且我希望每次有人单击图像中的不同对象时,它都会充当按钮并执行某些操作。

      您可以创建 Shape 对象的 ArrayList。然后将 MouseListener 添加到包含图像的组件中。每当生成 mousePressed 事件时,您循环遍历 ArrayList 并使用组件的 containsts(...) 方法来确定用户是否单击了 Shapes 坐标。

      查看Playing With Shapes。该代码不会帮助您解决眼前的问题,但它会让您了解您可以定义的Shapes 的类型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多