Java MouseEvent位置不准确 [英] Java MouseEvent position is inaccurate

查看:229
本文介绍了Java MouseEvent位置不准确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用我创建的画布类中遇到了一个问题,这是一个扩展的 JPanel ,用于绘制动画环形图。此图表使用 MouseListener 来获取点击事件。

I've got a problem in Java using a "canvas" class I created, which is an extended JPanel, to draw an animated ring chart. This chart is using a MouseListener to fetch click events.

问题是鼠标位置似乎没有是准确的,这意味着它似乎不是相对于画布而是相对于窗口(在左上角,我得到约30px的y coord)。

The problem is that the mouse position does not seem to be accurate, meaning it does not seem to be relative to the "canvas" but instead relative to the window (in the left, upper corner I got about 30px for y coord).

这是我的代码:

我创建了一个类,它扩展了JPanel并且有一个BufferedImage作为成员。

I created a class, that extends JPanel and does have a BufferedImage as member.

public class Canvas extends JPanel {

    public BufferedImage buf;
    private RingChart _parent;

    public Canvas(int width, int height, RingChart parent){
        buf = new BufferedImage(width, height, 1);
    ...

在绘图组件方法中我只绘制缓冲图像,所以我我可以通过在缓冲图像上绘制来从外部在画布上绘画,这是公共的。

In the paint component method I just draw the buffered image, so I am able to paint on the canvas from 'outside' by painting on the buffered image, which is public.

public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g; 
        g2.drawImage(buf, null, 0, 0); 

    }

现在有一个包含画布的RingChart类:

Now there's a class RingChart which contains a "canvas":

public class RingChart extends JFrame{

