【问题标题】:JavaFX - center origin at center of pane rather than top leftJavaFX - 窗格中心而不是左上角的中心原点
【发布时间】:2018-01-29 21:13:14
【问题描述】:

我正在尝试按照Red Blob Games 构建一个十六进制网格。十六进制网格轴向坐标系从-radius < x < radius-radius < y < radius 运行。 Red Blob 定义了一个函数,将int 轴向坐标转换为double 像素坐标。

public Point tileToPixel(Tile tile) {
    Hex hex = (Hex) tile;
    double x = (orientation.getF0() * hex.getX() + orientation.getF1() * hex.getY()) * size.getX();
    double y = (orientation.getF2() * hex.getX() + orientation.getF3() * hex.getY()) * size.getY();
    return new Point(x, y);
}

Point 等价于Point2D;我决定自己写。

orientation 是一个enum,它根据平顶或点顶六边形方向定义六边形的点。

POINT_TOP_ORIENTATION   (   Math.sqrt(3.0), Math.sqrt(3.0)/2.0, 0.0, 3.0/2.0,
                            Math.sqrt(3.0)/3.0, -1.0/3.0, 0.0, 2.0/3.0,
                            0.5),

FLAT_TOP_ORIENTATION    (   3.0/2.0, 0.0, Math.sqrt(3.0)/2.0, Math.sqrt(3.0),
                            2.0/3.0, 0.0, -1.0/3.0, Math.sqrt(3.0)/3.0,
                            0.0);

private HexOrientation(double f0, double f1, double f2, double f3, 
                        double b0, double b1, double b2, double b3,
                        double startAngle) {
    this.f0 = f0;
    this.f1 = f1;
    this.f2 = f2;
    this.f3 = f3;
    this.b0 = b0;
    this.b1 = b1;
    this.b2 = b2;
    this.b3 = b3;
    this.startAngle = startAngle;
}

问题变成了轴向坐标被转换为像素坐标double,其中包含负值并采用正常的笛卡尔格式(正Y向上,正X向右),原点为(0,0)在中心.

我正在使用 Scene Builder 来构建我的显示。这是我非常基本的设置:

你可以看到我有一个AnchorPane 作为根,一个BorderPane 和一个位于BorderPane 中心的Pane,我打算在其中显示我的六边形。

我的Main 类已定义:

public class Main extends Application {
@Override
public void start(Stage stage) {
    try {

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("/Display.fxml"));
        Parent root = loader.load();

        Scene scene = new Scene(root);    
        stage.setTitle("Grid Display");
        stage.setScene(scene);
        stage.show();

    } catch(Exception e) {
        e.printStackTrace();
    }
}

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

}

我的 FXML 类已定义:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>

<AnchorPane xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ScreenController">
   <children>
      <BorderPane layoutX="-8.0" layoutY="-69.0" prefHeight="297.0" prefWidth="610.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <center>
            <Pane fx:id="nodePane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
         </center>
      </BorderPane>
   </children>
</AnchorPane>

最后,定义了我的控制器类ScreenController

public class ScreenController {

@FXML
private Pane nodePane;

@FXML
protected void initialize() {
    Grid grid = new Grid(new HexScreen(HexOrientation.POINT_TOP_ORIENTATION, new Point (10,10)), new HexMap(MapShape.HEXAGON));

    for(Tile tile : grid.getMap().getMap()) {
        int i = 0;
        Double[] points = new Double[12];
        Point[] corners = grid.getScreen().polygonCorners(tile);
        for(Point point : corners) {
            points[i] = point.getX();
            points[i+1] = point.getY();
            i += 2;
        }
        Polygon polygon = drawTile(points);
        if (tile.getX() == 0 && tile.getY() == 0) {
            polygon.setFill(Color.BLACK);
        }

        this.nodePane.getChildren().add(polygon);
    }
}

private Polygon drawTile(Double[] points) {

    Polygon polygon = new Polygon();
    polygon.getPoints().addAll(points);
    polygon.setStroke(Color.BLACK);
    polygon.setFill(Color.TRANSPARENT);
    return polygon;
}   

}

