javaclicklisteneropenstreetmapjmapviewer

JMapViewer, MouseListener called 2 times


Working with JMapViewer, a strange behavior of the component was recognized. I am using DefaultMapController to get the map position (lat, lon).

import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import org.openstreetmap.gui.jmapviewer.DefaultMapController;
import org.openstreetmap.gui.jmapviewer.JMapViewer;

public class Test extends JMapViewer{

public Test() 
{
    addMouseListener(new DefaultMapController(this) {
            public void mouseClicked(MouseEvent e){
            Point  start = e.getPoint();
            System.out.println(e.getPoint());
            }            
       });
  }

protected void paintComponent(Graphics g){super.paintComponent(g);}  

public static void main (String [] args){
            JFrame jf = new JFrame();
            jf.setSize(800, 600);
            Test t= new Test();
            jf.add(t);
            jf.setVisible(true);
    }
}

Running the code, after the left mouse button is pressed, the method mouseClicked() gets called multiple times (2x). After the replacement

    addMouseListener(new DefaultMapController(this) {

with

    addMouseListener(new MouseAdapter() {

the code works correctly, the method gets called only 1x. Where is the problem? Is it a bug inside the library or the syntax is wrong or unsafe? How to avoid this issue? Thanks for your help.


Solution

  • Your Test extends JMapViewer, adding a MouseListener in an instance initializer block. As a consequence, the "default constructor will call the no-argument constructor of the superclass." The superclass, JMapController, adds your MouseListener—you guessed it—a second time.

    public JMapController(JMapViewer map) {
        this.map = map;
        if (this instanceof MouseListener)
            map.addMouseListener((MouseListener) this);
        …
    }
    

    Instead, create a new JMapController or DefaultMapController, as shown here, and use it to construct your JMapViewer.

    import java.awt.EventQueue;
    import java.awt.event.MouseEvent;
    import javax.swing.JFrame;
    import org.openstreetmap.gui.jmapviewer.DefaultMapController;
    import org.openstreetmap.gui.jmapviewer.JMapViewer;
    
    /**
     * @see https://stackoverflow.com/a/39461854/230513
     */
    public class TestMapController {
    
        private void display() {
            JFrame f = new JFrame("TestMapController");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JMapViewer map = new JMapViewer();
            new DefaultMapController(map) {
                @Override
                public void mouseClicked(MouseEvent e) {
                    System.out.println(e.getPoint());
                }
            };
            f.add(map);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new TestMapController()::display);
        }
    }