    public Canvas c;
    ...

我在canvas类的bufferedImage中创建了一个Graphics2D。这个g2d用于绘画:

And I create a Graphics2D from the bufferedImage in the canvas class. This g2d is used for painting:

public RingChart(){
    c = new Canvas(1500,980,this);
    add(c);
    setSize(1500, 1000);
    setTitle("Hans");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    g2d = (Graphics2D)c.buf.createGraphics();
    ...

我现在想要实现的是一个听过的老鼠听众在画布上发生鼠标事件。因此,当用户点击画布时,我可以在画布上通过事件变量检索他点击的位置。

What I now was trying to achieve, was a mouse listener that listened to mouse events happening on the canvas. So when the user clicks on the canvas I could retrieve the position he clicked on, upon the canvas, through the event variable.

所以我创建了一个鼠标监听器:

So I created a mouse listener:

class MouseHandler implements MouseListener {

    @Override
    public void mouseClicked(MouseEvent e){
        RingChart r = ((Canvas)e.getSource()).getParent();
        r.mouseClick(e);
    }
    ...

...并添加此鼠标监听器RingChart类的画布(myChart是RingChart的一个实例,c是它包含的画布):

...and added this mouse listener to the canvas of the RingChart class (myChart is an instance of RingChart and c is the canvas it contains):

        ...
        MouseHandler mouse = new MouseHandler();
        myChart.c.addMouseListener(mouse);
        ...

但正如我上面提到的,鼠标位置,即当点击事件被调用,似乎不准确。我认为错误必须以某种方式创建mouseListener,或者将其分配给错误的元素或类似的东西。但是我已经尝试了很多东西而且没有改变。也许有人能告诉我,我做错了什么?

But as I mentioned above, the mouse position, that's returned when the click event is called, does not seem to be accurate. I think the mistake must be somehow in the way I created that mouseListener or maybe assigned it to the wrong element or something like that. But I've tried quite a couple of things and it didn't change. Can maybe someone tell me, what I've done wrong?

更新:

函数的代码mouseClick是RingChart的成员,在鼠标侦听器中调用:

The code of the function "mouseClick" that is a member of RingChart and is called in the mouse listener:

public void mouseClick(MouseEvent evt){
    //evt = SwingUtilities.convertMouseEvent(this, evt, c);
    if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
        for(Element e : elements){
            if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
                //do some stuff
            }
        }
    }
}

再次,我的类的层次结构:
RingChart - 包含 - > Canvas --got a - > MouseListener。
此函数中的形状是在画布上绘制的形状c。现在我想检查,如果用户点击了其中一个。因此,我认为,形状应该在画布坐标中,事件位置应该在画布坐标中,并且所有内容都应该放在一起。但事实并非如此。
现在用户MadProgrammer告诉我,要使用ConvertMouseEvent函数。但我目前还没有看到我应该明智地使用哪种方式。

Again, the hierarchy of my classes: RingChart --contains a--> Canvas --got a--> MouseListener. The shapes in this function are shapes that have been painted on the canvas c. Now I want to check, if the user has clicked on one of them. So as I thought, the shapes should be in canvas-coordinates and the event position should be in canvas-coordinates and everything should fit together. But it doesn't. Now user MadProgrammer told me, to use the ConvertMouseEvent function. But I currently don't see which exact way I should use this sensibly.

更新:

我找到了一个解决方案:我所要做的就是不将画布直接添加到 JFrame ,而是添加到 ContentPane JFrame 而是:

I found a solution: All I had to do is adding the canvas not directly to the JFrame but to the ContentPane of the JFrame instead:

相反:

public RingChart(){
    c = new Canvas(1500,980,this);
    add(c);
    ...

我这样做:

public RingChart(){
    c = new Canvas(1500,980,this);
    getContentPane().add(c);
    ...

然后我给 MouseListener ContentPane

getContentPane().addMouseListener(new MouseHandler());
getContentPane().addMouseMotionListener(new MouseMoveHandler());

我不知道,如果这是一个优雅的解决方案,但它有效。

I don't know, if this is an elegant solution, but it works.

推荐答案

鼠标事件自动转换为相对于它发生的组件,即点0x0始终是左上角的组件。

The mouse event is automatically converted to be relative to the component that it occurred in that is, point 0x0 is always the top left corner of the component.

使用 RingChart r =((Canvas)e.getSource())。getParent(),您已经有效地更改了引用,现在意味着该位置不再有效。

By using RingChart r = ((Canvas)e.getSource()).getParent(), you've effectively changed the reference, which now means the location is no longer valid.

您需要转换位置,使其坐标位于父级的上下文中零件。看看 SwingUtilities.convertMouseEvent(Component,MouseEvent,Component)

You need to convert the location so that its coordinates are in the context of the parent component. Take a look at SwingUtilities.convertMouseEvent(Component, MouseEvent, Component)

UPDATE使用图片

让我们举个例子......

Lets take this example...

蓝框与红框的相对位置为50px x 50px 。如果你点击蓝色框,让我们说25x25,鼠标坐标将相对于蓝色框(0x0将是蓝色框的左上角)。

The blue box has a relative position of 50px x 50px to the red box. If you click in the blue box, lets say at 25x25, the mouse coordinates will be relative to the blue box (0x0 will be the top left of the blue box).

如果然后将此事件传递给红色框并尝试使用其中的坐标,您会发现坐标现在位于红色框的左上角和蓝色框之间,因为坐标是上下文敏感的。

If you then pass this event to the red box and try and use the coordinates from it, you will find that the coordinates will now be half way between the top left of the red box and the blue box, because the coordinates are context sensitive.

为了让它工作,您需要将鼠标事件位置从蓝色框转换为红色框,这将使其成为75x75

In order to get it to work, you need to translate the mouse events location from the blue box to the red box, which would make it 75x75

现在,当你将鼠标事件传递给 RingChart 时,我不知道你在做什么,所以我只是猜测这是你面临的问题。

Now, I don't know what you're doing when you pass the mouse event to the RingChart so I'm only guessing that this is the issue you're facing.

点击代码更新

好吧,比方说,你有100美元100的 Canvas 。您以50x50点击 Canvas 。然后将该值传递回链。

Okay, lets say, you have a Canvas at 100x100. You click on that Canvas at 50x50. You then pass that value back up the chain.

public void mouseClick(MouseEvent evt){
    //evt = SwingUtilities.convertMouseEvent(this, evt, c);
    if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
        for(Element e : elements){
            // Here, we are asking the shape if it contains the point 50x50...
            // Not 150x150 which would be the relative position of the click
            // in the context to the RingChart, which is where all your objects
            // are laid out.
            // So even the original Canvas you clicked on will return 
            // false because it's position + size (100x100x width x height) 
            // does not contain the specified point of 50x50...
            if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
                //do some stuff
            }
        }
    }
}

更新

我认为你的参考方式错误...

I think you have your references around the wrong way...

public static MouseEvent convertMouseEvent(Component source,
                       MouseEvent sourceEvent,
                       Component destination)

我认为应该读取类似

evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);

代码示例更新

好的,所以,我把这个小例子放在一起......

Okay, so, I put this little example together...

public class TestMouseClickPoint extends JFrame {

