[英]JavaFX: game scene doesn't get updated after button click
I have a Main
, Cell
and Displayer
classes. 我有一个
Main
, Cell
和Displayer
类。 Main creates a Cell[][]
grid, passes it to Displayer
that constructs Pane
s and returns a game Scene
. Main创建一个
Cell[][]
网格,将其传递到Displayer
,该Displayer
构造Pane
并返回游戏Scene
。
I have a deleteCells
button that calls deleteCells
method inside Main
class. 我有一个
deleteCells
按钮, deleteCells
在Main
类中调用deleteCells
方法。 However, after I press it, the Scene
doesn't get updated, even though System.out.println
output proves the method was executed: 但是,在按下它之后,即使
System.out.println
输出证明该方法已执行,该Scene
也不会得到更新:
Cell : 单元格 :
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;
}
}
Main : 主要 :
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();
}
}
Displayer : 显示器 :
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;
}
}
Is there way to make the Scene
update itself, even though it is constructed inside Displayer
and the buttons call methods inside Main
class? 即使它是在
Displayer
构造的,并且Button调用了Main
类中的方法,也可以使Scene
更新本身吗? I tried adding scene = gameDisplayer.getGameScene();
我尝试添加
scene = gameDisplayer.getGameScene();
inside deleteCells()
method, but it didn't change the situation. 在
deleteCells()
方法中,但并没有改变情况。 How should I handle user's input, in accordance with MVC, so that the Scene
responded to changes, given all GUI elements are located in a separate class Displayer
? 鉴于所有GUI元素都位于单独的
Displayer
类中,我应该如何按照MVC处理用户的输入,以使Scene
响应更改?
EDIT : 编辑 :
Added a editGrid()
method to Main
: 向
Main
添加了editGrid()
方法:
public static void editGrid(int x, int y, boolean status) {
grid[x][y].setStatus(status);
}
Updated setOnMouseClicked
inside Displayer
: 更新
setOnMouseClicked
内Displayer
:
rect.setOnMouseClicked(new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent me){
Main.editGrid ((int) rect.getX()/gridSize, (int) rect.getY()/gridSize, true);
}
});
In traditional MVC, the model is "observable", in the sense that observers can register to receive notifications of changes to the data. 在传统的MVC中,在观察者可以注册以接收数据更改通知的意义上,该模型是“可观察的”。 The view (or controller, depending on the variant of the MVC pattern you are using) observes the data in the model and updates the UI components accordingly when the data changes.
视图(或控制器,取决于您使用的MVC模式的变体)观察模型中的数据,并在数据更改时相应地更新UI组件。
JavaFX makes it pretty easy to do this by defining a properties and binding API . JavaFX通过定义属性和绑定API使其非常容易。 These properties classes are directly observable, firing events to
ChangeListener
s when they change, and the binding API allows you to express dependencies between variables. 这些属性类是直接可观察到的,在它们发生更改时将事件触发到
ChangeListener
,并且绑定API允许您表达变量之间的依赖关系。 The UI components themselves are written using these properties. UI组件本身是使用这些属性编写的。
So you can implement your model as 因此,您可以将模型实现为
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);
}
}
Then all you need to do is update the color of your rectangles when the corresponding cell's status changes: 然后,您所要做的就是在相应单元格的状态更改时更新矩形的颜色:
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.