1

Here's the code. It prints out the mouse location when it's in the panel but not the JTextArea. I added the mouse listener to the text area as well? The problem is that the coordinates are not consistent throughout the JFrame. Is there a way to just have one mouselistener that covers the entire jframe?

Is there a way to disable the mouse listener in the textarea?

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;


public class test extends JFrame {

public test(){
    setPreferredSize(new Dimension(600,400));
    JPanel p = new JPanel();
    p.setBackground(Color.blue);
    p.setPreferredSize(new Dimension(600,200));
    JTextArea t = new JTextArea();
    t.setPreferredSize(new Dimension(600,200));
    add(p,BorderLayout.NORTH);
    add(t,BorderLayout.SOUTH);
    pack();
    MouseInput m = new MouseInput();
    addMouseMotionListener(m);
    t.addMouseMotionListener(m);            
    setVisible(true);

}

public static void main(String[] args){
    new test();
}
public class MouseInput implements MouseMotionListener{

    @Override
    public void mouseDragged(MouseEvent e) {
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        int mx = e.getX();
        int my = e.getY();
        System.out.println(mx + "," + my);          
    }       
}

}
John
  • 23
  • 2
  • 6

3 Answers3

3

The JTextArea has its own MouseListener/MouseMotionListener that grabs the mouse information before any underlying class with a MouseListener or motion listener can.

This may be fixable by using an AWTEventListener, but I have not tried this myself yet.


Edit

OK, I have tried this as a for instance:

import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class Test2 extends JPanel {
   JTextArea textarea = new JTextArea(15, 60);

   public Test2() {
      JPanel topPanel = new JPanel();
      topPanel.setBackground(Color.blue);

      setLayout(new GridLayout(0, 1));
      add(topPanel);
      add(new JScrollPane(textarea));         
      addMouseMotionListener(new MouseAdapter() {
         @Override
         public void mouseMoved(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();
            System.out.printf("%20s [%03d, %03d]%n", "From MouseAdapter:", x, y);
         }
      });

      long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
      Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

         @Override
         public void eventDispatched(AWTEvent awtEvent) {
            MouseEvent mouseEvent = (MouseEvent) awtEvent;
            Component component = (Component) awtEvent.getSource();
            Point location = component.getLocationOnScreen();
            Point test2Location = Test2.this.getLocationOnScreen();

            // Normalized to find the mouse location relative to the main JPanel,
            // the Test2 "this" JPanel.
            int x = mouseEvent.getX() + location.x - test2Location.x;
            int y = mouseEvent.getY() + location.y - test2Location.y;
            System.out.printf("%20s [%03d, %03d]%n", "From AWTEvent:", x, y);
         }
      }, eventMask );
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("Test2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new Test2());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    Without context, `AWTEventListener` is a lot of work, having to monitor what's actually triggering the events etc, not saying you shouldn't, you just need to be prepared for the work load that comes with it ;) – MadProgrammer Jul 29 '13 at 21:43
  • Is there some java text gui that doesn't have an inherent mouselistener/mousemotionlistener? – John Jul 29 '13 at 21:47
  • @John: no, that's an integral part of a text component. – Hovercraft Full Of Eels Jul 29 '13 at 22:09
  • @MadProgrammer: your advice is much appreciated. Again, I'm no pro at this, by any means. And 1+ to your answer (which I gave when it was first posted). – Hovercraft Full Of Eels Jul 29 '13 at 22:10
  • @MadProgrammer: first time I've tried this, please have a look at the code and let me know what you think. – Hovercraft Full Of Eels Jul 29 '13 at 22:21
  • @John: please give the above code a try to see what I meant by use of the AWTEventListener. – Hovercraft Full Of Eels Jul 29 '13 at 22:23
  • 1
    @HovercraftFullOfEels Great minds, just added my own example. It's a personal thing, but I looked up the parent window and translated the point to it. Not sure it would make much difference as the result would be the same. Just beware that is is going to get hammered as every mouse motion event will go through it :P – MadProgrammer Jul 29 '13 at 22:24
  • 1
    @HovercraftFullOfEels You should take a look at `SwingUtilities.convertPointFromScreen` ;) – MadProgrammer Jul 29 '13 at 22:26
  • Thank you guys! I tested the performance and it hasn't gotten slower visibly so that's good enough for this project. – John Jul 29 '13 at 23:17
3

Think of your mouse events like rain. They fall from the top of your component hierarchy down until something stops them.

Once stopped, they will no long notify other listeners lower in the hierarchy.

