我在Java / JavaFX中制作应用程序时发疯了。
我有一个包含更多fxml文件的项目,每个文件都有一个控制器 (完全像这个例子JavaFX TabPane - One controller for each tab)
这是主要的fxml文件(screentab.fxml
),有多个fx:include
。
<TabPane fx:id="tabPane" BorderPane.alignment="CENTER">
<tabs>
<Tab text="Studenti">
<content>
<fx:include fx:id="Studenti" source="tabStudenti.fxml" />
</content>
</Tab>
<Tab text="Percorsi formativi">
<content>
<fx:include fx:id="tabPercorsiFormativi" source="tabPercorsiFormativi.fxml" />
</content>
</Tab>
<Tab text="Calendario delle lezioni">
<content>
<fx:include fx:id="tabCalendario" source="tabCalendario.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
它有效,但我认为我的模型有问题。
文件Main.java
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Manage your student");
Model model = new Model();
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("gui/screentab.fxml"));
BorderPane root = (BorderPane)loader.load();
SoftwareController controller = loader.getController();
controller.setModel(model);
Scene scene = new Scene(root,1000,600);
scene.getStylesheets().add(getClass().getResource("gui/stylesheet1.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
这是方法SoftwareController.java
;
setModel()
)
public class SoftwareController {
private Model model;
@FXML private TabPane tabPane;
@FXML private tabCalendarioController tabCalendarioController;
@FXML private tabPercorsiFormativiController tabPercorsiFormativiController;
@FXML private tabStudentiController tabStudentiController;
public void setModel(Model model) {
this.model = model;
}
@FXML
void initialize() {
assert tabPane != null : "fx:id=\"tabPane\" was not injected: check your FXML file 'screentab.fxml'.";
tabStudentiController.init(this);
tabCalendarioController.init(this);
tabPercorsiFormativiController.init(this);
}
}
model
调用DAO
并包含从多个控制器调用的所有方法。
public class Model {
StudentiDAO dao = new StudentiDAO();
List<Studente> elencoStudenti = new ArrayList<Studente>();
public List<Studente> elencaStudenti(){
elencoStudenti= dao.listaStudenti();
return elencoStudenti;
}
}
这是调用模型方法的控制器之一。
public class tabStudentiController {
private SoftwareController main;
private Model model;
@FXML
private Button btnElencoStudenti;
@FXML
public void doVisualizzaStudenti(ActionEvent event) {
model.elencaStudenti();
txtStudenti.appendText("Elenco studenti: \n");
for(Studente s: lista ){
txtStudenti.appendText(s.getStud_NOME()+ " "+ s.getStud_COGNOME()+ "\n");
}
}
public void setModel(Model model) {
this.model = model ;
}
public void init(SoftwareController softwareController) {
main = softwareController;
}
@FXML
void initialize() {
assert tabPane != null : "fx:id=\"tabPane\" was not injected: check your FXML file 'screentab.fxml'.";
assert tabStudenti != null : "fx:id=\"tabStudenti\" was not injected: check your FXML file 'screentab.fxml'.";
}
}
问题:
当我按下确实启动事件doVisualizzaStudenti
的按钮时,我有这个错误:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Node.fireEvent(Unknown Source)
at javafx.scene.control.Button.fire(Unknown Source)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(Unknown Source)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
... 57 more
Caused by: java.lang.NullPointerException
at software.tabStudentiController.doVisualizzaStudenti(tabStudentiController.java:36)
... 66 more
其中tabStudentiController.java:36
是model.elencaStudenti()
的行。
我做错了什么? 请帮助我,抱歉我的英语不好!
我使用回调更改了main
,并在每个嵌套控制器中添加了setModel()
。
但现在我有这个错误:
`javafx.fxml.LoadException:
/C:/software/gui/screentab.fxml
at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at software.Main.start(Main.java:43)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
... 13 more
Caused by: java.lang.NullPointerException
at software.SoftwareController.initialize(SoftwareController.java:42)
... 22 more`
其中Main.java:43
是行BorderPane root = (BorderPane)loader.load() and SoftwareController.java:42 is: tabStudentiController.init(this);
我又错了什么?
答案 0 :(得分:0)
我无法在任何地方看到setModel(...)
为#34;嵌套控制器&#34; (例如tabStudentiController
)。由于您从未初始化模型,因此在model.elencaStudenti()
处获得空指针异常。
您可能希望在SoftwareController
上设置模型时初始化每个嵌套控制器的模型:
public class SoftwareController {
private Model model;
@FXML private TabPane tabPane;
@FXML private tabCalendarioController tabCalendarioController;
@FXML private tabPercorsiFormativiController tabPercorsiFormativiController;
@FXML private tabStudentiController tabStudentiController;
public void setModel(Model model) {
this.model = model;
tabStduentiController.setModel(model);
tabCalendarioController.setModel(model);
tabPercorsiFormativiController.setModel(model);
}
@FXML
void initialize() {
assert tabPane != null : "fx:id=\"tabPane\" was not injected: check your FXML file 'screentab.fxml'.";
tabStudentiController.init(this);
tabCalendarioController.init(this);
tabPercorsiFormativiController.init(this);
}
}
另一种方法
也许更简洁的方法是让所有控制器类都将模型引用作为构造函数参数。这样,您可以保证每个控制器在创建时都具有模型实例:
public class SoftwareController {
private Model model;
@FXML private TabPane tabPane;
@FXML private tabCalendarioController tabCalendarioController;
@FXML private tabPercorsiFormativiController tabPercorsiFormativiController;
@FXML private tabStudentiController tabStudentiController;
public SoftwareController(Model model) {
this.model = model ;
}
@FXML
void initialize() {
assert tabPane != null : "fx:id=\"tabPane\" was not injected: check your FXML file 'screentab.fxml'.";
tabStudentiController.init(this);
tabCalendarioController.init(this);
tabPercorsiFormativiController.init(this);
}
}
和
public class tabStudentiController {
private SoftwareController main;
private Model model;
@FXML
private Button btnElencoStudenti;
public tabStudentiController(Model model) {
this.model = model ;
}
@FXML
public void doVisualizzaStudenti(ActionEvent event) {
model.elencaStudenti();
txtStudenti.appendText("Elenco studenti: \n");
for(Studente s: lista ){
txtStudenti.appendText(s.getStud_NOME()+ " "+ s.getStud_COGNOME()+ "\n");
}
}
public void init(SoftwareController softwareController) {
main = softwareController;
}
@FXML
void initialize() {
assert tabPane != null : "fx:id=\"tabPane\" was not injected: check your FXML file 'screentab.fxml'.";
assert tabStudenti != null : "fx:id=\"tabStudenti\" was not injected: check your FXML file 'screentab.fxml'.";
}
}
和其他控制器类似。
默认情况下,FXMLLoader
调用控制器类的默认(无参数)构造函数来创建控制器实例。由于您不再拥有这样的构造函数,因此您需要告诉FXMLLoader
如何创建控制器实例,您可以使用控制器工厂进行控制器实例:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Manage your student");
Model model = new Model();
// the controller factory is just a function mapping a Class
// to a controller instance:
Callback<Class<?>, Object> controllerFactory = type -> {
try {
for (Constructor<?> c : type.getConstructors()) {
// look for a constructor taking a single parameter of type Model:
if (c.getParameterCount()==1 && c.getParameterTypes()[0]==Model.class) {
return c.newInstance(model);
}
}
// no suitable constructor found, just use default:
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("gui/screentab.fxml"));
loader.setControllerFactory(controllerFactory);
BorderPane root = (BorderPane)loader.load();
Scene scene = new Scene(root,1000,600);
scene.getStylesheets().add(getClass().getResource("gui/stylesheet1.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
答案 1 :(得分:0)
这是少数使用controllerFactory的示例之一。这是一个负责创建控制器实例的工厂,可以在此处使用。将接口添加到需要访问Model
的所有控制器,并在创建后使用该接口中的方法将模型传递给控制器实例。
Model
。Model
时initialize
实例可用。(modelinjection
包内的所有内容)
public class ModelInjectionControllerFactory implements Callback <Class<?>, Object> {
private final Model model;
public ModelInjectionControllerFactory(Model model) {
this.model = model;
}
@Override
public Object call(Class<?> param) {
try {
// create controller using default constructor
Object controller = param.newInstance();
// inject model, if needed
if (controller instanceof ModelInjectionTarget) {
((ModelInjectionTarget) controller).injectModel(model);
}
return controller;
} catch (IllegalAccessException | InstantiationException ex) {
throw new IllegalArgumentException("Could not initialize "+ param.getSimpleName()+" using the default constructor", ex);
}
}
}
public interface ModelInjectionTarget {
void injectModel(Model model);
}
public class Model {
@Override
public String toString() {
return "I am your model";
}
}
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="modelinjection.ParentController">
<fx:include source="child.fxml"/>
</AnchorPane>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="modelinjection.ChildController">
</AnchorPane>
public class ParentController {
}
public class ChildController implements Initializable, ModelInjectionTarget {
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
System.out.println("this is my model: " +model);
}
private Model model;
@Override
public void injectModel(Model model) {
this.model = model;
}
}
Model model = new Model();
ModelInjectionControllerFactory controllerFactory = new ModelInjectionControllerFactory(model);
FXMLLoader loader = new FXMLLoader(ModelInjectionControllerFactory.class.getResource("parent.fxml"));
loader.setControllerFactory(controllerFactory);
Scene scene = new Scene(loader.load());
答案 2 :(得分:0)
错误的产生是因为您尚未实例化模型。解决此问题的最简单方法是制作Model Singleton
public class Model {
private static final Model model;
StudentiDAO dao;
List<Studente> elencoStudenti;
private Model(){
dao = new StudentiDAO();
elencoStudenti = new ArrayList<Studente>();
}
public static Model getInstance(){
if(model == null){
model = new Model();
}
return model;
}
public List<Studente> elencaStudenti(){
elencoStudenti= dao.listaStudenti();
return elencoStudenti;
}
}
您还可以为每个变量提供getter和setter方法。如果您现在想使用模型,只需要调用
Model model = Model.getInstance();
然后可以通过您的方法访问所有变量
model.elencaStudenti();
在我看来,这是一个更好的解决方案,而不是通过每个班级拉动模型。使用单例时,您可以从任何地方访问模型。我的应用程序总共有超过50个控制器,这非常有效。在模型中我也使用PropertyBindings
,它很安静。我认为这种方法也符合MVC的想法。