JavaFX访问控制器给出nullpointerexception

问题描述:

我想要实现的是从主要方法获取控制器实例,所以我可以从另一个类调用控制器的方法并更新fxml。反正这里是我的代码:JavaFX访问控制器给出nullpointerexception

主要类:

public class Main extends Application { 

Controller controller; 
@Override 
public void start(Stage primaryStage) throws Exception{ 

    FXMLLoader fxmlLoader = new FXMLLoader(); 

    Parent root = fxmlLoader.load(getClass().getResource("sample.fxml")); 
    controller = fxmlLoader.getController(); 

    primaryStage.setTitle("uPick Smart Service"); 
    primaryStage.setScene(new Scene(root, 1600, 600)); 

    primaryStage.show(); 

    ConnectionHandling connectionHandling = new ConnectionHandling(); 
    Thread X = new Thread (connectionHandling); 
    X.start(); 

} 

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

} 

public Controller getController(){ 
    return controller; 
} 


} 

我的控制器类:

public class Controller { 

public HBox billbox; 

public int childnr; 


public void createBill() { 
    System.out.println("Creating"); 
    TableView<Item> bill = new TableView<>(); 

    DropShadow dropShadow = new DropShadow(); 
    dropShadow.setRadius(5.0); 
    dropShadow.setOffsetX(3.0); 
    dropShadow.setOffsetY(3.0); 
    dropShadow.setColor(Color.color(0.4, 0.5, 0.5)); 

    VBox fullbill = new VBox(); 
    fullbill.setPadding(new Insets(1, 1, 1, 1)); 
    fullbill.getStyleClass().add("fullbill"); 

    TableColumn<Item, String> nameColumn = new TableColumn<>("Emri"); 
    nameColumn.setMinWidth(200); 
    nameColumn.setCellValueFactory(new PropertyValueFactory<>("name")); 

    TableColumn<Item, String> quantsColumn = new TableColumn<>("Sasia"); 
    quantsColumn.setMinWidth(50); 
    quantsColumn.setCellValueFactory(new PropertyValueFactory<>("quants")); 

    double tablewidth = nameColumn.getWidth() + quantsColumn.getWidth(); 

    Label tablenrlabel = new Label("Table 5"); 
    tablenrlabel.getStyleClass().add("tablenr-label"); 
    tablenrlabel.setMinWidth(tablewidth); 

    Button closebutton = new Button("Mbyll"); 
    closebutton.setMinWidth(tablewidth); 
    closebutton.getStyleClass().add("red-tint"); 

    bill.setItems(getItem()); 
    bill.setMinWidth(256); 
    bill.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); 
    bill.getColumns().addAll(nameColumn, quantsColumn); 

    fullbill.setEffect(dropShadow); 
    fullbill.getChildren().addAll(tablenrlabel, bill, closebutton); 

    billbox.getChildren().addAll(fullbill); 

    childnr += 1; 

    //Loops over every button in every vbox and gives it a seperate listener (the index of the button is hardcoded so it can cause problems if you add more items) 
    for (int i = 0; i < childnr; i++) { 
     VBox box = (VBox) billbox.getChildren().get(i); 
     Button btn = (Button) box.getChildren().get(2); //if sudden issues change this 
     btn.setId(Integer.valueOf(i).toString()); 
     btn.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent event) { 
       int index = billbox.getChildren().indexOf(btn.getParent()); 
       billbox.getChildren().remove(index); 
       childnr -= 1; 
       System.out.println(btn.getId()); 
      } 
     }); 
    } 
    System.out.println("done"); 
} 

} 

和阶级试图调用控制器的方法:

public class TakeOrder implements Runnable { 
Socket SOCK; 
Controller controller; 

//OrderIndexes: "Order","Waiter","Payment" 

private int NonConnectedDatas = 2; 

public TakeOrder(Socket X){ 
    this.SOCK = X; 
} 

public void CheckConnection() throws IOException{ 
    System.out.println("Checking connection"); 
    if(!SOCK.isConnected()){ 
     System.out.println("Dissconectiong"); 
     for(int i = 0; i < ConnectionHandling.ConnectionArray.size(); i++){ 
      if(ConnectionHandling.ConnectionArray.get(i) == SOCK){ 
       ConnectionHandling.ConnectionArray.remove(i); 
      } 
     } 
    } 
} 

public void run(){ 
    try{ 
     try{ 
      CheckConnection(); 


      ObjectInputStream ob = new ObjectInputStream(SOCK.getInputStream()); 

      String[] structuredArray = (String[])ob.readObject(); 

      String tablenr = structuredArray[0]; 
      String index = structuredArray[1]; 

      ArrayList<String> names = new ArrayList<>(); 
      ArrayList<String> quants = new ArrayList<>(); 

      int a = 0; 
      int b = 0; 
      switch (index) { 
       case "Order": 
        for (int i = NonConnectedDatas; i < structuredArray.length; i++) { 
         if (i % 2 == 0) { 
          names.add(a, structuredArray[i]); 
          System.out.println(names.get(a)); 
          a++; 
         } else { 
          quants.add(b, structuredArray[i]); 
          System.out.println(quants.get(b)); 
          b++; 
         } 
        } 
        break; 
      } 

      Platform.runLater(new Runnable() { 
       @Override 
       public void run() { 

       } 
      }); 
     }finally{ 
      SOCK.close(); 
     } 
    }catch(Exception X){ 
     System.out.print(X); 
    } 
} 



} 

