Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在JavaFXML应用程序中的模型和视图之间进行通信?_Java_Model View Controller_Javafx 2_Fxml - Fatal编程技术网

如何在JavaFXML应用程序中的模型和视图之间进行通信?

如何在JavaFXML应用程序中的模型和视图之间进行通信?,java,model-view-controller,javafx-2,fxml,Java,Model View Controller,Javafx 2,Fxml,免责声明:我对JavaFX和模型-视图-控制器设计原则非常陌生 以下是我的基本情况: 我有一个屏幕管理器类似于教程中概述的屏幕管理器。使用屏幕管理器,我使用屏幕按钮上的基本操作处理在几个FXML屏幕之间切换 问题是其中一个是带有地图的游戏屏幕。我将在这个游戏屏幕上绘制一个基于瓷砖的地图,所以我在我的FXML文件中使用了一个瓷砖面板(如果有更好的方法在屏幕的某个区域绘制瓷砖,请让我知道) 下面是我创建要绘制到游戏屏幕的TilePane的代码: public TilePane createRando

免责声明:我对JavaFX和模型-视图-控制器设计原则非常陌生

以下是我的基本情况:

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

问题是其中一个是带有地图的游戏屏幕。我将在这个游戏屏幕上绘制一个基于瓷砖的地图,所以我在我的FXML文件中使用了一个瓷砖面板(如果有更好的方法在屏幕的某个区域绘制瓷砖,请让我知道)

下面是我创建要绘制到游戏屏幕的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;
}
在上面的实例中,我将在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(Model-View-ViewModel)

模型和控制器之间的通信

我通常使用依赖注入来实现这一点。如果你想要一个简单的框架,我可以建议你或谷歌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());
    }
}

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

根据错误消息,您似乎正在尝试将字段映射窗格(即TilePane)分配给AnchorPane类型的字段。这感觉类似于类强制转换异常。如果您发布了FXML文件以确定发生了什么,这将非常有用。@axiopisty感谢您的快速回复。我已经添加了FXML文件中处理特定TilePane的部分。我不理解createRandomMap(…)的用途。它使用像tilePane这样的内部属性并返回它,但它似乎是一个工厂,这个函数位于哪里?试着给出一个任何人都可以运行的独立示例。没有足够的数据进行调试。
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());
    }
}