2013-06-26 3 views

답변

10

오라클은 tutorial on draggable nodes를 제공해야합니다. 때로는

private Node makeDraggable(final Node node) { 
final DragContext dragContext = new DragContext(); 
final Group wrapGroup = new Group(node); 

wrapGroup.addEventFilter(
    MouseEvent.ANY, 
    new EventHandler<MouseEvent>() { 
     public void handle(final MouseEvent mouseEvent) { 
      if (dragModeActiveProperty.get()) { 
       // disable mouse events for all children 
       mouseEvent.consume(); 
      } 
     } 
    }); 

wrapGroup.addEventFilter(
    MouseEvent.MOUSE_PRESSED, 
    new EventHandler<MouseEvent>() { 
     public void handle(final MouseEvent mouseEvent) { 
      if (dragModeActiveProperty.get()) { 
       // remember initial mouse cursor coordinates 
       // and node position 
       dragContext.mouseAnchorX = mouseEvent.getX(); 
       dragContext.mouseAnchorY = mouseEvent.getY(); 
       dragContext.initialTranslateX = 
        node.getTranslateX(); 
       dragContext.initialTranslateY = 
        node.getTranslateY(); 
      } 
     } 
    }); 

wrapGroup.addEventFilter(
    MouseEvent.MOUSE_DRAGGED, 
    new EventHandler<MouseEvent>() { 
     public void handle(final MouseEvent mouseEvent) { 
      if (dragModeActiveProperty.get()) { 
       // shift node from its initial position by delta 
       // calculated from mouse cursor movement 
       node.setTranslateX(
        dragContext.initialTranslateX 
         + mouseEvent.getX() 
         - dragContext.mouseAnchorX); 
       node.setTranslateY(
        dragContext.initialTranslateY 
         + mouseEvent.getY() 
         - dragContext.mouseAnchorY); 
      } 
     } 
    }); 

return wrapGroup; 

} 

당신이 필터 드래그 문맥을 필요로하지 않으며, 단지이 example에 같은 다양한 마우스 이벤트에 작용하여 간단한 일을 수행 할 수 있습니다 :

을 여기

튜토리얼에서 makeDraggable 방법
static class Delta { double x, y; } 
// make a node movable by dragging it around with the mouse. 
private void enableDrag(final Circle circle) { 
final Delta dragDelta = new Delta(); 
circle.setOnMousePressed(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    // record a delta distance for the drag and drop operation. 
    dragDelta.x = circle.getCenterX() - mouseEvent.getX(); 
    dragDelta.y = circle.getCenterY() - mouseEvent.getY(); 
    circle.getScene().setCursor(Cursor.MOVE); 
    } 
}); 
circle.setOnMouseReleased(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    circle.getScene().setCursor(Cursor.HAND); 
    } 
}); 
circle.setOnMouseDragged(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    circle.setCenterX(mouseEvent.getX() + dragDelta.x); 
    circle.setCenterY(mouseEvent.getY() + dragDelta.y); 
    } 
}); 
circle.setOnMouseEntered(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    if (!mouseEvent.isPrimaryButtonDown()) { 
     circle.getScene().setCursor(Cursor.HAND); 
    } 
    } 
}); 
circle.setOnMouseExited(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    if (!mouseEvent.isPrimaryButtonDown()) { 
     circle.getScene().setCursor(Cursor.DEFAULT); 
    } 
    } 
}); 
} 

주변 노드를 드래그하는 동일한 기술은 drag around stages로 사용할 수 있습니다

static class Delta { double x, y; } 
/** makes a stage draggable using a given node */ 
public static void makeDraggable(final Stage stage, final Node byNode) { 
final Delta dragDelta = new Delta(); 
byNode.setOnMousePressed(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    // record a delta distance for the drag and drop operation. 
    dragDelta.x = stage.getX() - mouseEvent.getScreenX(); 
    dragDelta.y = stage.getY() - mouseEvent.getScreenY(); 
    byNode.setCursor(Cursor.MOVE); 
    } 
}); 
byNode.setOnMouseReleased(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    byNode.setCursor(Cursor.HAND); 
    } 
}); 
byNode.setOnMouseDragged(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    stage.setX(mouseEvent.getScreenX() + dragDelta.x); 
    stage.setY(mouseEvent.getScreenY() + dragDelta.y); 
    } 
}); 
byNode.setOnMouseEntered(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    if (!mouseEvent.isPrimaryButtonDown()) { 
     byNode.setCursor(Cursor.HAND); 
    } 
    } 
}); 
byNode.setOnMouseExited(new EventHandler<MouseEvent>() { 
    @Override public void handle(MouseEvent mouseEvent) { 
    if (!mouseEvent.isPrimaryButtonDown()) { 
     byNode.setCursor(Cursor.DEFAULT); 
    } 
    } 
}); 
} 

