4

JavaFX provides both low-level path painting methods on a GraphicsContext and a high-level Path node.

I want to store shapes in classes and draw them in a GraphicsContext. The Path class seems convenient for me. I know, it is meant to be used as a node in the scene graph, but it contains all drawing elements I need.

I am looking for a method like GraphicsContext.fillPath(Path) but there is none.

Do I have to iterate over the Path elements by hand and translate them into low-level GraphicsContext methods, or did I miss something?

Andi
  • 3,234
  • 4
  • 32
  • 37
  • Hello Andi, is it possible to save the path in a variable and set it to a lable or something like this? I don't understand your problem... In JavaFX it is possible to Bind your Data to a specific graphical Object like an Label. So you can do something like this: label.bind(StringPath) -> This Example is not the real code but it would work like this from the logical side – Lukas Hieronimus Adler Jan 20 '15 at 12:32
  • 1
    This won't answer your question, but it's an easier way. Can you add a canvas to a pane then draw nodes or shapes (like path) on the pane and whatever else on the canvas? That's what I do for some custom high speed graphs. It's also easier for moving nodes around because there seems to be no XOR drawing mode for the javafx canvas, unlike awt. – brian Jan 20 '15 at 21:00

2 Answers2

3

Do I have to iterate over the Path elements by hand and translate them into low-level GraphicsContext methods?

Yes. You will need to write a translator to take data extracted from a Path and invoke appropriate graphics context methods (see the Path Rendering methods), for example beginPath(), moveTo(), lineTo(), closePath(), fill, stroke(), etc.


Rather than using a Path, you could perhaps use an SVGPath. It is easy to translate an SVGPath from a Scene graph node data to a GraphicsContext method - you can just do gc.appendSVGPath(svgPath.getContent()).

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • 1
    Finally I wrote my own Path class, so that I can use it on all platforms for which I write the software (JavaFX, Java 2D, Android, GWT). It's very simple... [Here](https://github.com/Xenoage/Zong/tree/0f0d6a721fb027d1d70dc049d3fe0c2350be4596/layout/src/com/xenoage/zong/symbols/path) are the data structures, and [here](https://github.com/Xenoage/Zong/blob/0f0d6a721fb027d1d70dc049d3fe0c2350be4596/renderer-javafx/src/com/xenoage/zong/renderer/javafx/symbols/JfxPath.java) is an example how the JavaFX renderer processes them. For performance reasons, the SVGPath from a String is no option for me. – Andi Jan 21 '15 at 16:39
  • Nice clean implementation Andi. You can always [answer your own questions](http://stackoverflow.com/help/self-answer). – jewelsea Jan 21 '15 at 18:22
0

I know, it comes a bit late, but here is a simple generic solution...

Since Path class is of type Node, you can use the method Node.snapshot() on your specific Path and then pass the generated WritableImage to GraphicsContext.drawImage().

Here's a simple code-snippet how to achieve this:

public void start(Stage primaryStage) {

    Pane pane = new Pane();
    Canvas canvas = new Canvas(70, 70);
    GraphicsContext gc = canvas.getGraphicsContext2D();
    pane.getChildren().add(canvas);
    Scene scene = new Scene(pane, 70, 70);
    primaryStage.setScene(scene);
    
    Path path = new Path(
            new MoveTo(10,10), 
            new LineTo(60,60), 
            new LineTo(60, 10), 
            new ClosePath());
    path.setStroke(Color.BLACK);
    path.setStrokeWidth(2.0);
    Bounds pathBounds = path.getLayoutBounds();
    WritableImage snapshot = new WritableImage(
            (int) pathBounds.getWidth(), (int) pathBounds.getHeight());
    SnapshotParameters snapshotParams = new SnapshotParameters();
    snapshot = path.snapshot(snapshotParams, snapshot);
    gc.drawImage(snapshot, pathBounds.getMinX(), pathBounds.getMinY());
    
    primaryStage.show();
}
Andy
  • 488
  • 4
  • 13