JavaFX边框不适合自定义形状的节点

3
我正在尝试弄清楚是否可以为具有自定义形状的节点绘制边框。目前,边框不适合节点的形状。
目前它看起来像这样: enter image description here 该形状是通过以下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:
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作为箭头中间部分。

我猜测一下,你能否在那个形状上叠加另一个形状,边框为黑色,中心透明?然后去掉当前的边框。 - SedJ601
1个回答

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...方法和子元素的布局。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接