这个的输出是:

如何将nodePane 的原点设置在Pane 的中心而不是左上角?我宁愿不通过tileToPixel() 重新计算像素坐标,因为此函数位于我作为JAR 导入到实际JavaFX 显示发生的GridDisplay 项目中的项目中。我打算能够将该 JAR 用作独立于我如何构建 GUI 的库,因此需要“通用”平铺到像素计算,而不是 JavaFX 特定的(如果有意义的话)。

因此,我认为最适合更改像素坐标的地方是ScreenController。到目前为止,我已经尝试过:

        for(Tile tile : grid.getMap().getMap()) {
        int i = 0;
        Double[] points = new Double[12];
        Point[] corners = grid.getScreen().polygonCorners(tile);
        for(Point point : corners) {
            points[i] = point.getX();
            points[i+1] = point.getY();
            i += 2;
        }
        Polygon polygon = drawTile(points);
        if (tile.getX() == 0 && tile.getY() == 0) {
            polygon.setFill(Color.BLACK);
        }

        polygon.setTranslateX(nodePane.getWidth()/2);
        polygon.setTranslateY(nodePane.getHeight()/2);

        this.nodePane.getChildren().add(polygon);
    }

这个输出看起来和上图一模一样。我还将nodePane.getWidth()nodePane.getHeight() 替换为:

    polygon.setTranslateX(nodePane.getPrefWidth()/2);
    polygon.setTranslateY(nodePane.getPrefHeight()/2);

这会稍微移动原点,但不会像我想象的那样移动。作为参考,我的AnchorPaneBorderPanePanePrefWidthPrefHeight 都设置为USE_COMPUTED_SIZE

最后,即使上面的解决方案将我的原点集中在Pane 的中心,我不相信如果用户调整窗口大小它会起作用。

感谢您阅读我的长篇文章,如果您需要任何其他信息,请告诉我。

【问题讨论】:

  • 如果您将nodePane 放在StackPane 中,它可能会起作用。

标签: javafx


【解决方案1】:

@Sedrick 感谢您的帮助。

这是我的解决方案。

public class ScreenController {

@FXML
private StackPane nodePane;

@FXML
protected void initialize() {
    Grid grid = new Grid(new HexScreen(HexOrientation.POINT_TOP_ORIENTATION, new Point (10,10)), new HexMap(MapShape.HEXAGON));
    Group group = new Group();
    for(Tile tile : grid.getMap().getMap()) {
        int i = 0;
        Double[] points = new Double[12];
        Point[] corners = grid.getScreen().polygonCorners(tile);
        for(Point point : corners) {
            points[i] = point.getX();
            points[i+1] = point.getY();
            i += 2;
        }
        Polygon polygon = drawTile(points);
        if (tile.getX() == 0 && tile.getY() == 0) {
            polygon.setFill(Color.BLACK);
        }
        group.getChildren().add(polygon);
    }
    this.nodePane.getChildren().add(group);
}

private Polygon drawTile(Double[] points) {

    Polygon polygon = new Polygon();
    polygon.getPoints().addAll(points);
    polygon.setStroke(Color.BLACK);
    polygon.setFill(Color.TRANSPARENT);
    //tileHandler.hoverHandler(polygon, Color.TRANSPARENT, Color.RED);
    return polygon;
}   

}

我首先将所有多边形(十六进制)放入Group 对象中。然后按照上面的建议将Group 添加到StackPane(而不是Pane)。如果我使用Pane 而不是Group,则此解决方案不起作用。这是结果输出:

我仍然需要在 X 轴上镜像网格(因为 -Y 仍然向上),并且最好允许通过调整窗口大小来动态调整网格大小,以便始终显示完整的网格。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    • 2021-06-05
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    相关资源
    最近更新 更多