JavaFX: how to connect two nodes in a row?

I want to connect two nodes (from the center of the first to the center of the second) with a line

Initial ideas:

Suppose two nodes exist somewhere in the scene graph > the line is used as a decorator and should not be optional > if the node boundaries change, the line should be updated

It seems that I need some composite attribute binding, including correct coordinate space conversion

How does this happen? Can anyone point out the direction?

Solution

The code in this response is based on the answer to the question: cubic curve JavaFX

The following examples:

It is assumed that all nodes involved are siblings. > Ensure that the connector cannot go online by calling setmousetransparent (true). > As the anchor node is dragged, the center of the line connecting the two anchor nodes is automatically updated

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

The above code is based on a circle, so it is easy to track the centerx and centery properties of the circle

For nodes of any shape, you can use the following code to track their parent central attributes:

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 central code to the anchor example above, you will get the following code:

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

If you want to track any node in the scene, not just siblings, you may need to look at node Getlayoutboundaries and node Getlocaltoscenetransform function

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>