基本上我得到了这个布局:GUI布局的图像。它是一个带有菜单栏(红色)的边框面板(黑色),一个包含一些内容的容器,在左侧边栏(绿色)和嵌套在中心(橙色)内的网格面板(灰色)
GridPane的单元格充满了可以消失的ImageViews(蓝色),当重新填充时,它们可能会通过平行过渡从顶部堆叠到它们的位置。到目前为止还不错,但是我想隐藏GridPane和菜单栏之间的图像部分,但无法使其工作。有人知道如何处理这个吗?我也不介意在只有一部分突出的时候隐藏整个图片。
//编辑:
如果您检查GridPane的JavaDoc,您将看到:
默认情况下,GridPane不会剪切其内容,因此如果子级的最小大小阻止它适合它的空间,则子级的边界可能会扩展到它自己的边界之外。
对于Pane
类的每个子类也是如此。因此,您需要手动处理剪裁,为此需要使用setClip()
方法。实现它的一个简单方法是使用Rectanda
与您的窗格尺寸一起进行剪裁。下面有一个代码,它就是这样做的:
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
而不是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;
}
}
结果:
这是使用绑定的JKostikiadis解决方案的较短版本:
private void clipChildren(Region region) {
Rectangle clip = new Rectangle();
clip.widthProperty().bind(region.widthProperty());
clip.heightProperty().bind(region.heightProperty());
region.setClip(clip);
}