【问题标题】:JavaFX (partially) hide image outside gridpaneJavaFX(部分)隐藏网格外的图像
【发布时间】:2019-01-08 06:32:27
【问题描述】:

基本上我有这个布局:Image of the GUI layout。 它是一个带有菜单栏(红色)的 BorderPane(黑色)、一个在左侧边栏中(绿色)的容器(里面有一些东西)和一个嵌套在中心(橙色)内的 GridPane(灰色)

GridPane 的单元格填充有可能会消失的 ImageView(蓝色),当重新填充时,它们可能会堆叠,通过平行过渡从顶部落入它们的位置。到目前为止一切顺利,但我想隐藏 GridPane 和菜单栏之间的图像部分,但无法让它工作。有人知道如何解决这个问题吗?我也不介意隐藏整个图片而只有一部分突出。

//编辑:

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

【问题讨论】:

  • 您是否使用 .fxml 作为用户界面?您能否提供一个实际图像也直接用 Image 等显示问题,我的意思是带有 MenuBar、GridPane 等的真实图像...谢谢:)
  • 我编辑了帖子,如果您需要更多信息,请告诉我 :) 问题只是目前从上方进入的石头的一小部分。
  • 一种方法是利用 JavaFx 中的图层 - 在网格的所有四个边上放置一个不透明的边界,在网格所在的图层“上方”...
  • 现在我明白了,GridPane 是否有通过 fxml 设置的边距或填充?我可以看到 fxml 文件吗?我当然可以解决你的问题:) 顺便说一句,不错的游戏!!!

标签: java javafx imageview transition gridpane


【解决方案1】:

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

}

结果

【讨论】:

  • 太棒了,这就像一个魅力!我刚刚添加了 clipChildren 函数并在创建我的 gui 对象时调用它。另外,解释得很好:)
【解决方案2】:

以下是 JKostikiadis 解决方案的简短版本,它使用了绑定:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-16
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多