Граница JavaFX не подходит для узла с пользовательской формой - PullRequest
0 голосов
/ 29 октября 2018

Я пытаюсь выяснить, можно ли нарисовать границу для узла с пользовательской формой. В настоящее время граница не соответствует форме узла.

Вот как это выглядит сейчас:
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 с надписью в нем в качестве средней части стрелки.

1 Ответ

0 голосов
/ 29 октября 2018

К сожалению, похоже, нет способа установить границы для различных сторон 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... и размещения дочерних элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...