如果您检查 GridPane 的 JavaDoc,您将看到:
默认情况下,GridPane 不会裁剪其内容,因此如果子项的最小尺寸使其无法适应其空间,则子项的边界可能会超出其自身的边界。
对于Pane 班级的每个孩子也是如此。因此,您将需要手动处理剪辑,为此可以使用 setClip() 方法。
实现它的一种简单方法是使用带有窗格尺寸的Rectangle 进行剪切。下面有一个代码可以做到这一点:
public void clipChildren(Region region) {
final Rectangle clipPane = new Rectangle();
region.setClip(clipPane);
region.layoutBoundsProperty().addListener((ov, oldValue, newValue) -> {
clipPane.setWidth(newValue.getWidth());
clipPane.setHeight(newValue.getHeight());
});
}
说实话,我也没有意识到这一点。您可以阅读一篇很棒的文章,其中详细解释了所有内容:JavaFX Pane Clipping
在我给你一个完整的例子之前,我想建议你使用Pane 而不是GridPane。主要原因是您可以更好地操作(单击、拖动等)您的控件。另外,一些免责声明,我不是游戏开发者,所以下面的示例只是一个示例。
MainApp.java
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class MainApp extends Application {
@Override
public void start(Stage stage) throws Exception {
GameBoard gameBoard = new GameBoard();
BorderPane mainPane = new BorderPane();
Button restartButton = new Button("Restart");
restartButton.setOnAction(e -> {
gameBoard.restartGame();
});
FlowPane controlPane = new FlowPane();
controlPane.setAlignment(Pos.CENTER);
controlPane.getChildren().add(restartButton);
mainPane.setCenter(gameBoard);
mainPane.setBottom(controlPane);
stage.setScene(new Scene(mainPane, 600, 600));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
GameBoard.java
import java.util.ArrayList;
import java.util.Random;
import javafx.animation.ParallelTransition;
import javafx.animation.RotateTransition;
import javafx.animation.TranslateTransition;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
public class GameBoard extends StackPane {
private final int TILE_WIDTH = 60;
private final int TILE_HEIGHT = 60;
private final int WIDTH;
private final int HEIGHT;
private int rows;
private int columns;
private ArrayList<Image> tileImages = new ArrayList<Image>();
private final Pane gamePane = new Pane();
public GameBoard() {
this(9, 9);
}
public GameBoard(int rows, int columns) {
this.rows = rows;
this.columns = columns;
WIDTH = columns * TILE_WIDTH;
HEIGHT = rows * TILE_HEIGHT;
// set the Clipping
clipChildren(gamePane);
// set the background color and also fix the dimensions
gamePane.setStyle("-fx-background-color : #52033D");
gamePane.setMinSize(WIDTH, HEIGHT);
gamePane.setPrefSize(WIDTH, HEIGHT);
gamePane.setMaxSize(WIDTH, HEIGHT);
getChildren().add(gamePane);
initTilesImages();
fillTiles();
}
public void clipChildren(Region region) {
final Rectangle clipPane = new Rectangle();
region.setClip(clipPane);
// In case we want to make a resizable pane we need to update
// our clipPane dimensions
region.layoutBoundsProperty().addListener((ov, oldValue, newValue) -> {
clipPane.setWidth(newValue.getWidth());
clipPane.setHeight(newValue.getHeight());
});
}
public void restartGame() {
gamePane.getChildren().clear();
fillTiles();
}
private void initTilesImages() {
tileImages.add(new Image(this.getClass().getResource("/resources/redTile.png").toExternalForm()));
tileImages.add(new Image(this.getClass().getResource("/resources/greenTile.png").toExternalForm()));
tileImages.add(new Image(this.getClass().getResource("/resources/blueTile.png").toExternalForm()));
tileImages.add(new Image(this.getClass().getResource("/resources/purpleTile.png").toExternalForm()));
tileImages.add(new Image(this.getClass().getResource("/resources/whiteTile.png").toExternalForm()));
tileImages.add(new Image(this.getClass().getResource("/resources/yellowTile.png").toExternalForm()));
}
// Fill with random images
private void fillTiles() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
ImageView tile = createTile(j, i);
gamePane.getChildren().add(tile);
}
}
}
// Create the ImageView which I call "tile"
private ImageView createTile(int x, int y) {
Random rand = new Random();
int index = rand.nextInt(tileImages.size());
ImageView img = new ImageView(tileImages.get(index));
img.setFitWidth(TILE_WIDTH);
img.setFitHeight(TILE_HEIGHT);
img.setTranslateX(x * TILE_WIDTH);
// set some rotation and transition
RotateTransition rt = new RotateTransition(Duration.millis(2000));
rt.setFromAngle(0);
rt.setToAngle(360);
TranslateTransition tt = new TranslateTransition(Duration.millis(2000));
tt.setFromY(TILE_HEIGHT * (y - rows));
tt.setToY(y * TILE_HEIGHT);
tt.play();
ParallelTransition pt = new ParallelTransition(img, tt, rt);
pt.play();
return img;
}
}
结果: