2014-01-22 28 views
1

我正尝试使用JavaFX和多个FXML文件中的自定义控件。我创建一个自定义控制:Java FX使用多个FXML文件获得自定义控件的工作

public class PetListGUIManager extends BorderPane 
{ 
    @FXML ListView<String> petList; 

    private PetManager pm; 

    public PetListGUIManager() 
    { 
     try 
     { 
      FXMLLoader loader = new FXMLLoader(getClass().getResource("PetList.fxml")); 

      loader.setRoot(this); 
      loader.setController(this); 

      loader.load(); 

     } 
     catch (IOException e) 
     { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     pm = new PetManager(); 

     ObservableList<String> items = FXCollections.observableArrayList(pm.getDisplayablePets()); 

     petList.setItems(items); 
    } 

    @FXML 
    public void handleButtonAction(ActionEvent event) 
    { 
     Button b = (Button) event.getSource(); 
     b.setText("Clicked!"); 
    } 
} 

使用此FXML文件:

<fx:root type="javafx.scene.layout.BorderPane" xmlns:fx="http://javafx.com/fxml"> 
    <bottom> 
    <Button onAction="#handleButtonAction" text="Click Me!" /> 
    </bottom> 
    <center> 
    <ListView fx:id="petList" prefHeight="200.0" prefWidth="200.0" /> 
    </center> 
</fx:root> 

然后我用这等主要程序:

public class TestMain extends Application 
{ 
    PetListGUIManager pm; 
    @FXML FlowPane mainPane; 

    @Override 
    public void start(Stage stage) throws Exception 
    { 

     Parent root = FXMLLoader 
       .load(getClass().getResource("Main.fxml")); 

     Scene scene = new Scene(root); 

     stage.setTitle("Test Main"); 
     stage.setScene(scene); 
     stage.show(); 


     pm = new PetListGUIManager(); 

    } 
    /** 
    * Purpose: 
    * @param args 
    */ 
    public static void main(String[] args) 
    { 
     Application.launch(args); 
    } 

    @FXML 
    public void doSomething(ActionEvent ae) 
    { 
     System.out.println("In do something: " + mainPane); 
     ObservableList<Node> children = mainPane.getChildren(); 
     System.out.println("Children are " + children); 
     children.add(pm); 

    } 
} 

使用这种FXML文件:

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" fx:controller="TestMain"> 
    <children> 
    <FlowPane fx:id="mainPane" prefHeight="400.0" prefWidth="600.0" > 
    <Button text="Click here to start" onAction="#doSomething"/> 
    </FlowPane> 
    </children> 
</AnchorPane> 

当我点击按钮我在主窗口 - 应加载自定义控件我得到一个java.lang.reflect.InvocationTargetException异常导致:java.lang.NullPointerException:子节点:子节点为null:parent = FlowPane [id = mainPane]

我在这里错过了什么?

第二个问题:您可能会注意到我随意在主窗口中添加了一个按钮,因此当它被点击时,我可以加载我的BorderPane自定义控件类。理想情况下,我想直接在TestMain的start方法中执行此操作,但mainPane在start方法中为null - 它何时变为非null?

+0

如果调试代码,mainPane是否在doSomething()中为null? –

回答

4

你应该从来没有使您的主要应用程序类控制器 - 它只是太混乱和充满错误,如你遇到过。

发生什么事情是,当你加载Main.fxml时,FXMLLoader将创建一个Application类的新实例。当你点击主fxml UI中定义的按钮时,doSomething方法将在新的TestMain对象上被调用,而不是在你的应用程序启动时创建的原始TestMain对象。

解决方案是创建一个MainController.java,该MainController.java作为Main.fxml GUI的控制器(类似于您已经完成的PetListGUIManager),并从您的主应用程序类中完全删除任何@FXML相关表示法。

相关问题