定义控制器时加载多个 FXML 文件失败
Loading multiple FXML-files fails when controllers are defined
我知道这个问题被问过很多次,但我找不到适合我的解决方案(实际上我什至看不出我做错了什么)。
基本思想是在需要时加载 GUI 组件。所以我在各种 FXML 文件中构造了 GUI,并实现了控制器-classes。 FXML 文件和 classes 都存储在同一个包中,但每个组件都有一个包。只要我没有在 FXML 文件 (fx:controller) 中定义控制器-class,每个 FXML 文件都会加载并添加到 GUI。如果它被定义,我将得到一个 LoadException。
为了更好地理解这里是我的代码(简化):
Main.java:
package application;
import application.a.ControllerA;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application
{
// Button aus MainLayout.fxml
@FXML
private Button button;
@Override
public void start(Stage primaryStage)
{
try
{
BorderPane root = new BorderPane();
Parent contentMain = FXMLLoader.load(getClass().getResource("MainLayout.fxml"));
ControllerA contentA = new ControllerA(root);
root.setTop(contentA.getContent());
root.setCenter(contentMain);
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
// Event-Handler für den Button -> funktioniert!
@FXML
public void buttonClicked(ActionEvent e)
{
if (!button.getText().equals("NEW"))
{
button.setText("NEW");
}
else
{
button.setText("OLD");
}
}
}
这个 class 也是以下布局的控制器(到目前为止它可以正常工作):
MainLayout.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.GridPane?>
<Pane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Main">
<children>
<Button fx:id="button" mnemonicParsing="false" onAction="#buttonClicked" text="Button" />
</children>
</Pane>
在 application
的子包(称为 a)中,您会发现:
ControllerA.java:
package application.a;
import java.net.URL;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
public class ControllerA
{
private Parent content;
@FXML
private Button buttonA;
public ControllerA(BorderPane root)
{
String sceneFile = "A.fxml";
URL url = null;
try
{
url = getClass().getResource(sceneFile);
content = FXMLLoader.load(url);
}
catch (Exception ex)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Parent getContent()
{
return content;
}
@FXML
public void clickedA(ActionEvent e)
{
buttonA.setText("Clicked already");
}
}
A.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.GridPane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.a.ControllerA">
<children>
<Button fx:id="buttonA" layoutX="274.0" layoutY="188.0" mnemonicParsing="false" onAction="#clickedA" text="A" />
</children>
</Pane>
这就是问题所在:
javafx.fxml.LoadException:
/Z:/BachelorArbeit/Projektdateien/Entwicklung/EclipseWorkspace/Sandbox/bin/application/a/A.fxml:8
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access0(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:932)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at application.a.ControllerA.<init>(ControllerA.java:26)
at application.Main.start(Main.java:35)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication12(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait5(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null3(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater4(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null8(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.InstantiationException: application.a.ControllerA
at java.lang.Class.newInstance(Class.java:427)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:927)
... 23 more
Caused by: java.lang.NoSuchMethodException: application.a.ControllerA.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 25 more
我已经尝试 fiddle 像
这样的路径字符串
- "./a/A.fxml"
- "/应用程序/a/A.fxml"
- "A.fxml"
- "a/A.fxml"
- ...
但没有任何效果。如果有人能帮我解决这个问题,我会感到很欣慰。
我将向您展示一个最小的工作示例项目,我建议您调整结构以适应它。
文件夹结构如下
这是主要内容class
包裹 dynamic.content.javafx;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public final class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root, 300, 200);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
主控制器
package dynamic.content.javafx;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
public final class MainController implements Initializable{
@FXML
private Button btnSwitch;
@FXML
private AnchorPane contentPane;
@Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
private boolean swtch = false;
@FXML
public void handleContentSwitch() throws IOException{
Parent contentNode = null;
if(swtch){
System.out.println("loading content A");
contentNode = FXMLLoader.load(getClass().getResource("./content/content_a.fxml"));
}else{
System.out.println("loading content B");
contentNode = FXMLLoader.load(getClass().getResource("./content/content_b.fxml"));
}
contentPane.getChildren().clear();
contentPane.getChildren().add(contentNode);
swtch = !swtch;
}
}
主要的 FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dynamic.content.javafx.MainController">
<children>
<Button fx:id="btnSwitch" onAction="#handleContentSwitch" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" text="Switch Content" />
<AnchorPane fx:id="contentPane" prefHeight="150.0" prefWidth="300.0" />
</children>
</VBox>
假设我们有内容 A 和 B,我们需要为每个内容创建一个控制器和一个 FXML
package dynamic.content.javafx.content;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class ContentAController implements Initializable{
@FXML
private Label labl;
@Override
public void initialize(URL location, ResourceBundle resources) {
labl.setText("Content A");
}
}
而现在对应的FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="150.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dynamic.content.javafx.content.ContentAController">
<children>
<Label fx:id="labl" alignment="CENTER" contentDisplay="CENTER" text="Label" textAlignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
下面是第二个控制器
package dynamic.content.javafx.content;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class ContentBController implements Initializable{
@FXML
private Label labl;
@Override
public void initialize(URL location, ResourceBundle resources) {
labl.setText("Content B");
}
}
和第二个 FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="150.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dynamic.content.javafx.content.ContentBController">
<children>
<Label fx:id="labl" alignment="CENTER" contentDisplay="CENTER" text="Label" textAlignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
如果您知道按下按钮,内容将被动态加载
如果您有任何问题,请告诉我:-)
您正在混合使用 FXML 和控制器的两种不同方式。如果您的 FXML 文件有 fx:controller="SomeClass"
,那么 FXMLLoader
将实例化 class 并将该实例用作控制器:换句话说,它使 FXML 创建控制器。
另一方面,您的控制器的构造函数加载 FXML,因此您还可以让控制器创建 FXML 中定义的 UI。
异常原因是FXMLLoader
遇到fx:controller
属性时,调用了指定[=]的无参构造函数 39=]:即在这种情况下,它会尝试调用 new ControllerA()
。由于没有这样的构造函数,您会得到异常:
java.lang.NoSuchMethodException: application.a.ControllerA.<init>()
控制器构造函数的 BorderPane
参数的用途不是很清楚,因为您从未使用过它。然而,即使你在这里有一个合适的构造函数,它也会导致另一个问题:加载 FXML 会调用控制器的构造函数,它加载 FXML,它会调用控制器的构造函数,等等:你会得到一个 WhosebugException
。如果要从控制器的构造函数加载 FXML:
- 从 FXML 文件中删除
fx:controller
属性
将 FXMLLoader
上的控制器显式设置为当前控制器实例:
public ControllerA(BorderPane root)
{
String sceneFile = "A.fxml";
URL url = null;
try
{
url = getClass().getResource(sceneFile);
FXMLLoader loader = new FXMLLoader(url);
loader.setController(this);
content = loader.load();
}
catch (Exception ex)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
我知道这个问题被问过很多次,但我找不到适合我的解决方案(实际上我什至看不出我做错了什么)。
基本思想是在需要时加载 GUI 组件。所以我在各种 FXML 文件中构造了 GUI,并实现了控制器-classes。 FXML 文件和 classes 都存储在同一个包中,但每个组件都有一个包。只要我没有在 FXML 文件 (fx:controller) 中定义控制器-class,每个 FXML 文件都会加载并添加到 GUI。如果它被定义,我将得到一个 LoadException。
为了更好地理解这里是我的代码(简化):
Main.java:
package application;
import application.a.ControllerA;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application
{
// Button aus MainLayout.fxml
@FXML
private Button button;
@Override
public void start(Stage primaryStage)
{
try
{
BorderPane root = new BorderPane();
Parent contentMain = FXMLLoader.load(getClass().getResource("MainLayout.fxml"));
ControllerA contentA = new ControllerA(root);
root.setTop(contentA.getContent());
root.setCenter(contentMain);
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
// Event-Handler für den Button -> funktioniert!
@FXML
public void buttonClicked(ActionEvent e)
{
if (!button.getText().equals("NEW"))
{
button.setText("NEW");
}
else
{
button.setText("OLD");
}
}
}
这个 class 也是以下布局的控制器(到目前为止它可以正常工作):
MainLayout.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.GridPane?>
<Pane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Main">
<children>
<Button fx:id="button" mnemonicParsing="false" onAction="#buttonClicked" text="Button" />
</children>
</Pane>
在 application
的子包(称为 a)中,您会发现:
ControllerA.java:
package application.a;
import java.net.URL;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
public class ControllerA
{
private Parent content;
@FXML
private Button buttonA;
public ControllerA(BorderPane root)
{
String sceneFile = "A.fxml";
URL url = null;
try
{
url = getClass().getResource(sceneFile);
content = FXMLLoader.load(url);
}
catch (Exception ex)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Parent getContent()
{
return content;
}
@FXML
public void clickedA(ActionEvent e)
{
buttonA.setText("Clicked already");
}
}
A.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.GridPane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.a.ControllerA">
<children>
<Button fx:id="buttonA" layoutX="274.0" layoutY="188.0" mnemonicParsing="false" onAction="#clickedA" text="A" />
</children>
</Pane>
这就是问题所在:
javafx.fxml.LoadException:
/Z:/BachelorArbeit/Projektdateien/Entwicklung/EclipseWorkspace/Sandbox/bin/application/a/A.fxml:8
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access0(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:932)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at application.a.ControllerA.<init>(ControllerA.java:26)
at application.Main.start(Main.java:35)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication12(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait5(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null3(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater4(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null8(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.InstantiationException: application.a.ControllerA
at java.lang.Class.newInstance(Class.java:427)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:927)
... 23 more
Caused by: java.lang.NoSuchMethodException: application.a.ControllerA.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 25 more
我已经尝试 fiddle 像
这样的路径字符串- "./a/A.fxml"
- "/应用程序/a/A.fxml"
- "A.fxml"
- "a/A.fxml"
- ...
但没有任何效果。如果有人能帮我解决这个问题,我会感到很欣慰。
我将向您展示一个最小的工作示例项目,我建议您调整结构以适应它。
文件夹结构如下
这是主要内容class 包裹 dynamic.content.javafx;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public final class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root, 300, 200);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
主控制器
package dynamic.content.javafx;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
public final class MainController implements Initializable{
@FXML
private Button btnSwitch;
@FXML
private AnchorPane contentPane;
@Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
private boolean swtch = false;
@FXML
public void handleContentSwitch() throws IOException{
Parent contentNode = null;
if(swtch){
System.out.println("loading content A");
contentNode = FXMLLoader.load(getClass().getResource("./content/content_a.fxml"));
}else{
System.out.println("loading content B");
contentNode = FXMLLoader.load(getClass().getResource("./content/content_b.fxml"));
}
contentPane.getChildren().clear();
contentPane.getChildren().add(contentNode);
swtch = !swtch;
}
}
主要的 FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dynamic.content.javafx.MainController">
<children>
<Button fx:id="btnSwitch" onAction="#handleContentSwitch" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" text="Switch Content" />
<AnchorPane fx:id="contentPane" prefHeight="150.0" prefWidth="300.0" />
</children>
</VBox>
假设我们有内容 A 和 B,我们需要为每个内容创建一个控制器和一个 FXML
package dynamic.content.javafx.content;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class ContentAController implements Initializable{
@FXML
private Label labl;
@Override
public void initialize(URL location, ResourceBundle resources) {
labl.setText("Content A");
}
}
而现在对应的FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="150.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dynamic.content.javafx.content.ContentAController">
<children>
<Label fx:id="labl" alignment="CENTER" contentDisplay="CENTER" text="Label" textAlignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
下面是第二个控制器
package dynamic.content.javafx.content;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class ContentBController implements Initializable{
@FXML
private Label labl;
@Override
public void initialize(URL location, ResourceBundle resources) {
labl.setText("Content B");
}
}
和第二个 FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="150.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dynamic.content.javafx.content.ContentBController">
<children>
<Label fx:id="labl" alignment="CENTER" contentDisplay="CENTER" text="Label" textAlignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
如果您知道按下按钮,内容将被动态加载
如果您有任何问题,请告诉我:-)
您正在混合使用 FXML 和控制器的两种不同方式。如果您的 FXML 文件有 fx:controller="SomeClass"
,那么 FXMLLoader
将实例化 class 并将该实例用作控制器:换句话说,它使 FXML 创建控制器。
另一方面,您的控制器的构造函数加载 FXML,因此您还可以让控制器创建 FXML 中定义的 UI。
异常原因是FXMLLoader
遇到fx:controller
属性时,调用了指定[=]的无参构造函数 39=]:即在这种情况下,它会尝试调用 new ControllerA()
。由于没有这样的构造函数,您会得到异常:
java.lang.NoSuchMethodException: application.a.ControllerA.<init>()
控制器构造函数的 BorderPane
参数的用途不是很清楚,因为您从未使用过它。然而,即使你在这里有一个合适的构造函数,它也会导致另一个问题:加载 FXML 会调用控制器的构造函数,它加载 FXML,它会调用控制器的构造函数,等等:你会得到一个 WhosebugException
。如果要从控制器的构造函数加载 FXML:
- 从 FXML 文件中删除
fx:controller
属性 将
FXMLLoader
上的控制器显式设置为当前控制器实例:public ControllerA(BorderPane root) { String sceneFile = "A.fxml"; URL url = null; try { url = getClass().getResource(sceneFile); FXMLLoader loader = new FXMLLoader(url); loader.setController(this); content = loader.load(); } catch (Exception ex) { // TODO Auto-generated catch block e.printStackTrace(); } }