创建不规则形状的 JavaFX 组件

Creating irregular shaped JavaFX component

我正在尝试为 JavaFX 制作一个不规则形状的组件,但遇到了非常奇怪的行为。

package pkg;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;

public class App extends Application {

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException {
        Pane pane = new Pane();
        for (int x = 50; x < 150; x += 50) {
            for (int y = 50; y < 150; y += 50) {
                pane.getChildren().add(new Triangle(x, y));
            }
        }
        scene = new Scene(pane, 640, 480);
        stage.setScene(scene);
        stage.show();
    }

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

    private static class Triangle extends Region {

        Polygon p;

        public Triangle(int x, int y) {
            super();
            p = new Polygon(x - 25, y + 25, x, y - 25, x + 25, y + 25);
            setOnMouseEntered(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent t) {
                    p.setFill(Color.RED);
                    System.out.println("x: " + x + " y: " + y);
                }
            });
            setOnMouseExited(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent t) {
                    p.setFill(Color.BLACK);
                }
            });
            setShape(p);
            getChildren().add(p);
        }
    }
}

依赖关系:

<dependencies>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>15.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>13</version>
    </dependency>
</dependencies>

当这是 运行 时,它会创建 4 个三角形,每个三角形都有鼠标悬停行为。

但是,当您将鼠标悬停在每个三角形上时,它们都表现得好像右下角的三角形被触发了。

这不直观。我不太清楚那是什么。

这里发生了什么,我如何让这些组件独立反应?

默认情况下,区域的边界将从 [0,0] 开始并扩展以填充所有子项所需的 space。因此,您创建的最后一个三角形实际上具有覆盖所有其他三角形的边界,并且由于它位于堆栈的最顶部(因为您最后添加它),它接收所有鼠标事件。

如果你将每个三角形推到后面(这不是一个特别好的解决方案),你会看到你想要的:

    for (int x = 50; x < 150; x += 50) {
        for (int y = 50; y < 150; y += 50) {
            Triangle t = new Triangle(x, y);
            pane.getChildren().add(t);
            t.toBack();
        }
    }

另一个解决方案是添加

setPickOnBounds(false) ;

Triangle 构造函数。这只会在鼠标悬停在 Triangle.

的非透明部分上时触发鼠标事件

也许您应该创建仅占用 space 他们真正需要的区域。您可能还需要 setPickOnBounds(false) 调用,因此三角形仅响应鼠标悬停在三角形部分(而不是包含它的完整矩形区域)上:

private static class Triangle extends Region {

    Polygon p;

    public Triangle() {
        super();
        p = new Polygon(0, 50, 25, 0, 50, 50);
        setOnMouseEntered(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                p.setFill(Color.RED);
            }
        });
        setOnMouseExited(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                p.setFill(Color.BLACK);
            }
        });
        setShape(p);
        getChildren().add(p);
        setPickOnBounds(false);
    }
}

然后您可以按照通常的方式将三角形放置在它们的包含窗格中:

    Pane pane = new Pane();
    for (int x = 25; x < 125; x += 50) {
        for (int y = 25; y < 125; y += 50) {
            Triangle t = new Triangle();
            pane.getChildren().add(t);
            t.setLayoutX(x);
            t.setLayoutY(y);
        }
    }

他们还将使用布局窗格:

    GridPane pane = new GridPane();
    for (int x = 0; x < 2; x++) {
        for (int y = 0; y < 2; y++) {
            Triangle t = new Triangle();
            pane.add(t, x, y);
        }
    }