在JavaFX中交换面板时出错

时间:2017-01-28 18:26:59

标签: javafx

我将我的问题抽象为这个简单的应用程序。当我尝试在面板之间导航时,我发现了这个错误。

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
    at application.TestPaneController.lambda$0(TestPaneController.java:22)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8413)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Unknown Source)

主要课程

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(Main.class.getResource("MainPane.fxml"));
            Pane painelTest = loader.load();

            Scene scene = new Scene(painelTest);
            primaryStage.setScene(scene);
            primaryStage.setResizable(false);
            primaryStage.show();
        } 
        catch(Exception e) {
            e.printStackTrace();
        }
    }

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

主应用程序面板(Main.fxml)

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.Pane?>

<Pane fx:id="mainPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <fx:include fx:id="testPane" source="TestPane.fxml"/>
    <fx:include fx:id="newPane" source="NewPane.fxml"/>
</Pane>

TestPane.fxml

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.Pane?>

<Pane fx:id="testPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.TestPaneController">
    <Label fx:id="labelTitle" layoutX="26.0" layoutY="348.0" text="Test panel"/>
    <Button fx:id="button" layoutX="261.2275390625" layoutY="345.0" mnemonicParsing="false" text="OK" />
</Pane>

TestPaneController类

package application;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;

public class TestPaneController implements Initializable {

    @FXML private Pane testPane;
    @FXML private Pane newPane;
    @FXML private Button button;
    @FXML private Label labelName;

    public void initialize(URL arg0, ResourceBundle arg1) {
        button.setOnAction(event->{
            testPane.setVisible(false);
            newPane.setVisible(true);
        });
    }
}

NewPane.fxml

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.Pane?>

<Pane fx:id="newPane" prefHeight="400.0" prefWidth="600.0" visible="false" fx:controller="application.NewPaneController" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <Label fx:id="labelName" layoutX="200.0" layoutY="100.0" text="Hello"/>
    <Button fx:id="buttonBack" layoutX="261.2275390625" layoutY="345.0" mnemonicParsing="false" text="Back"/>
</Pane>

NewPaneController类

package application;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;

public class NewPaneController implements Initializable {

    @FXML private Button buttonBack;
    @FXML private Pane newPane;
    @FXML private Pane testPane;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        buttonBack.setOnAction(event->{
            newPane.setVisible(false);
            testPane.setVisible(true);
        });
    }
}

printscreen: When I run the Main class

printscreen: After clicking the Ok button

面板为空,我只是不知道为什么

1 个答案:

答案 0 :(得分:0)

<div class="form-group pull-right"> <div class="input-group"> <input type="text" class="search form-control" placeholder="Search:"> <span class="input-group-btn"> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#devices"> Add Device </button> </span> </div> </div> <span class="counter pull-right"></span> <table class="table table-responsive table-hover table-bordered results"> <thead> <tr> <th class="col-md-3">Device #</th> <th class="col-md-3">Brand</th> <th class="col-md-3">Model</th> <th class="col-md-3">Color</th> </tr> <tr class="warning no-result"> <td colspan="7"><i class="fa fa-warning"></i> No result</td> </tr> </thead> <tbody> <? $sql = "SELECT * FROM devices"; if(!$result = $db->query($sql)){ die('There was an error running the query [' . $db->error . ']'); } while($row = $result->fetch_assoc()){ ?> <tr> <th scope="row"><?=$row['uniqueID'];?></th> <td><?=$row['Brand'];?></td> <td><?=$row['Model'];?></td> <td><?=$row['Color'];?></td> </tr> <? } ?> </tbody> </table> 没有TestPane.fxml的元素,因此fx:id="newPane"中的newPane字段为空。

由于TestPaneController不属于newPane,因此将testPane的{​​{1}}视为可见的责任并不合理。您应该在控制器中为主fxml文件执行此操作。最强大和最灵活的方法是创建一个跟踪当前可见的窗格的对象。所以我会做类似的事情:

newPane

现在创建一个引用已加载窗格的TestPaneController类:

public class ViewState {

    private final ObjectProperty<Pane> currentView = new SimpleObjectProperty<>();

    public ObjectProperty<Pane> currentViewProperty() {
        return currentView ;
    }

    public final Pane getCurrentView() {
        return currentViewProperty().get();
    }

    public final void setCurrentView(Pane view) {
        currentViewProperty().set(view);
    }
}

当然在主fxml中引用该控制器:

MainController

最后修改“子控制器”,以便更新视图状态:

public class MainController {

    @FXML
    private Pane mainPane ;

    @FXML
    private Pane newPane ;
    @FXML
    private Pane testPane ;
    @FXML
    private NewPaneController newPaneController ; // field name is fx:id + "Controller"
    @FXML
    private TestPaneController testPaneController ;

    public void initialize() {
        ViewState viewState = new ViewState();
        viewState.currentViewProperty().addListener((obs, oldView, newView) -> {
            testPane.setVisible(newView == testPane);
            newPane.setVisible(newView == newPane);

            // or: for (Node n : mainPane.getChildren()) n.setVisible(n == newView);
        });

        // pass view state to "child" controllers:
        testPaneController.setViewState(viewState);
        newPaneController.setViewState(viewState);
    }

}

请注意,此设计可避免子控制器知道有关父窗格或父窗格的其他子窗口的任何信息。

您可以扩展<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import java.lang.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.layout.Pane?> <Pane fx:id="mainPane" fx:controller="application.MainController" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <fx:include fx:id="testPane" source="TestPane.fxml"/> <fx:include fx:id="newPane" source="NewPane.fxml"/> </Pane> 的功能,例如如果需要,保留“历史记录”并实施“后退”和“前进”功能。