当前位置: 首页 > 知识库问答 >
问题:

如何在Javafx 2.0中创建可拖动节点。

赖绪
2023-03-14

如何在Javafx 2.0中制作可拖动节点。JavaFX专门用于GUI目的,仅我需要一些示例,谢谢

共有2个答案

公英哲
2023-03-14

虽然来晚了一点,但我需要在Node的许多子类中具有可拖动性,所以我创建了一个实用程序类:

/**
 * 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);

矩形是可拖动的。您可以将侦听器添加到可拖动的。自然,您可以添加可以同时拖动的额外节点。

这解决了我的需要,希望能有所帮助。

卫嘉泽
2023-03-14

Oracle提供了有关可拖动节点的教程

以下是教程中的makeDraggable方法:

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;

}

有时,您不需要过滤器和拖动上下文,只需对各种鼠标事件进行操作即可完成一些更简单的操作,如本例所示:

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);
    }
  }
});
}

拖动节点的相同技术也可用于拖动阶段:

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属性,而是适用于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的回答:

  • https://stackoverflow.com/a/22695105/1155209

他建议你不妨设置:

-Dprism.vsync=false

解决问题的步骤https://bugs.openjdk.java.net/browse/JDK-8087922.

 类似资料:
  • 问题内容: 我正在matplotlib中的轴对象上绘制图例,但是声称将其放置在智能位置的默认定位似乎不起作用。理想情况下,我希望图例可由用户拖动。如何才能做到这一点? 问题答案: 注意:现在已内置到matplotlib中 将按预期工作 好吧,我发现解决方案的点点滴滴分散在邮件列表中。我提出了一个很好的模块化代码块,您可以插入并使用…在这里: …以及您的代码中… 我给Matplotlib-users

  • 问题内容: 我在网上搜索了可拖动的Swing组件的示例,但发现示例不完整或不起作用。 我需要的是一个 Swing组件 ,可以用鼠标将其 拖动 到另一个组件中。在拖动时,它应该 已经改变 了位置,而不仅仅是“跳转”到目的地。 我将感谢没有非标准API的示例。 谢谢。 问题答案: 我提出了一个简单但可行的解决方案,我自己找到了;) 我该怎么办? 当按下鼠标时,我 在屏幕上* 记录了 光标的 位置以及

  • 本文向大家介绍如何使用JavaScript和CSS创建可拖动的HTML元素?,包括了如何使用JavaScript和CSS创建可拖动的HTML元素?的使用技巧和注意事项,需要的朋友参考一下 要使用JavaScript和CSS创建可拖动的HTML元素,代码如下- 示例 输出结果 上面的代码将产生以下输出- 通过拖动来移动div时-

  • 问题内容: 我创建了一个新的JsonNode 与此节点一起,然后如何在其中添加键值对,以便可以使用新值构造此新节点?我在http://www.cowtowncoder.com/blog/archives/2011/08/entry_460.html中阅读的内容涉及使用 但是,查看Jackson的JsonNode(v1.8)的API并没有显示任何此类方法。 问题答案: 这些方法在:除法中,大多数读取

  • 我已经使用MP Android chart创建了一个折线图,并希望创建一条可拖动的线来设置限制。因此,如果该值超过行值,则用户会收到警报。我的用例类似于Android系统数据使用限制。 我遇到了LimitLines-https://github.com/PhilJay/MPAndroidChart/wiki/The-Axis,还使用触摸事件回调拖动https://github.com/PhilJa