0
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. If the mouse button is released, I would set isDown to false in order to terminate the while loop.

What I am messing up here? Is it not possible for two MouseEvent methods to be running at the same time? The change in the isDown boolean variable is not being registered and I have an infinite while loop on my hands.

shdw
  • 87
  • 1
  • 11
  • @CyrilleKarmann If the event is begin triggered via the `MouseListener` interface, it will be in the EDT – MadProgrammer Feb 08 '13 at 01:23
  • 2
    It looks to me like you want a MouseMotionListener and then you would handle the mouseDragged() event. Then you don't need to worry about looping and block the EDT. – camickr Feb 08 '13 at 01:29
  • @MadProgrammer yeah I didn't see right away the while loop in the mousePressed listener. After seeing that, the problem was obvious. – Cyrille Ka Feb 08 '13 at 01:37
  • @CyrilleKarmann I just "while loop" and freaked :P – MadProgrammer Feb 08 '13 at 01:49

2 Answers2

7

This is a classic violation of the Event Dispatching Thread.

All UI code is run from within a single thread. 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. This will make your program look like it's hung.

Take a look at Concurrency in Swing for more details.

What you really should be doing is using a MouseMoitionListener to track drag events instead. 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); also worries me to no end.

You should never be using getGraphics to perform custom painting. getGraphics can return null and is only a snap shot of the last paint cycle. 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. Check out Performing Custom Painting for more details

Example

enter image description here

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;
                }
            }
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • How do I use the `mouseDragged()` method? The API is not very clear. Supposedly I have to use the `.getModifiersEx()` method? – shdw Feb 08 '13 at 01:31
  • Would this work? public void mouseDragged(MouseEvent e) { if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == MouseEvent.BUTTON1_DOWN_MASK) System.out.println("Button 1 is down"); } – shdw Feb 08 '13 at 01:33
  • Check out the *How to use Mouse Listeners* tutorial linked on the answer. Attach a `MouseMoitionListener` via the [`Component#addMouseMoitionListener`](http://docs.oracle.com/javase/6/docs/api/java/awt/Component.html#addMouseMotionListener%28java.awt.event.MouseMotionListener%29) method – MadProgrammer Feb 08 '13 at 01:34
  • So I overrided the `mouseDragged()` method and I removed my problematic code above. I added a `println()` method to print a short message when the `mouseDragged()` method is called. I run the code and drag my mouse around on the Component that I added the `MouseMotionListener` to, but no message is displayed to the console? – shdw Feb 08 '13 at 01:38
  • 1
    +1 for the MouseMotionListener (I must have missed you posting while I was adding my comment). Also, use the SwingUtilities.isLeftMouseButton(...) if you want to know which button is being pressed. – camickr Feb 08 '13 at 01:40
  • Did you run the code from the tutorial? Start with working code and then make changes. We can't guess what you might be doing wrong. – camickr Feb 08 '13 at 01:41
  • @user1744094 Check the example – MadProgrammer Feb 08 '13 at 01:46
  • @camickr +1 for mentioning `SwingUtilities`! – MadProgrammer Feb 08 '13 at 01:48
  • +1 classic example as usual... But I must ask What the heck is that extra *button* on the `JFrame`s border for?? :) – David Kroukamp Feb 08 '13 at 08:56
  • 1
    @DavidKroukamp FusionDesktop, some extra this and that – MadProgrammer Feb 08 '13 at 09:09
2

Your are doing the while loop inside your mousePressed() method. It means you are blocking the Swing Event Dispatch Thread! 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.

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. 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.

The problem with this solution is that your work is painting on a Swing component. All graphics should be done in an overriden paintComponent method. As @MadProgrammer is already explaining you that, I won't go into details about it.

Cyrille Ka
  • 15,328
  • 5
  • 38
  • 58