Shapes
Tags: java, programming, learning, beginners
Published: 2024-06-20 19:26:22

JavaFX provides many shape classes for drawing texts, lines, circles, rectangles, ellipses, arcs, polygons, and polylines. The **Shape** class is the abstract base class that defines the common properties for all shapes. Among them are the **fill**, **stroke**, and **strokeWidth** properties. The **fill** property specifies a color that fills the interior of a shape. The **stroke** property specifies a color that is used to draw the outline of a shape. The **strokeWidth** property specifies the width of the outline of a shape. This section introduces the classes **Text**, **Line**, **Rectangle**, **Circle**, **Ellipse**, **Arc**, **Polygon**, and **Polyline** for drawing texts and simple shapes. All these are subclasses of **Shape**, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvm1d8qgktychm7nxgqh.png)

## Text

The **Text** class defines a node that displays a string at a starting point (**x**, **y**), as shown in Figure below (a). A **Text** object is usually placed in a pane. The pane’s upper-left corner point is (**0**, **0**) and the bottom-right point is (**pane.getWidth()**, **pane.getHeight()**). A string may be displayed in multiple lines separated by **\n**. The UML diagram for the **Text** class is
shown in Figure below. The program below gives an example that demonstrates text, as shown in Figure below (b).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1glw885ljm5jtg2qi57n.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ocvdtcctrstm6d7o90f.png)

```
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.FontPosture;

public class ShowText extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane to hold the texts
		Pane pane = new Pane();
		pane.setPadding(new Insets(5, 5, 5, 5));
		Text text1 = new Text(20, 20, "Programming is fun");
		text1.setFont(Font.font("Courier", FontWeight.BOLD, FontPosture.ITALIC, 15));
		pane.getChildren().add(text1);
		
		Text text2 = new Text(60, 60, "Programming is fun\nDisplay text");
		pane.getChildren().add(text2);
		
		Text text3 = new Text(10, 100, "Programming is fun\nDisplay text");
		text3.setFill(Color.RED);
		text3.setUnderline(true);
		text3.setStrikethrough(true);
		pane.getChildren().add(text3);
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(pane);
		primaryStage.setTitle("ShowText"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}

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

```

The program creates a **Text** (line 19), sets its font (line 20), and places it to the pane (line 21). The program creates another **Text** with multiple lines (line 23) and places it to the pane (line 24). The program creates the third **Text** (line 26), sets its color (line 27), sets an underline and a strike through line (lines 28–29), and places it to the pane (line 30).

## Line

A line connects two points with four parameters **startX**, **startY**, **endX**, and **endY**, as shown in Figure below (a). The **Line** class defines a line. The UML diagram for the **Line** class is shown in Figure below. The program below gives an example that demonstrates text, as shown in Figure below (b).

```
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.shape.Line;

public class ShowLine extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a scene and place it in the stage
		Scene scene = new Scene(new LinePane(), 200, 200);
		primaryStage.setTitle("ShowLine"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}

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

class LinePane extends Pane{
	public LinePane() {
		Line line1 = new Line(10, 10, 10, 10);
		line1.endXProperty().bind(widthProperty().subtract(10));
		line1.endYProperty().bind(heightProperty().subtract(10));
		line1.setStrokeWidth(5);
		line1.setStroke(Color.GREEN);
		getChildren().add(line1);
		
		Line line2 = new Line(10, 10, 10, 10);
		line2.startXProperty().bind(widthProperty().subtract(10));
		line2.endYProperty().bind(heightProperty().subtract(10));
		line2.setStrokeWidth(5);
		line2.setStroke(Color.GREEN);
		getChildren().add(line2);
	}
}

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o669tg5wkxhyf23nvtml.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jqfa7fs0oexltj6zxfnm.png)

The program defines a custom pane class named **LinePane** (line 24). The custom pane class creates two lines and binds the starting and ending points of the line with the width and height of the pane (lines 27–28, 34–35) so that the two points of the lines are changed as the pane is resized.

## Rectangle

A rectangle is defined by the parameters **x**, **y**, **width**, **height**, **arcWidth**, and **arcHeight**, as shown in Figure below (a). The rectangle’s upper-left corner point is at (**x**, **y**) and parameter **aw** (**arcWidth**) is the horizontal diameter of the arcs at the corner, and **ah** (**arcHeight**) is the vertical diameter of the arcs at the corner.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rsuyylqgbdiamck99pl.png)

The **Rectangle** class defines a rectangle. The UML diagram for the **Rectangle** class is shown in Figure below. The program below gives an example that demonstrates rectangles, as shown in Figure above (b).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lu7r57z7dv4d9qmd09wq.png)

```
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.scene.shape.Rectangle;