부모 노드 (여러 자식 노드가 포함되어 있음) 주위를 끌기위한 샘플입니다. 이 예는 대부분의 노드가 가지고 있지 않은 centerX/Y 속성에 의존하지 않으므로 위에 나온 원 기반 예제보다 일반적입니다. 대신 parentX 또는 Y에있는 모든 노드에서 사용할 수있는 layoutX/Y에서 작동합니다 .

import javafx.application.Application; 
import javafx.scene.*; 
import javafx.scene.layout.*; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.scene.text.Text; 
import javafx.scene.text.TextBoundsType; 
import javafx.stage.Stage; 

public class TextOnCircleWithDragging extends Application { 
    private static final int W = 400; 
    private static final int H = 400; 
    private static final int R = 15; 

    @Override 
    public void start(Stage stage) { 
     final StackPane circleWithText = new StackPane(
       createCircle(), 
       createText() 
     ); 
     circleWithText.relocate(
       W/2 - R/2, 
       H/2 - R/2 
     ); 

     makeDraggable(circleWithText); 

     stage.setScene(
       new Scene(
         new Pane(circleWithText), 
         W, H 
       ) 
     ); 
     stage.show(); 
    } 

    private Circle createCircle() { 
     final Circle circle = new Circle(R); 
     circle.setFill(Color.PALEGREEN); 
     circle.relocate(0, 0); 

     return circle; 
    } 

    private Text createText() { 
     final Text text = new Text("A"); 
     text.setBoundsType(TextBoundsType.VISUAL); 

     return text; 
    } 

    private void makeDraggable(Node node) { 
     final Delta dragDelta = new Delta(); 

     node.setOnMouseEntered(me -> { 
      if (!me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.HAND); 
      } 
     }); 
     node.setOnMouseExited(me -> { 
      if (!me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
     }); 
     node.setOnMousePressed(me -> { 
      if (me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
      dragDelta.x = me.getX(); 
      dragDelta.y = me.getY(); 
      node.getScene().setCursor(Cursor.MOVE); 
     }); 
     node.setOnMouseReleased(me -> { 
      if (!me.isPrimaryButtonDown()) { 
       node.getScene().setCursor(Cursor.DEFAULT); 
      } 
     }); 
     node.setOnMouseDragged(me -> { 
      node.setLayoutX(node.getLayoutX() + me.getX() - dragDelta.x); 
      node.setLayoutY(node.getLayoutY() + me.getY() - dragDelta.y); 
     }); 
    } 

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

    private class Delta { 
     public double x; 
     public double y; 
    } 
} 

지연 조정

커서 뒤에 끌고 노드 지연을보고하고 해결하고자하는 경우, 다음에 Xanatos의 답변을 참조하십시오

그는 다음과 같이 설정할 것을 제안합니다 :

-Dprism.vsync=false 

해결 방법 문제 https://bugs.openjdk.java.net/browse/JDK-8087922.

0

파티에 조금 늦게,하지만 난 노드의 많은 subclassses에 draggability 필요, 그래서 유틸리티 클래스의 사용 생성 : 이것은 모든 노드에 적용 할 수

/** 
* Generalised implementation of 'Draggability' of a {@link Node}. The Draggable class is used as a 'namespace' for the internal 
* class/interfaces/enum. 
* @author phill 
* 
*/ 
public class Draggable { 
public enum Event { 
    None, DragStart, Drag, DragEnd 
} 

/** 
* Marker for an entity that has draggable nature. 
* @author phill 
*/ 
public interface Interface { 
    public abstract Draggable.Nature getDraggableNature(); 
} 

public interface Listener { 
    public void accept(Nature draggableNature, Event dragEvent); 
} 

/** 
* Class that encapsulates the draggable nature of a node. 
* <ul> 
* <li>EventNode: the event that receives the drag events</li> 
* <li>One or more DragNodes: that move in response to the drag events. The EventNode is usually (but not always) a 
* DragNode</li> 
* <li>Listeners: listen for the drag events</li> 
* </ul> 
* @author phill 
* 
*/ 
public static final class Nature implements EventHandler<MouseEvent> { 
    private double lastMouseX = 0, lastMouseY = 0; // scene coords 

