如何在JavaFX中实现箭头形状?

时间:2017-09-17 11:41:54

标签: java javafx

我正在编写一个需要绘制有向图的JavaFX应用程序。我想通过形状来实现它,因为我希望可以拖动顶点。我用一个圆来表示一个顶点,但是当我试图找到一个代表有向边的形状时,我遇到了一个问题 有向边应该看起来像一个箭头,我的想法是将一条线与一个三角形组合起来表示它。所以我扩展了javafx.scene.shape.Line类:

class Arrow extends Line {
    Polygon triangle;

    Arrow(double startX, double startY, double endX, double endY) {
        super(startX, startY, endX, endY);
        double dx = endX - startX;
        double dy = endY - startY;
        double angle = Math.atan2(dy, dx);
        triangle = new Polygon(endX, endY, endX - 8, endY + 4, endX - 8, endY - 4);
        triangle.setRotate(Math.toDegrees(angle));
        triangle.rotateProperty().bind()
            triangle.rotateProperty().bind(Bindings.createDoubleBinding(() -> { 
            double x = this.getEndX() - this.getStartX();
            double y = this.getEndY() - this.getStartY();
            double a = Math.atan2(y, x);
            return Math.toDegrees(a);
        }));
    }
}

由于顶点可以被拖动,当然边缘应该同时移动,这意味着箭头内的三角形应该根据线条的属性移动和旋转。但我还没有找到一种方法将Polygon的位置属性与Line的endXProperty和endYProperty绑定。
所以我想问一下如何实现这个目标?或者有没有更好的方法来实现形状的可移动箭头(有向边)?

2 个答案:

答案 0 :(得分:0)

如果要将ChangeListeners添加到endX和endY属性并在changed方法中重新定位Triangle,则可以使用Line移动三角形。

答案 1 :(得分:0)

我一直在寻找一个像您一样的箭头,虽然它在数学上是正确的,但是需要一些编程的东西,我创建了dx和dy作为属性,并为其添加了侦听器,并为三角形创建了“旋转”。这是完美的作品,但是您可以绑定其他属性,例如填充,颜色等。

import javafx.beans.binding.DoubleBinding;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;

public class Arrow extends Line {

private Polygon triangle;
private Pane Parent;


public Arrow(Pane Parent) {
    this.Parent = Parent;
    Parent.getChildren().addAll(this);
    canvas();
}

private DoubleBinding dx;
private DoubleBinding dy;

private void canvas(){
    dx = endXProperty().add(startXProperty().negate());
    dy = endYProperty().add(startYProperty().negate());
    triangle = new Polygon(getEndX(), getEndY(), getEndX() - 16, getEndY() + 8, getEndX() - 16, getEndY() - 8);
    var rotate = new Rotate(0,0,0,1,Rotate.Z_AXIS);
    triangle.getTransforms().add(rotate);
    dx.addListener((observable, oldValue, newValue) -> {
        rotate.setAngle(getAngle(dy.doubleValue(), newValue.doubleValue()));
    });
    dy.addListener((observable, oldValue, newValue) -> {
        rotate.setAngle(getAngle(newValue.doubleValue(), dx.doubleValue()));
    });
    triangle.layoutXProperty().bind(endXProperty());
    triangle.layoutYProperty().bind(endYProperty());
    Parent.getChildren().add(triangle);
}

private double getAngle(double dy ,double dx){
    return Math.toDegrees(Math.atan2(dy, dx));
}

}