0

I want to get the mouse position of my JFrame. But when mouse is on its child component (such as a table, button that is added to the JFrame) MouseMotion event is no more listening. How can I get the mouse position?

Peter1
  • 157
  • 1
  • 2
  • 13
  • I assume you've attached a `MouseListener` to the frame then added components on top of it? Why do you want the mouse position, what is it you are trying to achieve...? – MadProgrammer Aug 22 '13 at 06:43
  • I was trying to make a Sidebar on my Swing application, where sidebar is an undecorated JFrame. I have set to dispose it when mouse exits. But when I move the mouse over a component added to the sidebar, it disappears. Idea may be dumb I am new to Java. – Peter1 Aug 22 '13 at 06:47
  • 1
    please dispose() != setVisible(false) isn't it – mKorbel Aug 22 '13 at 06:48
  • read question by @Ernestas Gruodis [he's in the same problem](http://stackoverflow.com/users/2111085/ernestas-gruodis), sure this man has some knowledges about Java – mKorbel Aug 22 '13 at 06:57
  • After reading kleopatra's answer, also take a look at [this](http://stackoverflow.com/a/2445786/878469). Some other questions are also linked to that question. – predi Aug 22 '13 at 08:50
  • Maybe this article will give you some alternate sidebar ideas: http://blue-walrus.com/2010/11/expandable-swing-sidebar/ – Gilbert Le Blanc Aug 22 '13 at 13:03

2 Answers2

3

I was trying to make a Sidebar on my Swing application, where sidebar is an undecorated JFrame. I have set to dispose it when mouse exits. But when I move the mouse over a component added to the sidebar, it disappears. Idea may be dumb I am new to Java.

You could implement mouseExited as kleopatra suggests, but do it similar to this:

MouseListener closer = new MouseAdapter() {
    public void mouseExited(MouseEvent e) {
        // obtain source frame and see if mouse has left it
        Container cnt;
        if (e.getSource() instanceof JFrame) {
            // our frame, no conversion needed
            cnt = (Container) e.getSource();
        } else {
            // inside a descendant
            cnt = SwingUtilities.getAncestorOfClass(
                    JFrame.class, e.getComponent());
            // convert mouse event to make it appear
            // as if the frame generated it (I think :D)
            e = SwingUtilities.convertMouseEvent(
                    e.getComponent(), e, (Component) cnt);
        }            
        Rectangle r = new Rectangle(cnt.getSize());
        if (!r.contains(e.getPoint())) {
            cnt.setVisible(false);
            // or whatever
        }
    }
};

This is meant to be set for all descendant components of your sidebar and itself. It should check if your mouse is still inside your sidebar no matter over which of it's children/descendants the mouse is hovering.

You should also consider using an undecorated JDialog instead of a JFrame.

The reason why your sidebar is disappearing might be that you only added a mouse listener to it and not to any of it's children. It might be counter-intuitive, but when your mouse pointer enters a child/descendant of the sidebar, a mouseExited event is generated for the sidebar and then a mouseEntered event is generated for whichever child/descendant the mouse has entered. This is just how Swing mouse events are designed to work and there ain't much you can do about it.

predi
  • 5,528
  • 32
  • 60
  • ehhh .. why make it so complicated? Typically, registering listeners to _all_ children scales badly and more often than not isn't even needed. If it turns out to be needed (as in the QA you referenced in your other comment), some kind of global listener (via AWTEventListener or decorating with JLayer) is a less brittle approach. BTW: I see no reason to favour a dialog over a frame, care to elaborate? – kleopatra Aug 22 '13 at 15:18
  • @kleopatra, complicated? Perhaps in a way, but easily understood by a Swing beginner. I agree that there are more efficient ways of doing this. When I tested your solution, it did not work for me (not always, depending on mouse speed), so I played with it a bit. I'm all for the single JFrame per app [idea](http://stackoverflow.com/a/9554657/878469). Imagine ALT+Tab-ing to Lahiru's Sidebar (nothing but a glorified floating toolbar), accidentally going with your mouse over it and it disappearing. Dunno, just seems like a JDialog would be more appropriate here. – predi Aug 23 '13 at 06:14
  • reading my comment again, realized that it is partly wrong, so trying to clarify. Yes, the exit listener to the frame might not be notified. Just: adding a listener to every child is not an overly robust solution - must be done recursively, for every component in the complete hierarchy, which tends to break down in dynamic contexts where we don't have full control about the hierarchy (read: compound components like f.i. a combobox) – kleopatra Aug 23 '13 at 06:27
  • @kleopatra, indeed. Compound components would be problematic with the solution I suggest. JComboBox would have to be banned from the sidebar party. Also, I'm still in the 1.6 world, so I was not aware of JLayer. Thanks for mentioning it. Seems like a handy tool. – predi Aug 23 '13 at 06:48
  • @LahiruKavinda please consider to accept this answer (instead of mine) - it's better than mine :-) – kleopatra Aug 23 '13 at 06:53
2

Assuming the use-case in your comment is the real issue to solve, the answer is to implement the mouseExited such that it checks whether the mouse is still somewhere over the frame and hide it only if not.

Something like:

MouseListener closer = new MouseAdapter() {

    @Override
    public void mouseExited(MouseEvent e) {
        Rectangle r = new Rectangle(sideBar.getSize());
        if (!r.contains(e.getPoint())) {
            sideBar.setVisible(false);
        }
    }

};
kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • beware: @predi is correct in his/her evaluation that simply listening to the frame's exit might not be good enough (f.i. if the area between a child and the boundary of the frame is so small that a quick mouse movement can go over it without the frame's listener ever being notified) - we only disagree on if/how to fix that case :-) – kleopatra Aug 23 '13 at 06:12