2013-10-21 13 views
1

声明:我是新的JavaFX和模型 - 视图 - 控制器的设计原则。如何在Java FX FXML应用程序中的模型和视图之间进行通信?

这里是我的基本情况:

我有一个屏幕管理一个类似于在this教程中列出。使用屏幕管理器,我可以在屏幕按钮上使用基本的操作处理在几个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 

这是我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头和游戏设计一般,但非常想了解。我会很乐意澄清和批评这种结构的任何部分,以便使它更好,甚至不涉及我所问的问题。

预先感谢您!

+0

根据错误消息,它看起来像您要分配字段mapPane,它是一个TilePane ,到一个AnchorPane类型的字段。这感觉类似于类抛出的异常。如果您发布FXML文件以确切知道发生了什么,这将会很有帮助。 – axiopisty

+0

@axiopisty感谢您的快速回复。我已经添加了处理特定TilePane的FXML文件段。 –

+0

我不明白createRandomMap(...)的用途。它正在使用像tilePane这样的内部属性并返回它,但它似乎是作为工厂制作的,该函数的位置在哪里?尝试给出一个任何人都可以运行的独立示例。没有足够的数据来调试。 – zenbeni

回答

3

MVC

严格地说JavaFX的不支持MVC(这是死了发明者本人反正声明),但某种MVVM(模型 - 视图 - 视图模型)型号之间

通信和控制器

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

如果我们现在的标签在我们的演示/控制器声明,我们可以听到这样的

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。您通常希望您的业务逻辑能够在另一个线程中执行,否则当您的应用程序线程正在处理时,它将启动滞后

相关问题