Disable globe movement on click in World Wind

2019-07-08 07:44发布

I am trying to disable movement of the globe on mouse click in World Wind. I expected to be able to do:

void disableGlobeDrag(WorldWindowGLCanvas ww) {
    ww.addMouseMotionListener(new MyMouseMotionListener());
}

where MyMouseMotionListener consumes all of the mouse events. This is not working so instead I have to do:

void disableGlobeDrag(WorldWindowGLCanvas ww) {
    for(MouseMotionListener l : ww.getMouseMotionListeners()) {
        if(l.getClass().toString().equals("class gov.nasa.worldwind.awt.AWTInputHandler")) {
            ww.removeMouseMotionListener(l);
        }
    }
}

Is it expected that consumed mouse events should still reach the gov.nasa.worldwind.awt.AWTInputHandler listener?

Update: WorldWindowGLCanvas is just calling addMouseMotionListener() on java.awt.Component so apparently I don't understand how consuming events works.

Update 2: despite sharing interfaces with Swing, calling WorldWindowGLCanvas.removeMouseMotionListener() with AWTInputHandler as the argument will prevent all other MouseMotionListeners from receiving events. The add and remove methods on AWTInputHandler should be used instead.

3条回答
啃猪蹄的小仙女
2楼-- · 2019-07-08 08:25

Why it's not working:

As discussed here, many event sources maintain an EventListenerList. The prescribed scheme allows an arbitrary number of listeners to be added or removed. This related example lists all instances of DocumentListener registered to text component's Document. No one listener preempts another.

What you might do:

Given an instance of a WorldWindowGLCanvas, you might look at the array returned by getMouseMotionListeners() and invoke removeMouseMotionListener() as warranted.

查看更多
劫难
3楼-- · 2019-07-08 08:29

After struggling with a way to do this and stumbling across this solution, I believe I've come up with the "correct" solution. Removing the mouse motion listener completely does technically work, but it breaks other functionality that might be useful (KML tree node selecton, on screen view controls).

Create a subclass an input handler to remove the "move to" functionality

public class MyOrbitViewInputHandler extends OrbitViewInputHandler
{
  public MyOrbitViewInputHandler()
  {
    // Disable single click to pan functionality
    ViewInputAttributes.ActionAttributes actionAttrs =
      this.getAttributes().getActionMap(ViewInputAttributes.DEVICE_MOUSE).getActionAttributes(ViewInputAttributes.VIEW_MOVE_TO);
    actionAttrs.setMouseActionListener(null);
  }
}

Specify your new input handler in your worldwind.xml configuration file

<Property name="gov.nasa.worldwind.avkey.ViewInputHandlerClassName"
          value="mil.dtra.nucs.coe.ui.map.MyOrbitViewInputHandler"/>

Using this method, all other mouse interactions that take place on the canvas will still work correctly, but the "single click to pan" functionality is removed.

If you're curious about what other behaviors are specified that you could potentially override, you can look at gov.nasa.worldwind.awt.BasicViewInputHandler

查看更多
放我归山
4楼-- · 2019-07-08 08:39

Unfortunately removing the MouseMotionListener as @trashgod suggested does not work since there is some World Wind specific behavior happening: removing gov.nasa.worldwind.awt.AWTInputHandler causes other MouseMotionListeners to stop receiving event notifications.

To disable globe dragging and still receive events in another MouseMotionListener the following steps were necessary:

Get a reference to World Wind's AWTInputHandler:

AWTInputHandler wwHandler = null;
// get World Wind's AWTInputHandler class:
for (MouseMotionListener l : ww.getMouseMotionListeners()) {
    if(l instanceof AWTInputHandler) {
        wwHandler = (AWTInputHandler)l;
        break;
    }
}

Create a MouseMotionListener which consumes events:

public class MyMouseMotionListener implements MouseMotionListener {
    @Override
    public void mouseDragged(MouseEvent e) {
        // consume the event so the globe position does not change
        e.consume();
        if (e.getSource() instanceof WorldWindowGLCanvas) {
            // get the position of the mouse
            final WorldWindowGLCanvas canvas = ((WorldWindowGLCanvas) e.getSource());
            final Position p = canvas.getCurrentPosition();
            // do something with the position here
        }
    }
    @Override
    public void mouseMoved(MouseEvent e) {
        e.consume();
    }
}

Add the mouse motion listener to the AWTInputHandler:

if(wwHandler != null) {
    wwHandler.addMouseMotionListener(new MyMouseMotionListener());
} else {
    // I don't think this should happen unless the AWTInputHandler
    // is explicitly removed by client code
    logger.error("Couldn't find AWTInputHandler");
}

That said, I have no idea why WorldWindowGLCanvas is using Component.addMouseMotionListener() rather than AWTInputHandler.addMouseMotionListener().

查看更多
登录 后发表回答