public class ShowRectangle extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane
		Pane pane = new Pane();
		
		// Create rectangles and add to pane
		Rectangle r1 = new Rectangle(25, 10, 60, 30);
		r1.setStroke(Color.BLACK);
		r1.setFill(Color.WHITE);
		pane.getChildren().add(new Text(10, 27, "r1"));
		pane.getChildren().add(r1);
		
		Rectangle r2 = new Rectangle(25, 50, 60, 30);
		pane.getChildren().add(new Text(10, 67, "r2"));
		pane.getChildren().add(r2);
		
		Rectangle r3 = new Rectangle(25, 90, 60, 30);
		r3.setArcWidth(15);
		r3.setArcHeight(25);
		pane.getChildren().add(new Text(10, 107, "r3"));
		pane.getChildren().add(r3);
		
		for(int i = 0; i < 4; i++) {
			Rectangle r = new Rectangle(100, 50, 100, 30);
			r.setRotate(i * 360 / 8);
			r.setStroke(Color.color(Math.random(), Math.random(), Math.random()));
			r.setFill(Color.WHITE);
			pane.getChildren().add(r);
		}
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(pane, 250, 150);
		primaryStage.setTitle("ShowRectangle"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}

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

```

The program creates multiple rectangles. By default, the fill color is black. So a rectangle is filled with black color. The stroke color is white by default. Line 18 sets stroke color of rectangle **r1** to black. The program creates rectangle **r3** (line 27) and sets its arc width and arc height (lines 28–29). So **r3** is displayed as a rounded rectangle.

The program repeatedly creates a rectangle (line 34), rotates it (line 35), sets a random stroke color (lines 36), its fill color to white (line 37), and adds the rectangle to the pane (line 38).

If line 37 is replaced by the following line

`r.setFill(null);`

the rectangle is not filled with a color. So they are displayed as shown in Figure above (c).

## Circle and Ellipse

You have used circles in several examples early in the previous posts. A circle is defined by its parameters **centerX**, **centerY**, and **radius**. The **Circle** class defines a circle. The UML diagram for the **Circle** class is shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3zaiclvvtb0yg7jn97jx.png)

An ellipse is defined by its parameters **centerX**, **centerY**, **radiusX**, and **radiusY**, as shown in Figure below (a). The **Ellipse** class defines an ellipse. The UML diagram for the **Ellipse** class is shown in Figure below. The program below gives an example that demonstrates ellipses, as shown in Figure below (b).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vora1ixwjupdgzfaxara.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zyrn56c1p1dnk1ywshh0.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lyn7nitudiet7c4lkhae.png)

The program repeatedly creates an ellipse (line 17), sets a random stroke color (lines 18), sets its fill color to white (line 19), rotates it (line 20), and adds the rectangle to the pane (line 21).

## Arc

An arc is conceived as part of an ellipse, defined by the parameters **centerX**, **centerY**, **radiusX**, **radiusY**, **startAngle**, **length**, and an arc type (**ArcType.OPEN**, **ArcType.CHORD**, or **ArcType.ROUND**). The parameter **startAngle** is the starting angle; and length is the spanning angle (i.e., the angle covered by the arc). Angles are measured in degrees and follow the usual mathematical conventions (i.e., 0 degrees is in the easterly direction, and positive angles indicate counterclockwise rotation from the easterly direction), as shown in Figure below (a).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pcpo7gdeqx8pvolor7n3.png)

The **Arc** class defines an arc. The UML diagram for the **Arc** class is shown in Figure below. The program below gives an example that demonstrates ellipses, as shown in Figure above (b).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwrbmnvltihr3e669lsz.png)

```
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.text.Text;

public class ShowArc extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane
		Pane pane = new Pane();
		
		Arc arc1 = new Arc(150, 100, 80, 80, 30, 35); // Create an arc
		arc1.setFill(Color.RED); // Set fill color
		arc1.setType(ArcType.ROUND); // Set arc type
		pane.getChildren().add(new Text(210, 40, "arc1: round"));
		pane.getChildren().add(arc1); // Add arc to pane
		
		Arc arc2 = new Arc(150, 100, 80, 80, 30 + 90, 35);
		arc2.setFill(Color.WHITE);
		arc2.setType(ArcType.OPEN);
		arc2.setStroke(Color.BLACK);
		pane.getChildren().add(new Text(20, 40, "arc2: open"));
		pane.getChildren().add(arc2);
		
		Arc arc3 = new Arc(150, 100, 80, 80, 30 + 180, 35);
		arc3.setFill(Color.WHITE);
		arc3.setType(ArcType.CHORD);
		arc3.setStroke(Color.BLACK);
		pane.getChildren().add(new Text(20, 170, "arc3: chord"));
		pane.getChildren().add(arc3);
		
		Arc arc4 = new Arc(150, 100, 80, 80, 30 + 270, 35);
		arc4.setFill(Color.GREEN);
		arc4.setType(ArcType.CHORD);
		arc4.setStroke(Color.BLACK);
		pane.getChildren().add(new Text(210, 170, "arc4: chord"));
		pane.getChildren().add(arc4);

		// Create a scene and place it in the stage
		Scene scene = new Scene(pane, 300, 200);
		primaryStage.setTitle("ShowArc"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}

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

```

The program creates an arc **arc1** centered at (**150**, **100**) with **radiusX 80** and **radiusY 80**. The starting angle is **30** with **length 35** (line 15). **arc1**’s arc type is set to **ArcType.ROUND **(line 18). Since **arc1**’s fill color is red, **arc1** is displayed filled with red round.

The program creates an arc **arc3** centered at (**150**, **100**) with **radiusX 80** and **radiusY 80**. The starting angle is **30+180** with **length 35** (line 29). **Arc3**’s arc type is set to **ArcType.CHORD** (line 31). Since **arc3**’s fill color is white and stroke color is black, **arc3** is displayed with black outline as a chord.

Angles may be negative. A negative starting angle sweeps clockwise from the easterly direction, as shown in Figure below. A negative spanning angle sweeps clockwise from the starting angle. The following two statements define the same arc:

`new Arc(x, y, radiusX, radiusY, -30, -20);
new Arc(x, y, radiusX, radiusY, -50, 20);`

The first statement uses negative starting angle **-30** and negative spanning angle **-20**, as shown in Figure below (a). The second statement uses negative starting angle **-50** and positive spanning angle **20**, as shown in Figure below (b).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qu8d7ty8e9asrzk4xaei.png)

Note that the trigonometric methods in the **Math** class use the angles in radians, but the angles in the **Arc** class are in degrees.

## Polygon and Polyline

The **Polygon** class defines a polygon that connects a sequence of points, as shown in Figure below (a). The **Polyline** class is similar to the **Polygon** class except that the **Polyline** class is not automatically closed, as shown in Figure below (b).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v25xa2dbaeexz4qk5e8p.png)

The UML diagram for the **Polygon** class is shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ts4sqxbj9sew3atilkoq.png)

The program below gives an example that creates a hexagon, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cpkgfvm2bpwa2c9we7qo.png)

```
package application;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.shape.Polygon;
//import javafx.scene.shape.Polyline;

public class ShowPolygon extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Create a pane, a polygon, and place polygon to pane
		Pane pane = new Pane();
		Polygon polygon= new Polygon();
		pane.getChildren().add(polygon);
		polygon.setFill(Color.WHITE);
		polygon.setStroke(Color.BLACK);
		ObservableList<Double> list = polygon.getPoints();
		
		final double WIDTH = 200, HEIGHT = 200;
		double centerX = WIDTH / 2, centerY = HEIGHT / 2;
		double radius = Math.min(WIDTH,  HEIGHT) * 0.4;
		
		// Add points to the polygon list
		for(int i = 0; i < 6; i++) {
			list.add(centerX + radius * Math.cos(2 * i * Math.PI / 6));
			list.add(centerY - radius * Math.sin(2 * i * Math.PI / 6));
		}
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(pane, WIDTH, HEIGHT);
		primaryStage.setTitle("ShowPolygon"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}

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

```

The program creates a polygon (line 16) and adds it to a pane (line 17). The **polygon.getPoints()** method returns an **ObservableList<Double>** (line 20), which contains the **add** method for adding an element to the list (lines 28–29). Note that the value passed to **add(value)** must be a **double** value. If an **int** value is passed, the **int** value would be automatically boxed into an **Integer**. This would cause an error because the **ObservableList<Double>** consists of **Double** elements.

The loop adds six points to the polygon (lines 27–30). Each point is represented by its x- and y-coordinates. For each point, its x-coordinate is added to the polygon’s list (line 28) and then its y-coordinate is added to the list (line 29). The formula for computing the x- and
y-coordinates for a point in the hexagon is illustrated in Figure above (a).

If you replace **Polygon** by **Polyline**, the program displays a polyline as shown in Figure above (b). The **Polyline** class is used in the same way as **Polygon** except that the starting and ending point are not connected in **Polyline**.