JavaFX:如何通过一条线连接两个节点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19748744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaFX: How to connect two Nodes by a Line?
提问by Jens Piegsa
I want to connect two Node
s with a Line
(from center of the first to the center of the second).
我想Node
用 a连接两个s Line
(从第一个的中心到第二个的中心)。
Initial thoughts:
初步想法:
- It is assumed that both nodes exist somewhere in the scene graph
- The
Line
acts as a decorator and should not be pickable - If the
Node
Bounds
change, theLine
should be updated
- 假设两个节点都存在于场景图中的某处
- 在
Line
作为一个装饰,不应该拣选 - 如果
Node
Bounds
更改,Line
则应更新
It looks like I will need some compound property bindings including the proper coordinate space transformations.
看起来我需要一些复合属性绑定,包括正确的坐标空间转换。
How to achieve this? Can anyone point out a direction?
如何实现这一目标?谁能指出一个方向?
采纳答案by jewelsea
The code in this response is based on the answer to the question: CubicCurve JavaFX
此回复中的代码基于以下问题的答案:CubicCurve JavaFX
The sample below:
下面的示例:
- assumes all nodes involved are siblings.
- ensures the connecting line is not pickable by invoking setMouseTransparent(true)on the line.
- updates the line automatically to connect the centers of the two anchor nodes as the anchor nodes are dragged around.
- 假设所有涉及的节点都是兄弟节点。
- 通过在线路上调用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<MouseEvent>() {
@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<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
getScene().setCursor(Cursor.HAND);
}
});
setOnMouseDragged(new EventHandler<MouseEvent>() {
@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<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
getScene().setCursor(Cursor.HAND);
}
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
@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; }
}
}
The above code is based on a circle, so it is easy to track the circle's centerX and centerY properties.
上面的代码是基于一个圆的,所以很容易追踪到圆的centerX和centerY属性。
For an arbitrarily shaped node, you can track it's center properties within it's parent using the code below:
对于任意形状的节点,您可以使用以下代码在其父节点中跟踪它的中心属性:
class Center {
private ReadOnlyDoubleWrapper centerX = new ReadOnlyDoubleWrapper();
private ReadOnlyDoubleWrapper centerY = new ReadOnlyDoubleWrapper();
public Center(Node node) {
calcCenter(node.getBoundsInParent());
node.boundsInParentProperty().addListener(new ChangeListener<Bounds>() {
@Override public void changed(
ObservableValue<? extends Bounds> 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();
}
}
Applying the Center code to the Anchor sample above, you get the following code:
将 Center 代码应用于上面的 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()
);
If you wanted to track arbitrary nodes in a scene, not just sibling nodes, you might want to look into the node.getLayoutBoundsand node.getLocalToSceneTransformfunctions.
如果您想跟踪场景中的任意节点,而不仅仅是兄弟节点,您可能需要查看node.getLayoutBounds和node.getLocalToSceneTransform函数。