1

I have a shape that I would like to render as a JavaFX Polyline, but with multiple colours in the stroke. Essentially, it would be an 8-pixel wide blue line with a 2-pixel wide black border on either side of it. I can achieve the same effect by creating a Group, and then adding two Polylines into the Group:

Group group = new Group();
double[] coords = ...

Polyline bg = new Polyline(coords);
bg.setStroke(Color.BLACK);
bg.setStrokeWidth(12);

Polyline fg = new Polyline(coords);
fg.setStroke(Color.BLUE);
fg.setStrokeWidth(8);

group.getChildren().add(bg);
group.getChildren().add(fg);

So, while that renders the way I want, I now have a Group rather than a Polyline, so I can't treat it as a Shape. I can't see any way to specify a custom drawing mechanism, so is there a way to do this?

ctg
  • 615
  • 8
  • 16
  • Check this [question](http://stackoverflow.com/questions/28764190/javafx-line-fill-color/28765099#28765099). You can transform your polyline into a collection of lines, and apply the same solution. But you will have rendering issues at the joins. – José Pereda Apr 13 '16 at 09:40
  • Given that my goal is to remain with a single Polyline node, that approach is not going to work. I need a solution that does not involve breaking the node down into other nodes, or using a different type of node to render it. To be clear, if the answer is "that's not possible", I would prefer to hear that than to have a solution that does not fit my requirements. – ctg Apr 13 '16 at 19:46

1 Answers1

1

Overall, I like the group based approach you outlined in your question. It is unfortunate that it does not fit your particular situation, but for others who come across this question, it may be the preferred solution for their application.


You could apply a DropShadow effect to your PolyLine to generate the border color. This will end up with slightly rounded edges for corners, which may or may not be what you wish.

polyline

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polyline;
import javafx.stage.Stage;

public class Polyanna extends Application {
    @Override
    public void start(Stage stage) {
        Polyline polyline = new Polyline();
        polyline.getPoints().addAll(50.0, 50.0,
                200.0, 100.0,
                100.0, 200.0
        );
        polyline.setStrokeWidth(8);
        DropShadow borderEffect = new DropShadow(
                BlurType.THREE_PASS_BOX, Color.BLUE, 2, 1, 0, 0
        );
        polyline.setEffect(borderEffect);

        stage.setScene(
                new Scene(
                        new Group(polyline),
                        250, 250
                )
        );
        stage.show();
    }

    public static void main(String\[\] args) {
        launch(args);
    }
}

An alternate option is to draw a Polygon with a fill and stroke rather than a PolyLine. You could write a routine which takes an array of points for a Polyline and generates a matching array of points for a Polygon from that input array (with a bit of work ;-)


You can use shape intersection capabilities to create an arbitrary shape that you can fill and stroke to possibly end up with the easiest way to get something closest to what you wish. With this approach you have programmatic control over things like line caps, mitering and line join settings for the stroke of the border color.

shape intersect

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;

public class PolyIntersect extends Application {
    private static final double W = 250;
    private static final double H = 250;

    @Override
    public void start(Stage stage) {
        Polyline polyline = new Polyline();
        polyline.getPoints().addAll(50.0, 50.0,
                200.0, 100.0,
                100.0, 200.0
        );
        polyline.setStrokeWidth(8);
        Rectangle bg = new Rectangle(0, 0, W, H);
        Shape shape = Shape.intersect(bg, polyline);
        shape.setFill(Color.BLACK);
        shape.setStroke(Color.BLUE);
        shape.setStrokeType(StrokeType.OUTSIDE);
        shape.setStrokeWidth(2);

        stage.setScene(
                new Scene(
                        new Group(shape),
                        W, H
                )
        );
        stage.setResizable(false);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406