JavaFX imageview actions

*爱你&永不变心* 提交于 2019-12-24 20:48:57

问题


I'm trying to build a replica of MineSweeper, to do this I'm trying to setup some premade images (100x100 pixels made in Photoshop) into an imageview and then when clicked hiding it (to reveal the number below). Without much complexity -- Just the image going visible and invisible I am finding a lot of issues and difficulties.

It is likely due to a complete lack of knowledge on Javafx in general but I even following tutorials to the t I am still unable to implement this feature. I will attach to this my Main.Java code, my sample.fxml code (although it's not called anymore), and then the image I'm trying to hide when clicked.

I have done a lot of research on this (past couple of days) and haven't found anything that solves my problems.

Main.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);
    }
}

sample.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>

The "Button" that will be used for all the MineSweeper keys

My singular goal at this given moment is to create a window of any size where I can put the button anywhere and then when the user clicks that button it disappears.


回答1:


One possible solution is to create your own ImageView that holds the code for mouse clicks within.

Here's a sample TileButton class:

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);
        });
    }
}

Using this custom class, all the logic for the "button" is contained within the TileButton itself.

Now, you can populate your mine field with a GridPane of StackPane containers in each cell. The StackPane allows you to stack nodes on top of each other. So, place a Label with the number you want into each StackPane and then add your new TileButton on top of it.

Below is a complete sample application to demonstrate. Note, I am not implementing any of the actual game logic here, just providing a sample you can copy/paste and see in action. I also have not spent any time formatting and styling the ImageView, but your could use CSS to make it act like a standard button as well.

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);
        });
    }
}

The above sample application produces this:

Note I am not using FXML for this as creating a grid of multiple custom objects is much simpler in Java than FXML.


Per kleopatra's suggestion, this can be accomplished using a custom Button instead. With the new TileButton class below, you can add the buttons in our loop using 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));
        });

    }
}


来源:https://stackoverflow.com/questions/52229984/javafx-imageview-actions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!