首页 > 解决方案 > JavaFX 图像视图操作

问题描述

我正在尝试构建 MineSweeper 的副本,为此我尝试将一些预制图像(在 Photoshop 中制作的 100x100 像素)设置到图像视图中,然后单击隐藏它(以显示下面的数字)。没有太多复杂性——只是图像变得可见和不可见,我发现了很多问题和困难。

这可能是由于完全缺乏对 Javafx 的一般知识,但我什至按照教程进行操作,我仍然无法实现此功能。我将附上我的 Main.Java 代码、我的sample.fxml代码(虽然它不再被调用),然后是我试图在单击时隐藏的图像。

我对此(过去几天)进行了大量研究,但没有找到任何可以解决我问题的方法。

主.java:

package sample;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    ImageView button;
    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("MineSweeper XP");
        button = new ImageView();

        button.setOnMouseClicked(new EventHandler<MouseEvent>)(){

            public void handle(MouseEvent event){

            }
        }

        StackPane layout = new StackPane();
        layout.getChildren().add(button);

        Scene scene = new Scene(layout,1000, 1000);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

示例.fxml:

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

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="100.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <ImageView fx:id="button" fitHeight="150.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true">
         <image>
            <Image url="@../textures/Button_Custom.png" />
         </image>
      </ImageView>
   </children>
</AnchorPane>

将用于所有 MineSweeper 键的“按钮”

在这个特定时刻,我的唯一目标是创建一个任意大小的窗口,我可以在其中将按钮放在任何地方,然后当用户单击该按钮时它就会消失。

标签: javafximageview

解决方案


一种可能的解决方案是创建自己的解决方案ImageView,其中包含用于鼠标点击的代码。

这是一个示例TileButton类:

class TileButton extends ImageView {

    public TileButton() {

        // Set parameters for the image
        Image graphic = new Image("minesweeper/tile.png");
        setImage(graphic);
        setFitWidth(24);
        setFitHeight(24);

        // When this button is click, set its visibility to false.
        setOnMouseClicked(e -> {
            setVisible(false);
        });
    }
}

使用这个自定义类,“按钮”的所有逻辑都包含在其TileButton自身中。

GridPane现在,您可以在每个单元格中使用一个StackPane容器填充您的雷区。允许您将StackPane节点堆叠在一起。因此,Label在每个中放置一个带有您想要的数字的数字StackPane,然后TileButton在其上添加您的新数字。

下面是一个完整的示例应用程序来演示。请注意,我在这里没有实现任何实际的游戏逻辑,只是提供一个示例,您可以复制/粘贴并查看实际操作。我也没有花任何时间格式化和样式化ImageView,但您也可以使用 CSS 使其像标准按钮一样。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

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

    @Override
    public void start(Stage primaryStage) {

        VBox root = new VBox(5);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        // GridPane to hold the cells
        GridPane gridPane = new GridPane();
        gridPane.setGridLinesVisible(true);
        gridPane.setHgap(2);
        gridPane.setVgap(2);

        // Populate the Gridpane with a 10x10 grid
        int number = 0;
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {

                // Add a new StackPane for each grid cell. The Stackpane will hold a number and the
                // TileButton. When the TileButton is clicked, it disappears, revealing the number below
                StackPane pane = new StackPane();
                pane.getChildren().add(new Label(String.valueOf(number)));
                pane.getChildren().add(new TileButton());

                gridPane.add(pane, j, i);

                // Just increment our sample number
                number++;

            }
        }

        root.getChildren().add(gridPane);
        primaryStage.setScene(new Scene(root));

        primaryStage.show();
    }
}

class TileButton extends ImageView {

    public TileButton() {

        // Set parameters for the image
        Image graphic = new Image("minesweeper/tile.png");
        setImage(graphic);
        setFitWidth(24);
        setFitHeight(24);

        // When this button is click, set its visibility to false.
        setOnMouseClicked(e -> {
            setVisible(false);
        });
    }
}

上面的示例应用程序产生了这个:

截屏

注意我没有FXML为此使用,因为在 Java 中创建多个自定义对象的网格比 FXML 简单得多。


根据kleopatra 的建议,这可以使用自定义Button来完成。使用下面的新TileButton类,您可以使用以下方法在我们的循环中添加按钮gridPane.add(new TileButton(String.valueOf(number)), j, i);

class TileButton extends Button {

    public TileButton(String text) {

        // Set the button's size
        setPrefSize(24,24);
        setStyle("-fx-padding: 0");

        // Set the graphic to our tile.png image
        setGraphic(new ImageView("sample/done/minesweeper/tile.png"){{
            setFitWidth(24);
            setFitHeight(24);
        }});

        // Set the button to display only our graphic initially
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        // Set the action to remove the graphic when the button is clicked
        setOnAction(event -> {
            setGraphic(new Label(text));
        });

    }
}

推荐阅读