这是我的错误消息:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException 
at sample.TakeOrder$1.run(TakeOrder.java:80) 
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295) 
at java.security.AccessController.doPrivileged(Native Method) 
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(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$null$148(WinApplication.java:191) 
at java.lang.Thread.run(Thread.java:745) 

的ConnectionHandling类:

public class ConnectionHandling implements Runnable{ 

public static ArrayList<Socket> ConnectionArray = new ArrayList<Socket>(); 


public void run(){ 
    System.out.println("Starting"); 
    try{ 
     final int PORT = 60123; 
     ServerSocket SERVER = new ServerSocket(PORT); 
     System.out.println("Waiting for clients"); 
     while(true){ 
      Socket SOCK = SERVER.accept(); 
      ConnectionArray.add(SOCK); 

      TakeOrder ORDER = new TakeOrder(SOCK); 
      Thread X = new Thread(ORDER); 
      X.setDaemon(true); 
      X.start(); 
     } 
    }catch(Exception x){ 
     System.out.print(x); 
    } 

} 
+0

这说明什么回报? 'controller = fxmlLoader.getController();'它是否不将控制器设置为null? – ppeterka

+0

是的,它返回null – user6535530

+0

你在哪里实例化TakeOrder并执行它的run()方法(或将它传递给Thread)? –

首先,您使用的是staticFXMLLoader.load(URL)方法。因为它是static,所以您创建的FXMLLoader实例的控制器属性未通过调用此load方法进行初始化。所以controllerMain将是null

相反,设置的位置,并使用实例方法load()

@Override 
public void start(Stage primaryStage) throws Exception{ 

    FXMLLoader fxmlLoader = new FXMLLoader(); 
    fxmlLoader.setLocation(getClass().getResource("sample.fxml")); 

    Parent root = fxmlLoader.load(); 
    controller = fxmlLoader.getController(); 

    primaryStage.setTitle("uPick Smart Service"); 
    primaryStage.setScene(new Scene(root, 1600, 600)); 

    primaryStage.show(); 



} 

这并不能完全解决你的问题,但。当您启动应用程序时,JavaFX将在该实例上创建一个Main的实例并调用start()。通过以上更改,的controller字段将被正确初始化。

然而,在TakeOrder.run()您创建的Main另一个实例:

Main main = new Main(); 

该实例的controller场不会被初始化(即使你做初始化它,它是不一样的情况下,你想)。因此,您确实需要安排TakeOrder访问在启动方法中创建的控制器实例。

这是最简单的修复程序代码,以使这项工作:

public class ConnectionHandling implements Runnable{ 

    private final Controller controller ; 

    public ConnectionHandling(Controller controller) { 
     this.controller = controller ; 
    } 

    // ... 

    public void run(){ 

     // existing code ... 

     TakeOrder ORDER = new TakeOrder(SOCK, connection); 

     // ... 
    } 
} 

public class TakeOrder implements Runnable { 

    Socket SOCK; 
    Controller controller; 

    //OrderIndexes: "Order","Waiter","Payment" 

    private int NonConnectedDatas = 2; 

    public TakeOrder(Socket X, Controller controller){ 
     this.SOCK = X; 
     this.controller = controller ; 
    } 

    // ... 

    public void run() { 

     // ... 

     Platform.runLater(controller::createBill); 

     // ... 
    } 

} 

最后

public class Main extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception{ 

     FXMLLoader fxmlLoader = new FXMLLoader(); 

     Parent root = fxmlLoader.load(getClass().getResource("sample.fxml")); 
     Controller controller = fxmlLoader.getController(); 

     primaryStage.setTitle("uPick Smart Service"); 
     primaryStage.setScene(new Scene(root, 1600, 600)); 

     primaryStage.show(); 

     ConnectionHandling connectionHandling = new ConnectionHandling(controller); 
     Thread X = new Thread (connectionHandling); 
     X.start(); 

    } 

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

    } 

    public Controller getController(){ 
     return controller; 
    } 


} 

一般的应用,如此,你可能想要考虑使用MVC或MVP方法(即你需要一个模型班级,这将举行服务,如您的ConnectionHandler)。

您可能也有兴趣在this article集成JavaFX服务。

+0

好的,非常感谢。对我来说,更多的Google搜索似乎是:D – user6535530

+0

@ user6535530如果你在你的问题中解释你创建'TakeOrder'实例的位置,这可能很容易回答。 –

如果您手动实例化Application(在本例中为Main类),则不会调用start()函数。试着用

Application.launch

,而不是

Main main = new Main()

此外,launch方法启动您的应用程序不返回,直到退出应用程序。因此,您可能需要对您的调用重新排序getController()

还有另一种管理控制器实例的方法,即使用FXMLLoader中的setController(Object controller)


文档:

https://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#launch-java.lang.Class-java.lang.String...-

https://docs.oracle.com/javase/8/javafx/api/javafx/fxml/FXMLLoader.html#setController-java.lang.Object-