java - 如何在 Java FX FXML 应用程序中的模型和 View 之间进行通信?

标签 java model-view-controller javafx-2 fxml

免责声明:我对 JavaFX 和模型- View - Controller 设计原则非常不熟悉。

这是我的基本情况:

我有一个类似于 this 中概述的 ScreenManager教程。使用屏幕管理器,我使用屏幕按钮上的基本操作处理在多个 FXML 屏幕之间切换。

问题是其中一个是带有 map 的游戏画面。我将在这个游戏屏幕上绘制基于图 block 的 map ,因此我在我的 FXML 文件中使用了 TilePane(如果有更好的方法将图 block 绘制到屏幕区域,请告诉我)。

这是我创建要绘制到游戏屏幕的 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;
}

我已经能够在我的 Controller 类中访问这个 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

这是我的 FXML 文件中处理 TilePane 的部分:

<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(模型- View - View 模型)

模型和 Controller 之间的通信

我通常使用依赖注入(inject)来做到这一点。如果你想要一个简单的框架,我可以建议你 afterburner.fx或谷歌指南。两个非常轻量级的框架都可以做你想做的事。基本上,他们可以为您处理类的实例化,并确保如果需要,您的模型只有一个实例处于 Activity 状态。

一些示例代码:

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

我可以给你的另一个建议是线程。您通常希望您的业务逻辑在另一个线程中执行,否则您的应用程序线程在处理时会开始滞后

关于java - 如何在 Java FX FXML 应用程序中的模型和 View 之间进行通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19484914/

相关文章:

java - 将查询结果打印到jsp表 Java Spring MVC jsp

java - JFreeChart 未更新

JavaFX 2 - JPedal 包含在 Pane 中

JavaFX FileChooser : how to set file filters?

java - 如何从 Android 应用程序访问 Oracle 数据库。

java - 设备上的 Lollipop 更新后 Android GCM 无法工作

java - 期间.仅减去天数

java - 无法从 exec Java 方法运行 linux 命令

javascript - 在 MVC 项目中实现 autoNumeric v4

JavaFX 组合框样式按钮(如果可编辑)