如何绘制箭头JavaFX? (窗格) [英] How to draw arrow JavaFX? (pane)
问题描述
我需要从无向图制作有向图。我可以绘制line-Edge,但我不知道如何制作箭头:
I need to make directed graph from undirected. I can draw line-Edge, but I don't know how to make arrow:
public class Edge extends Group {
protected Cell source;
protected Cell target;
Line line;
public Edge(Cell source, Cell target) {
this.source = source;
this.target = target;
source.addCellChild(target);
target.addCellParent(source);
line = new Line();
line.startXProperty().bind(source.layoutXProperty().add(source.getBoundsInParent().getWidth() / 2.0));
line.startYProperty().bind(source.layoutYProperty().add(source.getBoundsInParent().getHeight() / 2.0));
line.endXProperty().bind(target.layoutXProperty().add( target.getBoundsInParent().getWidth() / 2.0));
line.endYProperty().bind(target.layoutYProperty().add( target.getBoundsInParent().getHeight() / 2.0));
getChildren().addAll(line);
}
推荐答案
(或者 Polygon
,其中的箭头相同)。
You need to add 2 more lines to make an arrow head (or a Polygon
with the same points for a filled arrow head).
注意箭头的方向可以根据主连接的线末端的开始和结束之间的差异来确定。构成箭头的每条线的一端需要与主线的末端位于相同的坐标处。另一端可以通过组合主线方向的一部分和与主线正交的部分来计算:
Note that the direction of the arrow can be determined based on the difference between start and end of the line ends of the "main" connection. One end of each of the lines that make up the arrow head need to be at the same coordinates as the end of the main line. The other end can be calculated by combining a part in direction of the main line and a part ortogonal to the main line:
public class Arrow extends Group {
private final Line line;
public Arrow() {
this(new Line(), new Line(), new Line());
}
private static final double arrowLength = 20;
private static final double arrowWidth = 7;
private Arrow(Line line, Line arrow1, Line arrow2) {
super(line, arrow1, arrow2);
this.line = line;
InvalidationListener updater = o -> {
double ex = getEndX();
double ey = getEndY();
double sx = getStartX();
double sy = getStartY();
arrow1.setEndX(ex);
arrow1.setEndY(ey);
arrow2.setEndX(ex);
arrow2.setEndY(ey);
if (ex == sx && ey == sy) {
// arrow parts of length 0
arrow1.setStartX(ex);
arrow1.setStartY(ey);
arrow2.setStartX(ex);
arrow2.setStartY(ey);
} else {
double factor = arrowLength / Math.hypot(sx-ex, sy-ey);
double factorO = arrowWidth / Math.hypot(sx-ex, sy-ey);
// part in direction of main line
double dx = (sx - ex) * factor;
double dy = (sy - ey) * factor;
// part ortogonal to main line
double ox = (sx - ex) * factorO;
double oy = (sy - ey) * factorO;
arrow1.setStartX(ex + dx - oy);
arrow1.setStartY(ey + dy + ox);
arrow2.setStartX(ex + dx + oy);
arrow2.setStartY(ey + dy - ox);
}
};
// add updater to properties
startXProperty().addListener(updater);
startYProperty().addListener(updater);
endXProperty().addListener(updater);
endYProperty().addListener(updater);
updater.invalidated(null);
}
// start/end properties
public final void setStartX(double value) {
line.setStartX(value);
}
public final double getStartX() {
return line.getStartX();
}
public final DoubleProperty startXProperty() {
return line.startXProperty();
}
public final void setStartY(double value) {
line.setStartY(value);
}
public final double getStartY() {
return line.getStartY();
}
public final DoubleProperty startYProperty() {
return line.startYProperty();
}
public final void setEndX(double value) {
line.setEndX(value);
}
public final double getEndX() {
return line.getEndX();
}
public final DoubleProperty endXProperty() {
return line.endXProperty();
}
public final void setEndY(double value) {
line.setEndY(value);
}
public final double getEndY() {
return line.getEndY();
}
public final DoubleProperty endYProperty() {
return line.endYProperty();
}
}
使用
Use
@Override
public void start(Stage primaryStage) {
Pane root = new Pane();
Arrow arrow = new Arrow();
root.getChildren().add(arrow);
root.setOnMouseClicked(evt -> {
switch (evt.getButton()) {
case PRIMARY:
// set pos of end with arrow head
arrow.setEndX(evt.getX());
arrow.setEndY(evt.getY());
break;
case SECONDARY:
// set pos of end without arrow head
arrow.setStartX(evt.getX());
arrow.setStartY(evt.getY());
break;
}
});
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
这篇关于如何绘制箭头JavaFX? (窗格)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!