在JavaFx场景中编辑窗格

在JavaFx场景中编辑窗格,java,javafx,Java,Javafx,我试图设置一个JavaFx场景,在这个场景中可以在运行时更改嵌套的FlowPane。我希望能够将新元素添加到窗格中,并将它们渲染出来 主要 包可渲染; 导入javafx.application.application; 导入javafx.event.ActionEvent; 导入javafx.event.EventHandler; 导入javafx.fxml.fxml; 导入javafx.fxml.fxmloader; 导入javafx.scene.Parent; 导入javafx.scene.

我试图设置一个JavaFx场景,在这个场景中可以在运行时更改嵌套的FlowPane。我希望能够将新元素添加到窗格中,并将它们渲染出来

主要

包可渲染;
导入javafx.application.application;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.fxml.fxml;
导入javafx.fxml.fxmloader;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.layout.FlowPane;
导入javafx.stage.stage;
公共类主扩展应用程序实现EventHandler
我无法正确引用与当前根目录关联的
RenderManager
对象,然后运行其“updateFlowPanel()”方法


如何在运行时将元素正确添加到窗格中?

获得空指针异常的原因是
@FXML
-注入字段
flowPane
仅在控制器中初始化。您正在对非控制器的
Main
实例调用
updateFlowPanel()
,因此
flowPane
在该实例中为null,因此
flowPane.getChildren()
引发null指针异常

具体来说:
Application.launch()
创建
Application
类的实例,并在该实例上调用
start()

默认情况下,调用
fxmloader.load()
,将创建由FXML根元素中的
fx:controller
属性指定的类的实例。在该实例中初始化任何
@FXML
-注入的字段,在该实例上调用事件处理程序方法,并在该实例上调用
initialize()
方法

由于对
应用程序
和控制器类使用相同的类
Main
总是一个错误,因此会出现两个
Main
实例。您可以从
start()
调用
updateFlowPanel()
,即在
Application.launch()创建的实例上调用它;但是,
flowPane
仅在由
fxmloader
创建的实例中初始化

您应该使用单独的控制器类。即做

package renderable;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/renderable/ClientRender.fxml"));
        Scene scene = new Scene(root, 1000, 720);
        primaryStage.setTitle("The Game");
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.show();
    }

}
然后定义一个控制器类:

package renderable ;

import javafx.fxml.FXML ;
import javafx.scene.layout.FlowPane ;
import javafx.scene.control.Button ;

public class Controller {

    @FXML
    private FlowPane flowPane ;

    public void updateFlowPanel(){
        Button button = new Button("...");
        flowPane.getChildren().add(button);
    }


}
并更新FXML以引用它:


现在,您可以在
initialize()
方法中调用
updateFlowPanel()

package renderable ;

import javafx.fxml.FXML ;
import javafx.scene.layout.FlowPane ;
import javafx.scene.control.Button ;

public class Controller {

    @FXML
    private FlowPane flowPane ;

    public void initialize() {
        updateFlowPanel();
    }

    public void updateFlowPanel(){
        Button button = new Button("...");
        flowPane.getChildren().add(button);
    }


}
    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/renderable/ClientRender.fxml"));
        Parent root = loader.load();
        Controller controller = loader.getController();
        controller.updateFlowPanel();
        Scene scene = new Scene(root, 1000, 720);
        primaryStage.setTitle("The Game");
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.show();
    }
或者,您可以从
start()
方法在正确的控制器实例上调用它:

package renderable ;

import javafx.fxml.FXML ;
import javafx.scene.layout.FlowPane ;
import javafx.scene.control.Button ;

public class Controller {

    @FXML
    private FlowPane flowPane ;

    public void initialize() {
        updateFlowPanel();
    }

    public void updateFlowPanel(){
        Button button = new Button("...");
        flowPane.getChildren().add(button);
    }


}
    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/renderable/ClientRender.fxml"));
        Parent root = loader.load();
        Controller controller = loader.getController();
        controller.updateFlowPanel();
        Scene scene = new Scene(root, 1000, 720);
        primaryStage.setTitle("The Game");
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.show();
    }
编辑: 您对问题所做的更新实际上阻止了代码的编译。如果您通过替换

loader.getController().updateFlowPanel();

但是,不使用该
FXMLLoader
实例来加载FXML,而是调用静态方法:

由于您调用的是静态方法,因此从未对
fxmloader
实例调用
load()
,因此其
controller
属性从未初始化。因此,
loader.getController()
为空,
loader.getController().updateFlowPanel()
引发空指针异常(与问题的前一版本中的空指针异常完全不同;它甚至不是从同一方法引发的)


如果要引用控制器,请使用我在上面发布的
start()
方法的第二个版本中的代码。

1。不太清楚为什么您似乎有两个
Application
类。控制器类不应是
应用程序
子类的子类。2.如果要更改FXML中定义的现有
FlowPane
的内容,则不应创建新的
FlowPane
。只需对现有的
流程窗格进行更改即可。3.你可能需要在这里创建一个模型,这样我们就可以看到所有的部件是如何组合在一起的。创建一个尽可能简单的示例,说明您正在尝试做什么,并编辑您的问题以将其全部包含在内。我不知道如何更改现有的流程窗格。当我尝试使用fxid引用它时,我得到一个NullPointerException。然后您可能没有在实际控制器上调用
fillFlowPane()
(您可能在
RenderManager控制器的另一个实例上调用它)。但从你在这里发布的内容是无法判断的。我们甚至不知道您实际运行的是哪个类作为主类(同样,为什么有两个
应用程序
类??)。您需要发布一个。另外,
?我很确定这不是有效的FXML。您需要在控制器上调用
updateFlowPanel()
:您在
Main
的错误实例上调用它。为控制器使用单独的类(而不是
应用程序
类)。决不能将
应用程序
类用作控制器类。
loader.getController().updateFlowPanel();
loader.<Main>getController().updateFlowPanel();
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("/renderable/ClientRender.fxml"));