java 单击绘制的对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12933592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:50:14  来源:igfitidea点击:

Clicking on a drawn object

javaswingeventsjakarta-eegraphics

提问by Dot NET

I've got a class called Shapewhich inherits from JPanel.

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

A number of sub-classes in turn extend the Shapeclasses, one for each type of shape.

许多子类依次扩展了这些Shape类,每种形状都有一个。

Each shape has its own overriden paint()method, which draws the respective shape.

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

I would like to be able to click on any shape, and am trying to implement this logic for now. Please note that each shape has been added to an arrayList.

我希望能够点击任何形状,现在我正在尝试实现这个逻辑。请注意,每个形状都已添加到一个数组列表中。

However, the contains statement always returns false, even when I have clearly clicked inside the shape.

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

Any ideas?

有任何想法吗?

回答by David Kroukamp

Never override paint()in JPanelrather paintComponent(..)

永不覆盖paint()JPanel相当paintComponent(..)

Im not quite sure I understand however I made a short example which I hope will help. Basically it is a simple JFramewith a DrawingPanel(my own class which extends JPaneland the shapes are drawn on). This panel will create shapes (only 2 for testing) add them to an ArrayListand draw them to the JPanelvia paintComponent(..)and a forloop, it also has a MouseAdapterto check for user mouseClicked(..)evnets on the JPanel. When a click is made we iterate through each Shapein the ArrayListand check whether the Shapecontains the point or not, and if so prints its class name and uses instance ofto check what type of Shapeis clicked and prints appropriate message:

我不太确定我理解但我做了一个简短的例子,我希望会有所帮助。基本上它是一个简单JFrameDrawingPanel(我自己的类,它扩展JPanel并绘制了形状)。本专题将创建形状(只有2个用于测试)将它们添加到一个ArrayList和借鉴他们的JPanel通过paintComponent(..)和一个for循环,它也有一个MouseAdapter检查用户mouseClicked(..)的evnets JPanel。当点击由我们迭代通过每个ShapeArrayList和检查是否Shape包含点或不是,如果是打印它的类名和用途instance of检查什么类型的Shape被点击并打印相应的消息:

enter image description here

enter image description here

Output(after clicking both shapes):

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

Clicked a java.awt.geom.Rectangle2D$Double

Clicked a rectangle

Clicked a java.awt.geom.Ellipse2D$Double

Clicked a circle

单击一个 java.awt.geom.Rectangle2D$Double

单击一个矩形

单击一个 java.awt.geom.Ellipse2D$Double

点击了一个圆圈

ShapeClicker.java:

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

回答by John Dvorak

If you are implementing Shapeyou have to implement the containsmethod yourself. The default implementation for Shapealways returns false.

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

If your Shapeis bounded by curves that you know how to intersect (or determine if a point is on one or the other side), you can use the even-odd rule. Cast a ray from the point tested in any direction not parallel to a straight line. If the number of intersections is odd, the point is inside. If the number of intersections is even, the point is outside.

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

The built-in classes implement this method, so you can use/extend the Polygon, Ellipse2D.Doubleor RoundRectangle2D.Doubleclass and have a filled polygon / ellipse / round rectangle that knows its inside.

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