Javafx(部分)将图像隐藏在网格窗格之外

时间:2018-07-31 19:16:32

标签: java javafx imageview transition gridpane

基本上我有以下布局:Image of the GUI layout 这是一个BorderBane(黑色),带有一个菜单栏(红色),一个包含一些东西的容器,在左侧边栏(绿色)和一个嵌套在中心(橙色)内部的GridPane(灰色)

网格窗格的单元格充满了可以消失的图像视图(蓝色),重新填充后,它们可能堆叠在一起,通过平行转换从顶部掉入其位置。到目前为止,一切都很好,但是我想在网格窗格和菜单栏之间隐藏图像的一部分,但无法使其正常工作。有人知道如何解决这个问题吗?我也不会介意仅在部分内容突出时隐藏整个图片。

//编辑:

Image of the actual game 主布局是使用fxml文件创建的。启动后,图像视图已添加到网格窗格中。

2 个答案:

答案 0 :(得分:2)

如果检查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;
}

}

结果

enter image description here

答案 1 :(得分:0)

这是JKostikiadis使用绑定的解决方案的简化版本:

private void clipChildren(Region region) {
    Rectangle clip = new Rectangle();
    clip.widthProperty().bind(region.widthProperty());
    clip.heightProperty().bind(region.heightProperty());
    region.setClip(clip);
}