4

Let's say I have some shapes like:

Shape s1 = new Rectangle(10, 10);
Shape s2 = new Circle(10);

etc. I would like to draw them on canvas. In Swing it was possible through Graphics2D.draw(Shape shape) method, but I don't see equivalent in JavaFX GraphicsContext. Is there something like this in JavaFX?

swch
  • 1,432
  • 4
  • 21
  • 37

1 Answers1

8

Im not entirely sure its possible to draw the objects directly onto the canvas in the way you would expect, it is to draw it directly onto the stage node, such as the example from here :

package javafx8_shape;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

    /**
     *
     * @web java-buddy.blogspot.com
     */
    public class JavaFX8_Shape extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            Group root = new Group();
            Scene scene = new Scene(root, 500, 500, Color.BLACK);
    
            //Filled rectangle
            Rectangle rect1 = new Rectangle(10, 10, 200, 200);
            rect1.setFill(Color.BLUE);
            
            //Transparent rectangle with Stroke
            Rectangle rect2 = new Rectangle(60, 60, 200, 200);
            rect2.setFill(Color.TRANSPARENT);
            rect2.setStroke(Color.RED);
            rect2.setStrokeWidth(10);
            
            //Rectangle with Stroke, no Fill color specified
            Rectangle rect3 = new Rectangle(110, 110, 200, 200);
            rect3.setStroke(Color.GREEN);
            rect3.setStrokeWidth(10);
            
            root.getChildren().addAll(rect1, rect2, rect3);
    
            primaryStage.setTitle("java-buddy.blogspot.com");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            launch(args);
        }
    
    }

however the canvas API is generally the way in which you draw the shapes, rectangle etc through method calls. So to recap you can even draw rectangle objects onto other nodes such as a HBOX:

HBox root =  new HBox(rectangle);  

But drawing it onto the canvas is usually done like this:

         gc.setFill(Color.WHITESMOKE);
         gc.fillRect(gc.getCanvas().getLayoutX(),      
         gc.getCanvas().getLayoutY(), 
         gc.getCanvas().getWidth(), 
         gc.getCanvas().getHeight());
         gc.setFill(Color.GREEN);
         gc.setStroke(Color.BLUE);

The best alternative would be to develop methods, which you pass your objects to and then use the API to draw using the dimensions of your object onto the canvas...

private void drawRectangle(GraphicsContext gc,Rectangle rect){
   gc.setFill(Color.WHITESMOKE);
   gc.fillRect(rect.getX(),      
               rect.getY(), 
               rect.getWidth(), 
               rect.getHeight());
   gc.setFill(Color.GREEN);
   gc.setStroke(Color.BLUE);
}
Aubin
  • 14,617
  • 9
  • 61
  • 84
D3181
  • 2,037
  • 5
  • 19
  • 44
  • Yeah I know that can draw shapes on canvas, but I though that there is some out of the box solution when I have for example collection of shapes to draw. Custom methods seems to be only solution here, but I feel like it is boilerplate – swch Nov 21 '16 at 22:20
  • Yeh i mean the best other way imo would be to add your canvas into a stack pane, and then add your rectangles etc onto the stackpane too essentially overlapping...this way you can add any node to javafx and still control its position etc and that would be my thought on how to get around it without boilerplate code like above - see this example if you want a working way to get an image or technically over the canvas.. https://stackoverflow.com/questions/30068651/is-it-possible-to-put-imageview-on-canvas-in-javafx – D3181 Nov 21 '16 at 22:22
  • The idea with stackpane is not that bad, but putting Shapes into canvas would be more natural I think. I wonder why authors decided to not add method like draw(Shape) in api. Thanks for your help – swch Nov 21 '16 at 22:28
  • I actually recall during the earlier versions of JavaFX that most of the drawing was done using their own scripting language which was java-like which felt odd at the time too! But i would guess their plans were to have shape classes etc used for defining new controls and the api for performance reasons on the canvas,perhaps the reason goes as far as compiler optimization, if the method calls can be optimized more efficiently during run time than trying to get information from an object at runtime etc...but i do agree having the ability would be useful Anyway good luck on the project :) – D3181 Nov 21 '16 at 22:32
  • 1
    Actually the though occurs that the rectangle and shape classes contain a number of methods that would perhaps lower performance if you were to draw a large number of instances of the shapes: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/shape/Rectangle.html Having all these methods may be their reason, if you prevent the creation of all these methods just to draw a rectangle on the canvas the performance will be better since they probably pertain mostly to ui dev i.e dragging etc wont be useful for example in every single game so having 100 square objects in memory is a waste – D3181 Nov 21 '16 at 22:42
  • 1
    you can use pane.snapshot(); Add your shape to pane, then get snapshot and draw it on canvas. Snapshots also can be cached. Pane must be on stage. You can put it on x:-9999,y:-9999 – Igor Bloom Jan 18 '18 at 20:32
  • 1
    `return gc;` should be removed in the last code snippet – bugybunny Jun 04 '18 at 15:36