Results 1 to 7 of 7
  1. #1
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,060
    Rep Power
    6

    Default Exasperated by MouseMotionListener

    Picture this: I have a JLayeredPane. I add a MouseMotionListener to a component and place the component in layer 0 of the JLayeredPane. Then I display it in the JFrame.

    This works as expected if the component in question is:

    - a JPanel
    - a JPanel using any layout containing another JPanel
    - a JScrollPane with a JPanel as its viewport view
    - a JPanel using FlowLayout containing a JScrollPane

    BUT...!

    If the component is a JPanel using BorderLayout or GridLayout containing a JScrollPane, then my MouseMotionListener never receives any events.

    Whyyyyyyyyy...?!?!

    SSCCE - uncomment different lines to try different components:

    Java Code:
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseMotionAdapter;
    
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLayeredPane;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.SwingUtilities;
    
    
    public class WTFMouseMotion {
    
    	public static void main(String[] args) {
    		SwingUtilities.invokeLater(new Runnable() {
    
    			@Override
    			public void run() {
    				
    				JLayeredPane layeredPane = new JLayeredPane();
    				
    				// JPanel: works
    				JComponent component = new JPanel();
    				component.setBackground(Color.pink);
    				
    				// nested JPanel: works
    				JPanel borderLayoutPanel = new JPanel(new BorderLayout());
    				//borderLayoutPanel.add(component, BorderLayout.CENTER);
    				//component = borderLayoutPanel;
    				
    				// JScrollPane: works
    				JScrollPane scrollPane = new JScrollPane(component);
    				scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    				component = scrollPane;
    				
    				// JScrollPane inside JPanel: doesn't work!
    				// (works with FlowLayout, though...)
    				borderLayoutPanel.add(component, BorderLayout.CENTER);
    				component = borderLayoutPanel;				
    				
    				
    				// set size because JLayeredPane doesn't have a layout manager
    				component.setSize(new Dimension(500, 300));
    				component.addMouseMotionListener(new MouseMotionAdapter() {
    					@Override
    					public void mouseMoved(MouseEvent e) {
    						System.out.println("mouse motion: " + e.getPoint());
    					}
    				});
    				layeredPane.setPreferredSize(component.getSize());
    				layeredPane.add(component, new Integer(0));
    				
    				JFrame frame = new JFrame("WTF, Mouse Motion Listeners?!");
    				frame.add(layeredPane);
    				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    				frame.pack();
    				frame.setVisible(true);				
    			}
    		});
    	}
    }
    Get in the habit of using standard Java naming conventions!

  2. #2
    doWhile is offline Moderator
    Join Date
    Jul 2010
    Location
    California
    Posts
    1,642
    Rep Power
    7

    Default Re: Exasperated by MouseMotionListener

    Looks like the correct behavior to me. With a BorderLayout, the borderLayoutPanel expands to fill up the space, meaning the parent component will not receive the events given its child is covering it up (as opposed to FlowLayout, in which the component is not sized to fit its parent and thus the parent JPanel is visible and can receive the events. If you wish your parent to receive the events of the child, register the listeners in the child and delegate to the parent.

  3. #3
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,060
    Rep Power
    6

    Default Re: Exasperated by MouseMotionListener

    I think I understand what you're saying. I had it stuck in my head that the parent container receives the events and may delegate to its child, not the other way around.

    But I still don't see how that explains the difference in behavior between a JPanel with a BorderLayout containing another JPanel, and a JPanel with a BorderLayout containing a JScrollPane. In both cases, the innermost child component takes up all available space and would receive the mouse events.

    Could it be that, by default, a JPanel delegates mouse events to its parent container, but a JScrollPane does not?
    Get in the habit of using standard Java naming conventions!

  4. #4
    doWhile is offline Moderator
    Join Date
    Jul 2010
    Location
    California
    Posts
    1,642
    Rep Power
    7

    Default Re: Exasperated by MouseMotionListener

    Whether or not JPanel or JScrollPane - does the child fill up the parent container? Add borders to the child and see where they are being arranged/sized in each condition - then observe how this correlates with the MouseListener firing.

  5. #5
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,060
    Rep Power
    6

    Default Re: Exasperated by MouseMotionListener

    Yes, in both cases the child fills up the parent container.

    If the component on which the the MouseMotionListener is registered is a JPanel, and its child is another JPanel displayed smaller than its parent, then the parent continues to receive mouse events even when the pointer passes over the child. The same is not true if the child is a JScrollPane. JPanel must delegate mouse events to its parent by default. I observed this and mistakenly thought that the parent was receiving the mouse events in the first place.
    Get in the habit of using standard Java naming conventions!

  6. #6
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default Re: Exasperated by MouseMotionListener

    I don't think that there's any "delegation" of mouse events going on, but rather that it may be more simplistic than that: the top-most component that has a MouseListener (if listening to mouse events) or MouseMotionListener (if listening to these events) gets the mouse events.

  7. #7
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,060
    Rep Power
    6

    Default Re: Exasperated by MouseMotionListener

    By top-most, do you mean drawn on top, i.e., the most descended from the parent container?

    Anyway, I ended up using a AWTEventListener to capture all mouse motion events, and SwingUtilities.convertMouseEvent() to identify the ones that are within the bounds of the component I'm interested in. The component, actually a Container, is provided to my class constructor, so I don't know what it is, what listeners it has, or what listeners its children might have.

    Incidentally, the "source" of the events received by my AWTEventListener is always the content pane of the JFrame, regardless of what child component the mouse pointer is over.
    Get in the habit of using standard Java naming conventions!

Similar Threads

  1. Java MouseMotionListener
    By Fluxtime in forum New To Java
    Replies: 4
    Last Post: 03-30-2012, 09:40 PM
  2. MouseMotionListener
    By ninjaturtlez in forum AWT / Swing
    Replies: 2
    Last Post: 12-14-2011, 11:19 PM
  3. MouseMotionListener
    By hubikmar in forum AWT / Swing
    Replies: 2
    Last Post: 04-15-2011, 11:35 AM
  4. using the mousemotionlistener and mouselistener
    By ravirajparab in forum New To Java
    Replies: 1
    Last Post: 12-21-2009, 07:11 PM
  5. MouseMotionListener 'scrolling'
    By Thez in forum Java 2D
    Replies: 3
    Last Post: 03-12-2009, 11:48 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •