Java FX使用多个FXML文件获取自定义控件

时间:2014-01-22 14:38:29

标签: javafx custom-controls fxml

我正在尝试使用JavaFX中的自定义控件和多个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:Children:子节点为null:parent = FlowPane [ ID = mainPane]

我在这里缺少什么?

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

1 个答案:

答案 0 :(得分:4)

你应该从不让你的主要Application类成为一个控制器 - 它太混乱了,并且充满了你遇到过的错误。

当您加载Main.fxml时,FXMLLoader将创建Application类的新实例。当您单击主fxml UI中定义的按钮时,将在该新TestMain对象上调用doSomething方法,而不是在启动应用程序时创建的原始TestMain对象。

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