javafx 可直接在 pane 上面畫上 2d/3d shape。
Shape
預設支援的 shape 有以下這些
Line:直線
Rectangle:矩形
Rounded Rectangle:圓角矩形 (setArcWidth / setArcHeight)
Circle:圓形
Ellipse:橢圓
Polygon:多邊形(此處為三角形)
CubicCurve:三次貝茲曲線
QuadCurve:二次貝茲曲線
Arc:弧線,可設定弧度長度與型態
SVGPath:以 SVG 路徑字串定義任意形狀
以下是所有 shape 的 demo
package javafx.shape2d;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
//Line:直線
//Rectangle:矩形
//Rounded Rectangle:圓角矩形 (setArcWidth / setArcHeight)
//Circle:圓形
//Ellipse:橢圓
//Polygon:多邊形(此處為三角形)
//CubicCurve:三次貝茲曲線
//QuadCurve:二次貝茲曲線
//Arc:弧線,可設定弧度長度與型態
//SVGPath:以 SVG 路徑字串定義任意形狀(此例為星形)
public class ShapesDemo extends Application {
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(15);
root.setPadding(new Insets(20));
// Line
Line line = new Line(0, 0, 150, 0);
line.setStrokeWidth(3);
line.setStroke(Color.BLUE);
// Rectangle
Rectangle rectangle = new Rectangle(150, 80);
rectangle.setFill(Color.LIGHTGREEN);
rectangle.setStroke(Color.DARKGREEN);
rectangle.setStrokeWidth(2);
// Rounded Rectangle
Rectangle roundedRect = new Rectangle(150, 80);
roundedRect.setArcWidth(30);
roundedRect.setArcHeight(30);
roundedRect.setFill(Color.LIGHTCORAL);
roundedRect.setStroke(Color.DARKRED);
roundedRect.setStrokeWidth(2);
// Circle
Circle circle = new Circle(40);
circle.setFill(Color.LIGHTBLUE);
circle.setStroke(Color.DARKBLUE);
circle.setStrokeWidth(2);
// Ellipse
Ellipse ellipse = new Ellipse(60, 40);
ellipse.setFill(Color.LIGHTYELLOW);
ellipse.setStroke(Color.GOLDENROD);
ellipse.setStrokeWidth(2);
// Polygon (triangle)
Polygon polygon = new Polygon();
polygon.getPoints().addAll(
0.0, 0.0,
100.0, 0.0,
50.0, 80.0
);
polygon.setFill(Color.PLUM);
polygon.setStroke(Color.PURPLE);
polygon.setStrokeWidth(2);
// Cubic Curve
CubicCurve cubicCurve = new CubicCurve();
cubicCurve.setStartX(10);
cubicCurve.setStartY(50);
cubicCurve.setControlX1(80);
cubicCurve.setControlY1(10);
cubicCurve.setControlX2(130);
cubicCurve.setControlY2(90);
cubicCurve.setEndX(200);
cubicCurve.setEndY(50);
cubicCurve.setStroke(Color.TEAL);
cubicCurve.setStrokeWidth(3);
cubicCurve.setFill(Color.TRANSPARENT);
// Quad Curve
QuadCurve quadCurve = new QuadCurve();
quadCurve.setStartX(10);
quadCurve.setStartY(100);
quadCurve.setControlX(100);
quadCurve.setControlY(50);
quadCurve.setEndX(200);
quadCurve.setEndY(100);
quadCurve.setStroke(Color.ORANGE);
quadCurve.setStrokeWidth(3);
quadCurve.setFill(Color.TRANSPARENT);
// Arc
Arc arc = new Arc();
arc.setCenterX(100);
arc.setCenterY(100);
arc.setRadiusX(80);
arc.setRadiusY(50);
arc.setStartAngle(45);
arc.setLength(270);
arc.setType(ArcType.ROUND);
arc.setFill(Color.LIGHTPINK);
arc.setStroke(Color.HOTPINK);
arc.setStrokeWidth(2);
// SVGPath (star shape)
SVGPath svgPath = new SVGPath();
svgPath.setContent("M100,10 L40,198 L190,78 L10,78 L160,198 Z");
svgPath.setFill(Color.GOLD);
svgPath.setStroke(Color.ORANGE);
svgPath.setStrokeWidth(2);
root.getChildren().addAll(
line,
rectangle,
roundedRect,
circle,
ellipse,
polygon,
cubicCurve,
quadCurve,
arc,
svgPath
);
Scene scene = new Scene(root, 400, 900);
primaryStage.setTitle("JavaFX 2D Shapes Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Properties
2d shape 的 properties 有以下這些 method
| 屬性 | 用途說明 |
|---|---|
StrokeType |
邊框繪製位置,三種:CENTERED(預設)、INSIDE、OUTSIDE |
StrokeWidth |
邊框寬度 |
Stroke |
邊框顏色 |
StrokeLineJoin |
連接線段時的連接樣式:MITER、BEVEL、ROUND |
StrokeMiterLimit |
當 MITER 連接時,限制尖角長度 |
StrokeLineCap |
線段端點樣式:BUTT、ROUND、SQUARE |
Smooth |
是否啟用平滑繪製(抗鋸齒效果) |
sample code:
package javafx.shape2d;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class ShapeStrokePropertiesDemo extends Application {
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(20);
root.setPadding(new Insets(20));
// Rectangle 1: StrokeType.CENTERED (預設)
Rectangle rect1 = new Rectangle(150, 60);
rect1.setFill(Color.LIGHTBLUE);
rect1.setStroke(Color.DARKBLUE);
rect1.setStrokeWidth(8);
rect1.setStrokeType(StrokeType.CENTERED);
rect1.setSmooth(true);
// Rectangle 2: StrokeType.INSIDE
Rectangle rect2 = new Rectangle(150, 60);
rect2.setFill(Color.LIGHTGREEN);
rect2.setStroke(Color.DARKGREEN);
rect2.setStrokeWidth(8);
rect2.setStrokeType(StrokeType.INSIDE);
rect2.setSmooth(false);
// Rectangle 3: StrokeType.OUTSIDE
Rectangle rect3 = new Rectangle(150, 60);
rect3.setFill(Color.PEACHPUFF);
rect3.setStroke(Color.ORANGE);
rect3.setStrokeWidth(8);
rect3.setStrokeType(StrokeType.OUTSIDE);
rect3.setSmooth(true);
// Polygon with different StrokeLineJoin
Polygon polyMiter = new Polygon(0,0, 100,0, 50,80);
polyMiter.setFill(Color.TRANSPARENT);
polyMiter.setStroke(Color.CRIMSON);
polyMiter.setStrokeWidth(12);
polyMiter.setStrokeLineJoin(StrokeLineJoin.MITER);
polyMiter.setStrokeMiterLimit(10);
polyMiter.setSmooth(true);
Polygon polyBevel = new Polygon(0,0, 100,0, 50,80);
polyBevel.setFill(Color.TRANSPARENT);
polyBevel.setStroke(Color.DARKMAGENTA);
polyBevel.setStrokeWidth(12);
polyBevel.setStrokeLineJoin(StrokeLineJoin.BEVEL);
polyBevel.setSmooth(true);
Polygon polyRound = new Polygon(0,0, 100,0, 50,80);
polyRound.setFill(Color.TRANSPARENT);
polyRound.setStroke(Color.DARKORANGE);
polyRound.setStrokeWidth(12);
polyRound.setStrokeLineJoin(StrokeLineJoin.ROUND);
polyRound.setSmooth(true);
// Line with different StrokeLineCap
Line lineButt = new Line(0, 0, 150, 0);
lineButt.setStroke(Color.DARKCYAN);
lineButt.setStrokeWidth(12);
lineButt.setStrokeLineCap(StrokeLineCap.BUTT);
lineButt.setSmooth(true);
Line lineRound = new Line(0, 0, 150, 0);
lineRound.setStroke(Color.TEAL);
lineRound.setStrokeWidth(12);
lineRound.setStrokeLineCap(StrokeLineCap.ROUND);
lineRound.setSmooth(true);
Line lineSquare = new Line(0, 0, 150, 0);
lineSquare.setStroke(Color.MEDIUMVIOLETRED);
lineSquare.setStrokeWidth(12);
lineSquare.setStrokeLineCap(StrokeLineCap.SQUARE);
lineSquare.setSmooth(true);
VBox shapesGroup = new VBox(10,
rect1,
rect2,
rect3,
polyMiter,
polyBevel,
polyRound,
lineButt,
lineRound,
lineSquare
);
root.getChildren().add(shapesGroup);
Scene scene = new Scene(root, 400, 800);
primaryStage.setTitle("JavaFX Shape Stroke Properties Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Operations
2d shape 的operations 有三種
union 聯集
intersect 交集
substract 差集
sample code
package javafx.shape2d;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Text;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ShapeOperationsDemo extends Application {
@Override
public void start(Stage primaryStage) {
// 原始兩個圓形
Circle circle1 = new Circle(80, 80, 70, Color.LIGHTBLUE);
Circle circle2 = new Circle(130, 80, 70, Color.LIGHTCORAL);
circle1.setStroke(Color.BLUE);
circle1.setStrokeWidth(2);
circle2.setStroke(Color.RED);
circle2.setStrokeWidth(2);
// Union 聯集
Shape union = Shape.union(circle1, circle2);
union.setFill(Color.LIGHTGREEN);
union.setStroke(Color.DARKGREEN);
union.setStrokeWidth(2);
// Intersection 交集
Shape intersect = Shape.intersect(circle1, circle2);
intersect.setFill(Color.ORANGE);
intersect.setStroke(Color.DARKORANGE);
intersect.setStrokeWidth(2);
// Subtract 差集 circle1 - circle2
Shape subtract = Shape.subtract(circle1, circle2);
subtract.setFill(Color.PLUM);
subtract.setStroke(Color.PURPLE);
subtract.setStrokeWidth(2);
// 佈局顯示,每個下方有說明文字
VBox vUnion = new VBox(5, union, new Text("Union"));
VBox vIntersect = new VBox(5, intersect, new Text("Intersection"));
VBox vSubtract = new VBox(5, subtract, new Text("Subtract"));
HBox root = new HBox(30, vUnion, vIntersect, vSubtract);
root.setPadding(new Insets(20));
Scene scene = new Scene(root, 700, 250);
primaryStage.setTitle("JavaFX Shape Boolean Operations");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Path
Path 可用來繪製任意形狀複雜的圖案
- MoveTo(x,y) 設定起點位置
- LineTo(x,y) 從前一點畫直線到指定點
- HLineTo(x) 從前一點畫水平線到 x 軸座標
- VLineTo(y) 從前一點畫垂直線到 y 軸座標
- QuadCurveTo 畫二次貝茲曲線(1 控制點)
- CubicCurveTo 畫三次貝茲曲線(2 控制點)
- ArcTo 畫圓弧(需設定半徑、終點、sweep 等)
sample code:
package javafx.shape2d;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
//MoveTo(x,y) 設定起點位置
//LineTo(x,y) 從前一點畫直線到指定點
//HLineTo(x) 從前一點畫水平線到 x 軸座標
//VLineTo(y) 從前一點畫垂直線到 y 軸座標
//QuadCurveTo 畫二次貝茲曲線(1 控制點)
//CubicCurveTo 畫三次貝茲曲線(2 控制點)
//ArcTo 畫圓弧(需設定半徑、終點、sweep 等)
public class PathDemo extends Application {
@Override
public void start(Stage primaryStage) {
Path path = new Path();
path.setStroke(Color.DARKBLUE);
path.setStrokeWidth(3);
path.setFill(Color.LIGHTBLUE.deriveColor(1, 1, 1, 0.3)); // 半透明填色
// 1. MoveTo 起點
MoveTo moveTo = new MoveTo(50, 50);
// 2. LineTo: 畫直線
LineTo lineTo = new LineTo(150, 50);
// 3. HLineTo: 畫水平線
HLineTo hLineTo = new HLineTo(250);
// 4. VLineTo: 畫垂直線
VLineTo vLineTo = new VLineTo(150);
// 5. QuadCurveTo: 二次貝茲曲線
QuadCurveTo quadCurveTo = new QuadCurveTo(200, 200, 150, 250);
// 6. CubicCurveTo: 三次貝茲曲線
CubicCurveTo cubicCurveTo = new CubicCurveTo(100, 300, 50, 200, 50, 150);
// 7. ArcTo: 畫弧線
ArcTo arcTo = new ArcTo();
arcTo.setX(50);
arcTo.setY(50); // 回到起點形成封閉形狀
arcTo.setRadiusX(30);
arcTo.setRadiusY(30);
arcTo.setSweepFlag(true);
path.getElements().addAll(
moveTo,
lineTo,
hLineTo,
vLineTo,
quadCurveTo,
cubicCurveTo,
arcTo
);
StackPane root = new StackPane(path);
root.setPadding(new Insets(20));
Scene scene = new Scene(root, 400, 400);
primaryStage.setTitle("JavaFX Path Elements Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}