    private ContentPane content;

    public TestMouseClickPoint() throws HeadlessException {

        setSize(600, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        setLayout(new BorderLayout());

        content = new ContentPane();
        add(content);

    }

    protected void updateClickPoint(MouseEvent evt) {
        content.updateClickPoint(evt);
    }

    protected class ContentPane extends JPanel {

        private Point relativePoint;
        private Point absolutePoint;

        public ContentPane() {
            setPreferredSize(new Dimension(600, 600));
            setLayout(null); // For testing purpose only...

            MousePane mousePane = new MousePane();
            mousePane.setBounds(100, 100, 400, 400);

            add(mousePane);
        }

        protected void updateClickPoint(MouseEvent evt) {
            absolutePoint = new Point(evt.getPoint());
            evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);
            relativePoint = new Point(evt.getPoint());

            System.out.println(absolutePoint);
            System.out.println(relativePoint);

            repaint();
        }

        protected void paintCross(Graphics2D g2d, Point p) {
            g2d.drawLine(p.x - 5, p.y - 5, p.x + 5, p.y + 5);
            g2d.drawLine(p.x - 5, p.y + 5, p.x + 5, p.y - 5);
        }

        /*
         * This is not recommended, but I want to paint ontop of everything...
         */
        @Override
        public void paint(Graphics g) {
            super.paint(g);

            Graphics2D g2d = (Graphics2D) g;

            if (relativePoint != null) {
                g2d.setColor(Color.BLACK);
                paintCross(g2d, relativePoint);
            }

            if (absolutePoint != null) {
                g2d.setColor(Color.RED);
                paintCross(g2d, absolutePoint);
            }

        }
    }

    protected class MousePane extends JPanel {

        private Point clickPoint;

        public MousePane() {

            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    clickPoint = e.getPoint();
                    TestMouseClickPoint.this.updateClickPoint(e);
                    repaint();
                }
            });

            setBorder(new LineBorder(Color.RED));

        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.BLUE);

            if (clickPoint != null) {
                g2d.drawLine(clickPoint.x, clickPoint.y - 5, clickPoint.x, clickPoint.y + 5);
                g2d.drawLine(clickPoint.x - 5, clickPoint.y, clickPoint.x + 5, clickPoint.y);
            }

        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
        } catch (InstantiationException ex) {
        } catch (IllegalAccessException ex) {
        } catch (UnsupportedLookAndFeelException ex) {
        }

        new TestMouseClickPoint().setVisible(true);
    }
}

基本上,它会画三点。点击鼠标的点(相对于事件的来源),父容器中的未转换点以及父容器的转换点。

Basically, it will paint three points. The point that the mouse was clicked (relative to the source of the event), the unconverted point in the parent container and the converted point with the parent container.

接下来你需要做的事情确定鼠标位置实际上已被转换,失败了。我可能需要查看代码的工作示例,以确定它实际上是在做什么。

The next thing you need to do is determine the mouse location is actually been converted, failing that. I'd probably need to see a working example of your code to determine what it is you're actually doing.

这篇关于Java MouseEvent位置不准确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