我正在尝试找出是否可以为具有自定义形状的节点绘制边框。当前边框不适合节点的形状。
形状是通过以下CSS实现的:
.arrow-tail {
-fx-shape: "M 0 0 L 10 0 L 10 10 L 0 10 L 10 5 Z";
}
.arrow-head {
-fx-shape: "M 0 0 L 10 5 L 0 10 Z";
}
这是使用CSS的arrow类的重要代码:
public class Arrow extends HBox {
public void Arrow(Node graphic, String title) {
getChildren().addAll(getArrowTail(), getArrowMiddlePart(graphic, title), getArrowHead());
}
private final Region getArrowTail() {
final Region arrowTail = new Region();
arrowTail.setMinWidth(10);
arrowTail.getStyleClass().add("arrow-tail");
return arrowTail;
}
private final Node getArrowMiddlePart(Node graphic, String text) {
labelTitle = new Label(text);
labelTitle.setGraphic(graphic);
labelTitle.idProperty().bind(idProperty());
final Tooltip tooltip = new Tooltip();
tooltip.textProperty().bind(labelTitle.textProperty());
Tooltip.install(labelTitle, tooltip);
final HBox arrowMiddlePart = new HBox(labelTitle);
arrowMiddlePart.minWidthProperty().bind(minWidthProperty());
arrowMiddlePart.setAlignment(Pos.CENTER);
return arrowMiddlePart;
}
private final Region getArrowHead() {
final Region arrowHead = new Region();
arrowHead.setMinWidth(10);
arrowHead.getStyleClass().add("arrow-head");
return arrowHead;
}
}
Arrow类是一个HBox,我在其中创建一个自定义形状的区域,如箭头的尾巴和箭头,另一个HBox中带有标签的区域作为箭头的中间部分。
答案 0 :(得分:1)
不幸的是,似乎没有一种方法可以为Region
的不同边设置边界,并单独应用形状。
我建议扩展Region
作为第一个孩子直接添加Path
并覆盖layoutChildren
来调整此路径的大小。
public class Arrow extends Region {
private static final double ARROW_LENGTH = 10;
private static final Insets MARGIN = new Insets(1, ARROW_LENGTH, 1, ARROW_LENGTH);
private final HBox container;
private final HLineTo hLineTop;
private final LineTo tipTop;
private final LineTo tipBottom;
private final LineTo tailBottom;
public Arrow(Node graphic, String title) {
Path path = new Path(
new MoveTo(),
hLineTop = new HLineTo(),
tipTop = new LineTo(ARROW_LENGTH, 0),
tipBottom = new LineTo(-ARROW_LENGTH, 0),
new HLineTo(),
tailBottom = new LineTo(ARROW_LENGTH, 0),
new ClosePath());
tipTop.setAbsolute(false);
tipBottom.setAbsolute(false);
path.setManaged(false);
path.setStrokeType(StrokeType.INSIDE);
path.getStyleClass().add("arrow-shape");
Label labelTitle = new Label(title, graphic);
container = new HBox(labelTitle);
getChildren().addAll(path, container);
HBox.setHgrow(labelTitle, Priority.ALWAYS);
labelTitle.setAlignment(Pos.CENTER);
labelTitle.setMaxWidth(Double.POSITIVE_INFINITY);
}
@Override
protected void layoutChildren() {
// hbox layout
Insets insets = getInsets();
double left = insets.getLeft();
double top = insets.getTop();
double width = getWidth();
double height = getHeight();
layoutInArea(container,
left, top,
width - left - insets.getRight(), height - top - insets.getBottom(),
0, MARGIN, true, true, HPos.LEFT, VPos.TOP);
// adjust arrow shape
double length = width - ARROW_LENGTH;
double h2 = height / 2;
hLineTop.setX(length);
tipTop.setY(h2);
tipBottom.setY(h2);
tailBottom.setY(h2);
}
@Override
protected double computeMinWidth(double height) {
Insets insets = getInsets();
return 2 * ARROW_LENGTH + insets.getLeft() + insets.getRight() + container.minWidth(height);
}
@Override
protected double computeMinHeight(double width) {
Insets insets = getInsets();
return 2 + insets.getTop() + insets.getBottom() + container.minHeight(width);
}
@Override
protected double computePrefWidth(double height) {
Insets insets = getInsets();
return 2 * ARROW_LENGTH + insets.getLeft() + insets.getRight() + container.prefWidth(height);
}
@Override
protected double computePrefHeight(double width) {
Insets insets = getInsets();
return 2 + insets.getTop() + insets.getBottom() + container.prefHeight(width);
}
@Override
protected double computeMaxWidth(double height) {
Insets insets = getInsets();
return 2 * ARROW_LENGTH + insets.getLeft() + insets.getRight() + container.maxWidth(height);
}
@Override
protected double computeMaxHeight(double width) {
Insets insets = getInsets();
return 2 + insets.getTop() + insets.getBottom() + container.maxHeight(width);
}
}
CSS
.arrow-shape {
-fx-fill: dodgerblue;
-fx-stroke: black;
}
请注意,如果扩展HBox
,代码将更简单,但这将允许其他类访问子列表,这可能会导致删除Path
;扩展Region
允许我们保留方法protected
来防止这种访问,但是需要我们实现compute...
方法和子项的布局。