我正在尝试使用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?
答案 0 :(得分:4)
你应该从不让你的主要Application类成为一个控制器 - 它太混乱了,并且充满了你遇到过的错误。
当您加载Main.fxml时,FXMLLoader将创建Application类的新实例。当您单击主fxml UI中定义的按钮时,将在该新TestMain对象上调用doSomething方法,而不是在启动应用程序时创建的原始TestMain对象。
解决方案是创建一个MainController.java,它充当Main.fxml GUI的控制器(类似于您已经使用PetListGUIManager完成的操作),并从主应用程序类中完全删除任何与@FXML相关的表示法。