Kieran France Kieran France is a programmer for IDRSolutions. He enjoys tinkering with most things including gadgets, code and electronics. He spends his time working on the the JPedal library and our internal test suite..

1 Listener to rule them all

2 min read

Mouse Listener
1 Listener to rule them all!

We have a situation where we require a mouse listener to track page coordinates of a pdf as the mouse is moved. This is relatively simple to achieve. Unfortunately we can also have form components on a pdf page that is handled by added various java components to the page. Suddenly the mouse does not update the page coordinates when the mouse is over the form components. One way to fix this would involve passing the listener through to the form components to ensure the coords are updated. This has additional issues such as altering public method signatures and having multiple listeners of the same type on a single component. So how do we handle coordinate update for all these components? What we need is 1 listener to rule them all.

AWTEventListener – 1 Listener to rule them all

The AWTEventListener is a class that passively watches for events dispatched from Components, MenuComponents and their subclasses. This will work nicely for our needs as it will notify us if an event is triggered within our application. Using this we can trigger generic code, such as the coordinate update regardless of where the event is dispatched from.

First thing we need to do is take this method and lock it down to ensure we don’t all it too often or on the wrong events. First we need to lock the listener down to a given type of listener. This is done with a mask when we create the listener. I used AWTEvent.MOUSE_MOTION_EVENT_MASK as I only wanted to watch mouse motion events.

Next we have the method AWTEvent.getID() to lock down to a single event type, in our case we need to watch for the value 503 (mouse moved event) and as this method will be called in other methods we add a simple boolean and if statement to prevent calling the update method if we are currently calling the update method.

Now we have limited the events and frequency the update code can be called we need to actually call the update method. The easiest way to achieve this was to dispatch a MouseMoved event for the existing MouseMotionListener on PdfDecoder that handles coordinate update.

The only problem with this was that the update would be called twice, once by AWTEventListener and once by the MouseMotionListener. To do this we introduce a simple method that sets a flag to allow coordinate updating that is switched off after the coordinates have updated. This way we could keep additional functionality (such as that used in the form components) from the MouseMotionListener but control the updating so it takes place only once.

 

For those who need to see the code, here is a simple version.

long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
        
//Add universal listener to catch coords updating regardless of form component
Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
{
    //Required to prevent recursive calling of listener
    boolean listenerCalled = false;
            
    public void eventDispatched(AWTEvent e)
    {
        //ID 503 == Mouse Moved event (506 == Mouse Dragged)
        if(!listenerCalled && e.getID()==503){
            listenerCalled = true;

            Point mousePosition = ((PdfDecoder)decode_pdf).getMousePosition();
            if(mousePosition!=null){
                //Prevent double calling of the update code
                ((SwingMouseListener)mouseHandler).allowMouseCoordsUpdate();
                ((PdfDecoder)decode_pdf).dispatchEvent(new MouseEvent(((PdfDecoder)decode_pdf),
                   e.getID(),
                   System.currentTimeMillis(),
                   0,
                   mousePosition.x,
                   mousePosition.y,
                   0,
                   false));
            }

            listenerCalled = false;
        }
    }
}, eventMask);

Do you have any tips and tricks? Let us know.

If you’re a first-time reader, or simply want to be notified when we post new articles and updates, you can keep up to date by social media (TwitterFacebook and Google+) or the Blog RSS.

Kieran France Kieran France is a programmer for IDRSolutions. He enjoys tinkering with most things including gadgets, code and electronics. He spends his time working on the the JPedal library and our internal test suite..

Leave a Reply

Your email address will not be published. Required fields are marked *