2025/12/15

JavaFX 05 2d

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(預設)、INSIDEOUTSIDE
StrokeWidth 邊框寬度
Stroke 邊框顏色
StrokeLineJoin 連接線段時的連接樣式:MITERBEVELROUND
StrokeMiterLimit MITER 連接時,限制尖角長度
StrokeLineCap 線段端點樣式:BUTTROUNDSQUARE
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);
    }
}

沒有留言:

張貼留言