简体   繁体   English

当我释放鼠标按钮时,MouseEvent未注册发布

[英]MouseEvent is not registering a release when I release the mouse button

public void mousePressed(MouseEvent e) {
    //Invoked when a mouse button has been pressed on a component.
    if (e.getButton() == MouseEvent.BUTTON1) {
        isDown = true;
        System.out.println("isDown is now true");
    }
    if (e.getButton() == MouseEvent.BUTTON3) {
        isDown2 = true;
        System.out.println("isDown2 is now true");
    }
    do {
        Point location = MouseInfo.getPointerInfo().getLocation(); 
        int x = location.x - (drawingPanel.getLocationOnScreen()).x;
        int y = location.y - (drawingPanel.getLocationOnScreen()).y;
        drawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19);
    } while (isDown);
    System.out.println("Mouse has been pressed down.");
}

public void mouseReleased(MouseEvent e) {
    //Invoked when a mouse button has been released on a component.
    if (e.getButton() == MouseEvent.BUTTON1) {
        isDown = false;
        System.out.println("isDown is now false");
    }
    if (e.getButton() == MouseEvent.BUTTON3) {
        isDown2 = false;
        System.out.println("isDown2 is now false");
    }
    System.out.println("Mouse has been released.");
}

This is what I have so far. 到目前为止,这就是我所拥有的。 My original intentions were to design the code so that the boolean isDown would be set to true when the mouse was pressed down and then I would have the while loop run while isDown is true. 我的初衷是设计代码,以便在按下鼠标时将布尔值isDown设置为true,然后在isDown为true while运行while循环。 If the mouse button is released, I would set isDown to false in order to terminate the while loop. 如果释放鼠标按钮,我将isDown设置为false,以终止while循环。

What I am messing up here? 我在这里搞砸了吗? Is it not possible for two MouseEvent methods to be running at the same time? 两个MouseEvent方法不能同时运行吗? The change in the isDown boolean variable is not being registered and I have an infinite while loop on my hands. isDown布尔变量中的更改未注册,并且手上有一个无限的while循环。

This is a classic violation of the Event Dispatching Thread. 这是对事件调度线程的经典违反。

All UI code is run from within a single thread. 所有UI代码都在单个线程中运行。 All events are dispatched the UI from this same thread, meaning that should you block this thread (using a loop or other blocking operation), no events will be dispatched. 所有事件都是从同一线程分派UI的,这意味着如果您阻塞该线程(使用循环或其他阻塞操作),则不会分派任何事件。 This will make your program look like it's hung. 这将使您的程序看起来已挂起。

Take a look at Concurrency in Swing for more details. 有关更多详细信息,请参阅Swing中的并发

What you really should be doing is using a MouseMoitionListener to track drag events instead. 您真正应该做的是改用MouseMoitionListener来跟踪拖动事件。 Check out How to use Mouse Listeners for more details. 请查看如何使用鼠标侦听器以获取更多详细信息。

This drawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19); drawingPanel.paint(drawingPanel.getGraphics(), (x - (x % 20) - 1), (y - (y % 20) - 1), 19, 19); also worries me to no end. 也让我无休止

You should never be using getGraphics to perform custom painting. 您永远不应使用getGraphics执行自定义绘制。 getGraphics can return null and is only a snap shot of the last paint cycle. getGraphics可以返回null,它只是最后一个绘制周期的快照。 Any painting done using this method will be removed/cleaned when another repaint occurs. 当再次进行重画时,使用此方法完成的任何画都将被删除/清理。

You should be creating a custom component (such as a JPanel ) and overriding it's paintComponent method and performing any painting you need in it. 您应该创建一个自定义组件(例如JPanel ),并覆盖它的paintComponent方法,并在其中执行所需的绘画。 Check out Performing Custom Painting for more details 请查看表演自定义绘画以获取更多详细信息

Example

在此处输入图片说明

public class MouseDraggedTest {

    public static void main(String[] args) {
        new MouseDraggedTest();
    }

    public MouseDraggedTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Map<Point, List<Point>> mapPoints;
        private Point currentPoint;

        public TestPane() {
            mapPoints = new HashMap<>(25);
            MouseAdapter mouseListener = new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    currentPoint = e.getPoint();
                    mapPoints.put(currentPoint, new ArrayList<Point>(25));
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    List<Point> points = mapPoints.get(currentPoint);
                    if (points.isEmpty()) {
                        mapPoints.remove(currentPoint);
                    }
                    currentPoint = null;
                }

                @Override
                public void mouseDragged(MouseEvent me) {
                    List<Point> points = mapPoints.get(currentPoint);
                    points.add(me.getPoint());
                    repaint();
                }
            };
            addMouseListener(mouseListener);
            addMouseMotionListener(mouseListener);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            for (Point startPoint : mapPoints.keySet()) {
                List<Point> points = mapPoints.get(startPoint);
                for (Point p : points) {
                    if (startPoint != null) {
                        g.drawLine(startPoint.x, startPoint.y, p.x, p.y);
                    }
                    startPoint = p;
                }
            }
        }
    }
}

Your are doing the while loop inside your mousePressed() method. 您正在在mousePressed()方法内部进行while循环。 It means you are blocking the Swing Event Dispatch Thread! 这意味着您正在阻止Swing事件调度线程! As this method will not return as long as isDown is true, then the execution will not come back to the listener handler, which will never call your mouseReleased() listener. 由于只要isDown为true,此方法就不会返回,因此执行将不会返回到侦听器处理程序,该处理程序永远不会调用mouseReleased()侦听器。

As a general rule, you should never launch a long running operation in a listener, because it makes your GUI not respond to any event as long as it runs. 通常,永远不要在侦听器中启动长时间运行的操作,因为只要它运行,GUI便不会响应任何事件。 Which in this case means forever! 在这种情况下,这意味着永远! Any listener should not do more than set a few flags, and then return. 任何侦听器都只能设置几个标志,然后返回。 It is necessary for your application to stay responsive. 您的应用程序必须保持响应状态。

One typical solution is to launch a new thread to do the long running work. 一种典型的解决方案是启动一个新线程来执行长期运行的工作。 It would free the Event Dispatching Thread and your mouseReleased() listener will be called. 它将释放事件调度线程,并且将调用mouseReleased()侦听器。

The problem with this solution is that your work is painting on a Swing component. 该解决方案的问题在于您的工作是在Swing组件上进行的。 All graphics should be done in an overriden paintComponent method. 所有图形都应在重写的paintComponent方法中完成。 As @MadProgrammer is already explaining you that, I won't go into details about it. 正如@MadProgrammer已经向您解释的那样,我将不对其进行详细介绍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM