簡體   English   中英

如何在Java FX FXML應用程序中的Model和View之間進行通信?

[英]How to communicate between the Model and View in a Java FX FXML application?

免責聲明:我對JavaFX和模型 - 視圖 - 控制器設計原則非常陌生。

這是我的基本情況:

我有一個類似於教程中概述的ScreenManager。 使用屏幕管理器,我使用屏幕按鈕上的基本操作處理在幾個FXML屏幕之間切換。

問題是其中一個是帶有地圖的游戲屏幕。 我將在這個游戲畫面上繪制一個基於圖塊的地圖,所以我在我的FXML文件中使用了TilePane(如果有更好的方法將圖塊繪制到屏幕區域,請告訴我)。

這是我創建要繪制到游戲屏幕的TilePane的代碼:

public TilePane createRandomMap(boolean centeredRiver)
{

    Image atlas = new Image("resources/textures/tile_atlas.jpg");
    Random rand = new Random();
    int riverPos = 4, 
        tileHeight = (int)atlas.getHeight()/2, 
        tileWidth = (int)atlas.getWidth()/3;
    if(!centeredRiver)
        riverPos = rand.nextInt(10);
    for(int i = 0; i < 5; i++)
    {
        for(int j = 0; j < riverPos; j++)
        {
            int type = rand.nextInt(4);
            Tile tile = new Tile(tileTypes[type], i, j);
            tile.setImage(atlas);
            tile.setViewport(new Rectangle2D((type%3)*tileWidth, //minX
                    tileHeight-(type/3)*tileHeight, //minY
                    tileWidth, tileHeight)); // width, height
            tile.setFitHeight(tilePane.getHeight()/5); //fit to the size of the pane
            tile.setFitWidth(tilePane.getWidth()/9); //fit to the size of the pane
            tile.setPreserveRatio(true);
            tilesToAdd.add(tile); 
        }
        if(i == 2)
        {
            Tile tile = new Tile(tileTypes[5], i, riverPos);
            tile.setImage(atlas);
            tile.setViewport(new Rectangle2D(2*tileWidth, 0, 
                    tileWidth, tileHeight));
            tile.setFitHeight(tilePane.getHeight()/5);
            tile.setFitWidth(tilePane.getWidth()/9);
            tile.setPreserveRatio(true);
            tilesToAdd.add(tile);
        }
        else
        {
            Tile tile = new Tile(tileTypes[4], i, riverPos);
            tile.setImage(atlas);
            tile.setViewport(new Rectangle2D(tileWidth, 0, 
                    tileWidth, tileHeight));
            tile.setFitHeight(tilePane.getHeight()/5);
            tile.setFitWidth(tilePane.getWidth()/9);
            tile.setPreserveRatio(true);
            tilesToAdd.add(tile);
        }
        for(int j = riverPos + 1; j<9; j++)
        {
            int type = rand.nextInt(4);
            Tile tile = new Tile(tileTypes[type], i, j);
            tile.setImage(atlas);
            tile.setViewport(new Rectangle2D((type%3)*tileWidth, //minX
                    tileHeight-(type/3)*tileHeight, //minY
                    tileWidth, tileHeight)); // width, height
            tile.setFitHeight(tilePane.getHeight()/5); //fit to the size of the pane
            tile.setFitWidth(tilePane.getWidth()/9); //fit to the size of the pane
            tile.setPreserveRatio(true);
            tilesToAdd.add(tile); 
        }
    }
    tilePane.getChildren().addAll(tilesToAdd);

    return tilePane;
}

我已經能夠在我的控制器類中訪問此TilePane:

public class GameScreenController implements Initializable, ControlledScreen {

ScreenManager screenManager;

@FXML
TilePane mapPane

/**
 * Initializes the controller class.
 */
@Override
public void initialize(URL url, ResourceBundle rb) {
    TileEngine engine = new TileEngine();
    mapPane = engine.createRandomMap(true);
}    

在上面的例子中,我將在我的FXML屏幕中定義的TilePane設置為我在模型中創建的TilePane,但是我收到以下錯誤:

Can not set javafx.scene.layout.TilePane field
screens.gameScreen.GameScreenController.mapPane to 
javafx.scene.layout.AnchorPane

這是我處理TilePane的FXML文件的一部分:

<TilePane id="MapPane" fx:id="mapPane" layoutX="0.0" layoutY="0.0" prefColumns="9" prefHeight="560.0" prefTileHeight="112.0" prefTileWidth="112.0" prefWidth="1108.0" visible="true" />

我真的很難圍繞JavaFX和游戲設計,但非常想學習。 我很樂意澄清並批評這個結構的任何部分,以使其更好,即使是與我所問的問題無關的事情。

先感謝您!

MVC

嚴格來說,JavaFX不支持MVC(無論發明者自己都宣稱死了),但某種MVVM(Model-View-ViewModel)

模型與控制器之間的通信

我通常使用依賴注入來執行此操作。 如果你想要一個簡單的FrameWork,我可以建議你使用afterburner.fx或Google Guice。 兩個非常輕量級的框架,你做你想要的。 基本上,他們可以為您處理類的實例化,並確保是否只需要模型的一個實例是活動的。

一些示例代碼:

public class Presenter {
    // Injects
    @Inject private StateModel stateModel;
}

無需聲明構造函數或任何東西。 如果你需要,你需要更多的工作來測試它,但總的來說我不想再次錯過這個功能,因為通常你只需要一個StateModel ,其中所有的信息都來自它,所有的視圖只是聽它們或者改變它們。

讓我們舉一個例子來擴展到已發布的代碼

@Singleton
public class StateModel {
    // Properties
    private final StringProperty name = new SimpleStringProperty();

    // Property Getter
    public StringProperty nameProperty() { return this.name; }
}

如果我們現在在Presenter / Controller中聲明了一個標簽,我們可以像這樣聽取模型中的變化

public class Presenter implements Initializable {
    // Nodes
    @FXML private Label nodeLabelName;

    // Injects
    @Inject private StateModel stateModel;

    @Override
    public void initialize(URL location, ResourceBundle resource) {
        this.nodeLabelName.textProperty().bind(this.stateModel.nameProperty());
    }
}

我可以給你的另一個建議是Threading 您通常希望您的業務邏輯在另一個線程中執行,否則您的Application-Thread將在處理時開始滯后

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM