JavaFX:按下按钮后,游戏场景不会更新

时间:2018-01-21 15:42:09

标签: java events model-view-controller javafx event-handling

我有MainCellDisplayer个类。 Main创建一个Cell[][]网格,将其传递给构建Displayer的{​​{1}}并返回游戏Pane

我有一个Scene按钮,可以调用deleteCells类中的deleteCells方法。但是,在我按下它之后,Main没有更新,即使Scene输出证明方法已执行:

细胞

System.out.println

主要

public class Cell {
    private boolean status;

    public Cell()  {
        System.out.println("DEAD CELL CREATED");

        status = false;
    }

    public boolean getStatus()  {
            return status;
    }

    public void setStatus(boolean status)  {
        this.status = status;
    }

}

显示仪

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.util.Random;

public class Main extends Application {
    private static int  gameWidth= 800;
    private static int gameHeight=600;

    private static int gridSize = 20;
    private static Cell[][] grid = new Cell[gridSize][gridSize];

    private static Scene scene;
    private static Displayer gameDisplayer;    

    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("Advanced Game of Life");

        createGrid();

        gameDisplayer = new Displayer(gameWidth, gameHeight, grid);

        scene = gameDisplayer.getGameScene();
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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

    private static void createGrid()  {
        for (int i=0; i<gridSize; i++)  {
            for (int j=0; j<gridSize; j++)
                grid[i][j] = new Cell();
        }
    }

    public static void deleteCells()  {
        for (int i=0; i<gridSize; i++)  {
            for (int j=0; j<gridSize; j++) {
                grid[i][j].setStatus(false);
            }
        }

        //scene = gameDisplayer.getGameScene();  //this doesn't work
    }

    public static void createCell()  {
        Random rand = new Random();
    }
}

有没有办法让import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; public class Displayer implements EventHandler<ActionEvent> { private static Color ALIVE_COLOR=Color.GREEN; private static Color DEAD_COLOR=Color.SILVER;; private static BorderPane gamePane; private static Pane cellsPane; private HBox buttonsPane; private Pane statsPane; private Pane setupsPane; private HBox bottomPane; Button createCellButton; Button deleteCellsButton; Label cellsCountLabel; Label setupsLabel; private int gameWidth; private int gameHeight; static int gridSize = 20; static int cellId = 1; private Cell[][] gameGrid; private Scene gameScene; public Displayer(int width, int height, Cell[][] grid) { gameWidth = width; gameHeight = height; gameGrid=grid; createPanes(); createButtons(); createLabels(); setPaneStyles(); setButtonsStyles(); setLabelsStyles(); gameScene = new Scene(gamePane, gameWidth, gameHeight); } public Scene getGameScene() { return gameScene; } private void createPanes() { gamePane = new BorderPane(); buttonsPane = new HBox(5); statsPane = new Pane(); cellsPane = makeGridPane(gameGrid); setupsPane = new Pane(); bottomPane = new HBox(5); } private void createButtons() { createCellButton = new Button(); deleteCellsButton = new Button(); } private void createLabels() { cellsCountLabel = new Label("Cells Count: " + (cellId + 1)); setupsLabel = new Label("Setups Label"); } private void setPaneStyles() {...} private void setButtonsStyles() {...} private void setLabelsStyles() {...} public void handle(ActionEvent event) { if (event.getSource()==createCellButton) { //Main.createCell(); } else if (event.getSource() == deleteCellsButton) { Main.deleteCells(); cellsCountLabel.setText("Cells Count: " + (cellId + 1)); System.out.println("Cells deleted"); } else { System.out.println("Unknown button"); } } public Pane makeGridPane(Cell[][] grid) { Pane gridPane = new Pane(); for(int i=0; i<gridSize; i++){ for(int j=0; j<gridSize; j++){ Rectangle rect = new Rectangle(); System.out.println("grid[" + i + "][" + j +"]"); if (grid[i][j].getStatus()) { rect.setFill(ALIVE_COLOR); } else { rect.setFill(DEAD_COLOR); } rect.setStroke(Color.BLACK); rect.setX(i * gridSize); rect.setY(j * gridSize); rect.setWidth(gridSize); rect.setHeight(gridSize); rect.setOnMouseClicked(new EventHandler<MouseEvent>(){ @Override public void handle(MouseEvent me){ rect.setFill(Color.RED); } }); gridPane.getChildren().add(rect); } } return gridPane; } } 更新自己,即使它是在Scene内构建的,按钮调用Displayer类中的方法?我尝试在Main方法中添加scene = gameDisplayer.getGameScene();,但它并没有改变这种情况。我应该如何根据MVC处理用户的输入,以便deleteCells()响应更改,因为所有GUI元素都位于单独的类Scene中?

修改

Displayer添加了editGrid()方法:

Main

public static void editGrid(int x, int y, boolean status) { grid[x][y].setStatus(status); } 内更新了setOnMouseClicked

Displayer

1 个答案:

答案 0 :(得分:1)

在传统的MVC中,模型是“可观察的”,在某种意义上,观察者可以注册接收数据变化的通知。视图(或控制器,取决于您使用的MVC模式的变体)观察模型中的数据,并在数据更改时相应地更新UI组件。

通过定义properties and binding API,JavaFX可以很容易地做到这一点。这些属性类是可直接观察的,在更改时向ChangeListener发送事件,绑定API允许您表达变量之间的依赖关系。 UI组件本身是使用这些属性编写的。

因此,您可以将模型实现为

public class Cell {
    private final BooleanProperty status;

    public Cell()  {
        System.out.println("DEAD CELL CREATED");

        status = new SimpleBooleanProperty(false);
    }

    public BooleanProperty statusProperty() {
        return status ;
    }

    public final boolean getStatus()  {
            return statusProperty().get();
    }

    public final void setStatus(boolean status)  {
        statusProperty().set(status);
    }

}

然后,当相应单元格的状态发生变化时,您需要做的就是更新矩形的颜色:

public Pane makeGridPane(Cell[][] grid) {
    Pane gridPane = new Pane();

    for(int i=0; i<gridSize; i++){
        for(int j=0; j<gridSize; j++){
            Rectangle rect = new Rectangle();

            System.out.println("grid[" + i + "][" + j +"]");

            if (grid[i][j].getStatus()) {
                rect.setFill(ALIVE_COLOR);
            } else {
                rect.setFill(DEAD_COLOR);
            }

            grid[i][j].statusProperty().addListener((obs, oldStatus, newStatus) -> {
                if (newStatus) {
                    rect.setFill(ALIVE_COLOR);
                } else {
                    rect.setFill(DEAD_COLOR);
                }
            });

            rect.setStroke(Color.BLACK);

            rect.setX(i * gridSize);
            rect.setY(j * gridSize);
            rect.setWidth(gridSize);
            rect.setHeight(gridSize);


            rect.setOnMouseClicked(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent me){
                        rect.setFill(Color.RED);
                }
            });

            gridPane.getChildren().add(rect);


        }
    }

    return gridPane;
}