加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

JavaFX:如何通过一行连接两个节点?

发布时间:2020-12-14 16:20:48 所属栏目:Java 来源:网络整理
导读:我想用一条线连接两个节点(从第一个的中心到第二个的中心). 初步想法: 假设两个节点存在于场景图中的某处 线条作为装饰器,不应该是可选的 如果Node Bounds改变,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,endY);
    stage.setTitle("Line Manipulation Sample");
    stage.setScene(new Scene(new Group(line,start,end),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,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,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; }
  }  
}

上面的代码是基于一个圆,所以很容易跟踪圆的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<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();
    }
}

将中心代码应用到上面的锚定示例中,您将获得以下代码:

Anchor start = new Anchor(Color.PALEGREEN,startY);
Anchor end   = new Anchor(Color.TOMATO,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的功能.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读