首页 文章

编辑JavaFx场景中的窗格

提问于
浏览
-1

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

主要

package renderable;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
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.FlowPane;
import javafx.stage.Stage;

public class Main extends Application implements EventHandler<ActionEvent{
Button button;
@FXML public FlowPane flowPane;

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

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

public void updateFlowPanel(){
    flowPane.getChildren().add(button);
}

@Override
public void handle(ActionEvent event) {
    if (event.getSource() == button)
        System.out.println("The first button was pushed.");
    }
}

RenderManager

public class RenderManager implements EventHandler<ActionEvent>{
cCard tableCards[];
cHand thisPlayerHand;
@FXML public FlowPane flowPane;
Button button;

public RenderManager() {
}
public void updateFlowPanel(){
    flowPane.getChildren().add(button);
}

@Override
public void handle(ActionEvent event) {
    if (event.getSource() == button)
        System.out.println("The first button was pushed.");
}
}

ClientRender.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?package renderable?>
<?import javafx.geometry.*?>

<FlowPane id="flowPane" fx:id="flowPane" hgap="4.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="480.0" prefWidth="600.0" prefWrapLength="1400.0" style="-fx-background-color: #006600;" vgap="4.0" BorderPane.alignment="CENTER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="renderable.Main"/>

我无法正确引用与当前根关联的 RenderManager 对象,然后运行它's `updateFlowPanel()'方法 .

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

1 回答

  • 0

    获得空指针异常的原因是 @FXML -injected字段 flowPane 仅在控制器中初始化 . 您在 Main 的不是控制器的实例上调用 updateFlowPanel() ,因此 flowPane 在该实例中为空,因此 flowPane.getChildren() 抛出空指针异常 .

    具体来说: Application.launch() 创建 Application 类的实例并在该实例上调用 start() (以及其他内容) .

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

    由于 Application 和控制器类使用相同的类 Main - 这是 always 错误,因此最终会出现两个 Main 实例 . 你从 start() 调用 updateFlowPanel() ,即你在 Application.launch() 创建的实例上调用它;但 flowPane 仅在 FXMLLoader 创建的实例中初始化 .

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

    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以引用它:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    <?package renderable?>
    <?import javafx.geometry.*?>
    
    <FlowPane id="flowPane" fx:id="flowPane" hgap="4.0" 
        nodeOrientation="LEFT_TO_RIGHT" prefHeight="480.0" prefWidth="600.0" 
        prefWrapLength="1400.0" style="-fx-background-color: #006600;" vgap="4.0" 
        BorderPane.alignment="CENTER" xmlns="http://javafx.com/javafx/8" 
        xmlns:fx="http://javafx.com/fxml/1" 
        fx:controller="renderable.Controller"/>
    

    现在你可以在 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);
        }
    
    
    }
    

    或者您可以使用 start() 方法在正确的控制器实例上调用它:

    @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();
    

    loader.<Main>getController().updateFlowPanel();
    

    那么你创建的(完全不同的)问题就是你创建了一个 FXMLLoader 的实例:

    FXMLLoader loader = new FXMLLoader();
    

    但是后来不是使用 FXMLLoader 实例来加载FXML,而是调用静态方法load(URL)

    Parent root = loader.load(getClass().getResource("/renderable/ClientRender.fxml"));
    

    由于您正在调用静态方法,因此您永远不会在 FXMLLoader 实例上调用 load() ,因此它的 controller 属性永远不会被初始化 . 因此, loader.<Main>getController() 为null, loader.<Main>getController().updateFlowPanel() 抛出空指针异常(完全不同于您在先前版本的问题中的空指针异常;它甚至不会从同一方法抛出) .

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

相关问题