In you program you have and JPanel and JTextField sitting on top of another component (the content pane) sitting on a JLayeredPane sitting on top of the frame. Any one of these may be consuming the mouse event.

Try adding the MouseInput to your JPanel, p instead

Updated

This is an example of a global mouse listener (as suggested by @Hovercraft Full Of Eels, it WILL get hammered, as every mouse event will pass through it.

It also demonstrates how to translate a mouse point from it's local context to another context.

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class GloablMouseListener {

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

    public GloablMouseListener() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

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

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            JPanel panel = new JPanel();
            panel.setBackground(Color.BLUE);
            JTextArea ta = new JTextArea(10, 20);
            add(panel, BorderLayout.NORTH);
            add(new JScrollPane(ta), BorderLayout.SOUTH);

            Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
                @Override
                public void eventDispatched(AWTEvent event) {
                    if (event instanceof MouseEvent) {
                        MouseEvent e = (MouseEvent) event;
                        System.out.println("Local point = " + e.getPoint());
                        Point p = e.getPoint();
                        Window window = SwingUtilities.getWindowAncestor(e.getComponent());
                        if (window != e.getSource() && window != null) {
                            p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), window);
                        }
                        System.out.println("Global point = " + p);
                    }
                }
            }, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • The panel p doesn't cover the textarea though. I added mouseinput to p instead and the it only listens up to the borders of the blue panel – John Jul 29 '13 at 21:47
  • No, but the `JTextArea` covers the frame, which you've added your mouse listener to. There are other components ontop the frame which may also be absorbing the mouse events. What is it you are trying to achieve? – MadProgrammer Jul 29 '13 at 22:07
  • I want to find the x and y relative to the frame. – John Jul 29 '13 at 22:10
  • Also remember, mouse events are contextual. They are translated so that position 0x0 is the top, left corner of the component that triggered them – MadProgrammer Jul 29 '13 at 22:10
  • @John: `"I want to find the x and y relative to the frame."` -- but for what purpose? what do you propose to do with the information? – Hovercraft Full Of Eels Jul 29 '13 at 22:11
  • But if I add the mouse listener to the frame shouldn't only the frame be triggering the mouse event? I'll try adding the panel and the jtextarea to another panel which I'll add to the frame and see if that works. @Hovercraft, I just want to be able to process the location of the click relative to the frame at all times. – John Jul 29 '13 at 22:12
  • You could take a look at [`SwingUtilities.convertMouseEvent(Component, MouseEvent, Component)`](http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#convertMouseEvent%28java.awt.Component,%20java.awt.event.MouseEvent,%20java.awt.Component%29) and [`SwingUtilities#convertPoint(Component, Point, Component)`](http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#convertPoint%28java.awt.Component,%20int,%20int,%20java.awt.Component%29) – MadProgrammer Jul 29 '13 at 22:12
  • *"But if I add the mouse listener to the frame shouldn't only the frame be triggering the mouse event?"* - No, because any component can have a mouse listener attached to it that will then block any events going below it – MadProgrammer Jul 29 '13 at 22:13
  • Can I override the JTextArea's mouse event handling? – John Jul 29 '13 at 22:14
  • @John: do this at the risk of disabling the text component's ability to handle mouse events properly. – Hovercraft Full Of Eels Jul 29 '13 at 22:22
  • @John Added an example of a global mouse listener. This could degrade the performance of your application if you are not careful – MadProgrammer Jul 29 '13 at 22:25
  • @HovercraftFullOfEels I will do the same thing, it's just schematics about the point conversion – MadProgrammer Jul 29 '13 at 22:27
1

Try adding a MouseListener to your application's GlassPane.

See these following link. It includes a Java Web Start demo of something similar to what you want to do. How to Use Root Panes

Gregory Peck
  • 636
  • 7
  • 22
  • 1
    So now we're going to block EVERY mouse event going to any component in the application instead? This would also require the glass pane to visible – MadProgrammer Jul 29 '13 at 22:06
  • The example does include code to redirect the events so they are not consumed (but maybe not in the most efficient way.) Is there necessarily a problem with having the glass pane visible? – Gregory Peck Jul 29 '13 at 22:15
  • It covers what I want to have on the screen. – John Jul 29 '13 at 22:16
  • @John The link says the glass pane should be completely transparent. Make sure you aren't adding anything to the glass pane, which might cover up the other components. – Gregory Peck Jul 29 '13 at 22:34
  • @GregoryPeck: have you tested your recommendation? Will the JTextArea be usable if the original poster follows your recommendation? – Hovercraft Full Of Eels Jul 29 '13 at 22:39