6

我有一个Shape继承自 JPanel 的类。

许多子类依次扩展了这些Shape类,一种用于每种形状。

每个形状都有自己的覆盖paint()方法,用于绘制相应的形状。

我希望能够单击任何形状,并且现在正在尝试实现此逻辑。请注意,每个形状都已添加到 arrayList。

但是,包含语句总是返回 false,即使我已经清楚地单击了形状内部。

有任何想法吗?

4

2 回答 2

13

永远不要覆盖paint()JPanel不是paintComponent(..)

我不太确定我是否理解,但是我做了一个简短的示例,希望对您有所帮助。基本上它是一个简单JFrameDrawingPanel(我自己的类扩展JPanel并绘制形状)。此面板将创建形状(仅 2 个用于测试)将它们添加到一个ArrayList并将它们绘制到JPanel通孔paintComponent(..)和一个for循环,它还有一个MouseAdapter用于mouseClicked(..)检查JPanel. 当单击时,我们遍历每个Shape中的ArrayList并检查是否Shape包含该点,如果是,则打印其类名并用于instance of检查Shape单击的类型并打印适当的消息:

在此处输入图像描述

输出(单击两个形状后):

单击了 java.awt.geom.Rectangle2D$Double

单击了一个矩形

单击了 java.awt.geom.Ellipse2D$Double

点击了一个圈子

ShapeClicker.java:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ShapeClicker {

    public ShapeClicker() {
        JFrame frame = new JFrame();
        frame.setTitle("Shape Clicker");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        initComponents(frame);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        //create frame and components on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ShapeClicker();
            }
        });
    }

    private void initComponents(JFrame frame) {
        frame.add(new ShapePanel());
    }
}

//custom panel
class ShapePanel extends JPanel {

    private Shape rect = new Rectangle2D.Double(50, 100, 200, 100);
    private Shape cirlce = new Ellipse2D.Double(260, 100, 100, 100);
    private Dimension dim = new Dimension(450, 300);
    private final ArrayList<Shape> shapes;

    public ShapePanel() {
        shapes = new ArrayList<>();
        shapes.add(rect);
        shapes.add(cirlce);
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent me) {
                super.mouseClicked(me);
                for (Shape s : shapes) {
                    
                    if (s.contains(me.getPoint())) {//check if mouse is clicked within shape
                        
                        //we can either just print out the object class name
                        System.out.println("Clicked a "+s.getClass().getName());
                        
                        //or check the shape class we are dealing with using instance of with nested if
                        if (s instanceof Rectangle2D) {
                            System.out.println("Clicked a rectangle");
                        } else if (s instanceof Ellipse2D) {
                            System.out.println("Clicked a circle");
                        }
                        
                    }
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        Graphics2D g2d = (Graphics2D) grphcs;
        for (Shape s : shapes) {
            g2d.draw(s);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return dim;
    }
}
于 2012-10-17T12:52:54.080 回答
3

如果您正在实施Shape,则必须自己实施该contains方法。Shape总是返回的默认实现false

如果您Shape的边界是您知道如何相交的曲线(或确定一个点是否在一侧或另一侧),您可以使用奇偶规则。从测试点向任何不平行于直线的方向投射光线。如果交叉点的数量是奇数,则该点在内部。如果交叉点的数量是偶数,则该点在外部。

内置类实现了此方法,因此您可以使用/扩展Polygon,Ellipse2D.DoubleRoundRectangle2D.Double类,并拥有一个知道其内部的填充多边形/椭圆/圆形矩形。

于 2012-10-17T12:11:04.783 回答