1

I've got a JFrame with no decoration (no title bar, close button, etc) that I can drag around the screen using setLocation() and mouse position.

Unfortunately, the mouseExited event is called upon first move of the window...

  1. Move mouse into window and mouseEntered event is fired
  2. Click mouse and mousePressed event is fired.
  3. Drag mouse and mouseDragged event is fired, and setLocation is called.
  4. mouseExited event is fired, even though the mouse is still in the window!
  5. Moving mouse out of the window at this point will not fire mouseExited.
  6. Moving mouse out and back in will reset back to step 1.

How do I fix this problem, other than just manually testing mouse position on screen?

Edit: Here's a distilled version of the code

import java.awt.*;
import javax.swing.*;
import java.awt.Event;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;
import javax.swing.JFrame;

class DragNDropper implements MouseMotionListener, MouseListener
{
    private int x, y;
    private int dx, dy;

    private boolean clicked;

    private JFrame frame;

    public DragNDropper(JFrame frame)
    {
    dx = dy = 0;
    this.frame = frame;
    }

    public void mouseDragged(MouseEvent e)
    {
    x = e.getXOnScreen();
    y = e.getYOnScreen();

    frame.setLocation(x-dx, y-dy);
    }

    public void mouseMoved(MouseEvent e)
    {
    x = e.getXOnScreen();
    y = e.getYOnScreen();
    }

    public void mouseClicked(MouseEvent e)
    {

    }

    public void mousePressed(MouseEvent e)
    {
    clicked = true;
    dx = e.getX();
    dy = e.getY();
    }

    public void mouseReleased(MouseEvent e)
    {
    clicked = false;
    }

    public void mouseEntered(MouseEvent e)
    {
    System.out.println("Mouse entered");
    }


    public void mouseExited(MouseEvent e)
    {
    System.out.println("Mouse exited");
    }
}


public class Program
{
public static void main(String[] argv)
{
JFrame jf = new JFrame();
DragNDropper dnd = new DragNDropper(jf);

jf.setSize(new Dimension(512, 512));
jf.addMouseListener(dnd);
jf.addMouseMotionListener(dnd);

jf.show();
}
}
Name McChange
  • 2,750
  • 5
  • 27
  • 46
  • 1
    For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) showing the problem. – Andrew Thompson Jan 12 '14 at 04:50
  • `Error: Main method not found in class DragNDropper, please define the main method as: public static void main(String[] args)`.. An MCVE includes a main. – Andrew Thompson Jan 12 '14 at 04:57
  • @SuperDisk : This does not complies to MCVE document. Where is the `JFrame` in the class provided? How to run it as is ? Again this new edit does not conforms to MCVE document. In simple terms one should be able to simply copy and paste and run the code. In this case one has to first delete `public` from one class and redundant `import` statements to make it run. – nIcE cOw Jan 12 '14 at 04:58
  • @AndrewThompson Okay, I enclosed it in a main function. – Name McChange Jan 12 '14 at 05:00
  • The `main` should ideally be part of the (single MCVE) class. Make it as easy as possible for others to see the problem. Also start the GUI on the EDT. – Andrew Thompson Jan 12 '14 at 05:04
  • @AndrewThompson How about now? – Name McChange Jan 12 '14 at 05:08
  • __"I've got a JFrame with no decoration (no title bar, close button, etc)"__. The `JFrame` is a normal windows, with everything on it, in the code provided, as far as I can see!!! – nIcE cOw Jan 12 '14 at 05:13
  • How about you ask me about anything you do not understand. For instance. *"start the GUI on the EDT."* See [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) for more details. But for a 'quick tip: the code on [this question](http://stackoverflow.com/a/7143398/418556) achieves it by wrapping the code in `main` in a `Runnable`, and calling it using `SwingUtilities.invokeLater`.. – Andrew Thompson Jan 12 '14 at 05:14
  • @nicecow I'm really just scraping together a quick runnable thing. The "no decoration" part just makes the example code bigger and is irrelevant. – Name McChange Jan 12 '14 at 05:17

1 Answers1

2

Everything is working fine, with this code. Please stop using frame.show(), from where you come to know of this being used to show the JFrame, use frame.setVisible(true) instead. Please explain a bit more about the problem. Please have a look at this modification of the code :

import java.awt.*;
import java.awt.Event;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.*;

public class DragNDropper implements MouseMotionListener, MouseListener {

    private int x, y;
    private int dx, dy; 
    private boolean clicked;    
    private JFrame jf;

    public static void main(String[] argv) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DragNDropper().displayGUI();
            }
        });
    }

    private void displayGUI() {
        dx = dy = 0;
        jf = new JFrame();
        jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        jf.setUndecorated(true);

        jf.setSize(new Dimension(512, 512));
        jf.addMouseListener(this);
        jf.addMouseMotionListener(this);

        jf.setVisible(true);
    }

    public void mouseDragged(MouseEvent e) {
        x = e.getXOnScreen();
        y = e.getYOnScreen();
        jf.setLocation(x-dx, y-dy);
    }

    public void mouseMoved(MouseEvent e) {
        x = e.getXOnScreen();
        y = e.getYOnScreen();
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        clicked = true;
        dx = e.getX();
        dy = e.getY();
    }

    public void mouseReleased(MouseEvent e) {
        clicked = false;
    }

    public void mouseEntered(MouseEvent e) {
        System.out.println("Mouse entered");
    }

    public void mouseExited(MouseEvent e) {
        System.out.println("Mouse exited");
    }
}
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • Intriguing; There doesn't seem like much of a difference save for the merging of the classes and the use of EventQueue.invokeLater. Thanks anyhow! – Name McChange Jan 12 '14 at 06:41