    private boolean dragging = false; 

    private final boolean enabled = true; 
    private final Node eventNode; 
    private final List<Node> dragNodes = new ArrayList<>(); 
    private final List<Listener> dragListeners = new ArrayList<>(); 

    public Nature(final Node node) { 
     this(node, node); 
    } 

    public Nature(final Node eventNode, final Node... dragNodes) { 
     this.eventNode = eventNode; 
     this.dragNodes.addAll(Arrays.asList(dragNodes)); 
     this.eventNode.addEventHandler(MouseEvent.ANY, this); 
    } 

    public final boolean addDraggedNode(final Node node) { 
     if (!this.dragNodes.contains(node)) { 
      return this.dragNodes.add(node); 
     } 
     return false; 
    } 

    public final boolean addListener(final Listener listener) { 
     return this.dragListeners.add(listener); 
    } 

    public final void detatch() { 
     this.eventNode.removeEventFilter(MouseEvent.ANY, this); 
    } 

    public final List<Node> getDragNodes() { 
     return new ArrayList<>(this.dragNodes); 
    } 

    public final Node getEventNode() { 
     return this.eventNode; 
    } 

    @Override 
    public final void handle(final MouseEvent event) { 
     if (MouseEvent.MOUSE_PRESSED == event.getEventType()) { 
      if (this.enabled && this.eventNode.contains(event.getX(), event.getY())) { 
       this.lastMouseX = event.getSceneX(); 
       this.lastMouseY = event.getSceneY(); 
       event.consume(); 
      } 
     } else if (MouseEvent.MOUSE_DRAGGED == event.getEventType()) { 
      if (!this.dragging) { 
       this.dragging = true; 
       for (final Listener listener : this.dragListeners) { 
        listener.accept(this, Draggable.Event.DragStart); 
       } 
      } 
      if (this.dragging) { 
       final double deltaX = event.getSceneX() - this.lastMouseX; 
       final double deltaY = event.getSceneY() - this.lastMouseY; 

       for (final Node dragNode : this.dragNodes) { 
        final double initialTranslateX = dragNode.getTranslateX(); 
        final double initialTranslateY = dragNode.getTranslateY(); 
        dragNode.setTranslateX(initialTranslateX + deltaX); 
        dragNode.setTranslateY(initialTranslateY + deltaY); 
       } 

       this.lastMouseX = event.getSceneX(); 
       this.lastMouseY = event.getSceneY(); 

       event.consume(); 
       for (final Listener listener : this.dragListeners) { 
        listener.accept(this, Draggable.Event.Drag); 
       } 
      } 
     } else if (MouseEvent.MOUSE_RELEASED == event.getEventType()) { 
      if (this.dragging) { 
       event.consume(); 
       this.dragging = false; 
       for (final Listener listener : this.dragListeners) { 
        listener.accept(this, Draggable.Event.DragEnd); 
       } 
      } 
     } 

    } 

    public final boolean removeDraggedNode(final Node node) { 
     return this.dragNodes.remove(node); 
    } 

    public final boolean removeListener(final Listener listener) { 
     return this.dragListeners.remove(listener); 
    } 

    /** 
    * When the initial mousePressed is missing we can supply the first coordinates programmatically. 
    * @param lastMouseX 
    * @param lastMouseY 
    */ 
    public final void setLastMouse(final double lastMouseX, final double lastMouseY) { 
     this.lastMouseX = lastMouseX; 
     this.lastMouseY = lastMouseY; 
    } 
} 
} 

을 :

final Rectangle rectangle = new Rectangle(100, 100, 200, 50); 
Draggable.Nature nature = new Draggable.Nature(rectangle); 

그리고 사각형은 드래그 가능합니다. Draggable.Nature에 리스너를 추가 할 수 있으며 동시에 드래그 할 수있는 추가 노드를 추가 할 수 있습니다.

이것은 나의 필요를 해결했습니다. 도움이되기를 바랍니다.

관련 문제