JavaFX:如何通过线路连接两个节点?

我想用一条Line连接两个Node (从第一个中心到第二个中心)。

初步想法:

  • 假设两个节点都存在于场景图中的某处
  • Line充当装饰者,不应该是可挑选的
  • 如果Node Bounds更改,则应更新Line

看起来我需要一些复合属性绑定,包括适当的坐标空间转换。

怎么做到这一点? 谁能指出方向?

此响应中的代码基于问题的答案: CubicCurve JavaFX

以下示例:

  • 假设所涉及的所有节点都是兄弟姐妹。
  • 通过在行上调用setMouseTransparent(true)来确保连接线不可选 。
  • 当拖动锚节点时,自动更新线以连接两个锚节点的中心。

线

 import javafx.application.Application; import javafx.beans.property.*; import javafx.event.EventHandler; import javafx.scene.*; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.*; import javafx.stage.Stage; /** Example of dragging anchors around to manipulate a line. */ public class LineManipulator extends Application { public static void main(String[] args) throws Exception { launch(args); } @Override public void start(final Stage stage) throws Exception { DoubleProperty startX = new SimpleDoubleProperty(100); DoubleProperty startY = new SimpleDoubleProperty(100); DoubleProperty endX = new SimpleDoubleProperty(300); DoubleProperty endY = new SimpleDoubleProperty(200); Anchor start = new Anchor(Color.PALEGREEN, startX, startY); Anchor end = new Anchor(Color.TOMATO, endX, endY); Line line = new BoundLine(startX, startY, endX, endY); stage.setTitle("Line Manipulation Sample"); stage.setScene(new Scene(new Group(line, start, end), 400, 400, Color.ALICEBLUE)); stage.show(); } class BoundLine extends Line { BoundLine(DoubleProperty startX, DoubleProperty startY, DoubleProperty endX, DoubleProperty endY) { startXProperty().bind(startX); startYProperty().bind(startY); endXProperty().bind(endX); endYProperty().bind(endY); setStrokeWidth(2); setStroke(Color.GRAY.deriveColor(0, 1, 1, 0.5)); setStrokeLineCap(StrokeLineCap.BUTT); getStrokeDashArray().setAll(10.0, 5.0); setMouseTransparent(true); } } // a draggable anchor displayed around a point. class Anchor extends Circle { Anchor(Color color, DoubleProperty x, DoubleProperty y) { super(x.get(), y.get(), 10); setFill(color.deriveColor(1, 1, 1, 0.5)); setStroke(color); setStrokeWidth(2); setStrokeType(StrokeType.OUTSIDE); x.bind(centerXProperty()); y.bind(centerYProperty()); enableDrag(); } // make a node movable by dragging it around with the mouse. private void enableDrag() { final Delta dragDelta = new Delta(); setOnMousePressed(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { // record a delta distance for the drag and drop operation. dragDelta.x = getCenterX() - mouseEvent.getX(); dragDelta.y = getCenterY() - mouseEvent.getY(); getScene().setCursor(Cursor.MOVE); } }); setOnMouseReleased(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { getScene().setCursor(Cursor.HAND); } }); setOnMouseDragged(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { double newX = mouseEvent.getX() + dragDelta.x; if (newX > 0 && newX < getScene().getWidth()) { setCenterX(newX); } double newY = mouseEvent.getY() + dragDelta.y; if (newY > 0 && newY < getScene().getHeight()) { setCenterY(newY); } } }); setOnMouseEntered(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { if (!mouseEvent.isPrimaryButtonDown()) { getScene().setCursor(Cursor.HAND); } } }); setOnMouseExited(new EventHandler() { @Override public void handle(MouseEvent mouseEvent) { if (!mouseEvent.isPrimaryButtonDown()) { getScene().setCursor(Cursor.DEFAULT); } } }); } // records relative x and y co-ordinates. private class Delta { double x, y; } } } 

上面的代码基于一个圆圈,因此很容易跟踪圆的centerX和centerY属性。

对于任意形状的节点,您可以使用以下代码在其父级中跟踪它的中心属性:

 class Center { private ReadOnlyDoubleWrapper centerX = new ReadOnlyDoubleWrapper(); private ReadOnlyDoubleWrapper centerY = new ReadOnlyDoubleWrapper(); public Center(Node node) { calcCenter(node.getBoundsInParent()); node.boundsInParentProperty().addListener(new ChangeListener() { @Override public void changed( ObservableValue observableValue, Bounds oldBounds, Bounds bounds ) { calcCenter(bounds); } }); } private void calcCenter(Bounds bounds) { centerX.set(bounds.getMinX() + bounds.getWidth() / 2); centerY.set(bounds.getMinY() + bounds.getHeight() / 2); } ReadOnlyDoubleProperty centerXProperty() { return centerX.getReadOnlyProperty(); } ReadOnlyDoubleProperty centerYProperty() { return centerY.getReadOnlyProperty(); } } 

将中心代码应用于上面的Anchor示例,您将获得以下代码:

 Anchor start = new Anchor(Color.PALEGREEN, startX, startY); Anchor end = new Anchor(Color.TOMATO, endX, endY); Center startCenter = new Center(start); Center endCenter = new Center(end); Line line = new BoundLine( startCenter.centerXProperty(), startCenter.centerYProperty(), endCenter.centerXProperty(), endCenter.centerYProperty() ); 

如果要跟踪场景中的任意节点,而不仅仅是兄弟节点,您可能需要查看node.getLayoutBounds和node.getLocalToSceneTransform函数。