当前位置: 首页 > 知识库问答 >
问题:

JavaFX访问控制器提供nullpointerexception

韩禄
2023-03-14

我试图实现的是从main方法获取控制器实例,这样我就可以从另一个类调用控制器的方法并更新fxml。总之,这是我的代码:

主要类别:

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);
    }

}

共有2个答案

隆康平
2023-03-14

如果手动实例化应用程序,在本例中是Main类,则不会调用start()函数。试着用

一个pplication.launch

而不是

Main=new Main()

此外,启动方法在应用程序退出之前不会返回。因此,您可能希望对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-爪哇。lang.反对-

司知
2023-03-14

首先,您使用的是staticFXMLLoader。加载(URL)方法。因为它是静态的,所以创建的FXMLLoader实例的控制器属性不是通过调用此load方法初始化的。因此,Main中的controller将为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()。通过上述更改,该实例的控制器字段将被正确初始化。

但是,在TakeOrder.run()中,您创建另一个Main实例:

Main main = new Main();

该实例的controller字段不会被初始化(即使您确实初始化了它,它也与您想要的实例不同)。因此,您确实需要安排TakeOrder来访问在start方法中创建的控制器实例。

下面是对代码最直接的修复,以使其工作:

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方法(即,您需要一个模型类,它将保存服务,例如您的连接处理程序)。

您可能还对这篇关于在JavaFX中集成服务的文章感兴趣。

 类似资料:
  • 这让我的头撞到了墙上!!!!希望有人能给我指出正确的方向。我确信我在做一些完全愚蠢的事情。我找了又找,但似乎找不出为什么这不管用!!(在IntelliJ IDE 15.x上使用JDK8.x和Scenebuilder)。我试图在GUI上显示数据,但希望access通过编程将这些数据从其他类/方法发送给它。。。。下面是一个简单的概念,我在着手更大的项目之前,正试图让它发挥作用: 我的简单GUI在FXM

  • 我怎么绕过这个?我需要以某种方式再次实现那个方法,但突然间我不能通过作为一个论点的阶段。

  • null 我在TopMenuButtons中有一个按钮,它具有openAssisstantStage()方法,打开新的小阶段: 对于这个阶段,我还有FXML文件和控制器(AssisstantController)。只有2个按钮-第一个按钮应该打开前一个阶段和关闭电流,但第二个按钮也应该打开普雷沃阶段,关闭电流,也打开一个特定的标签在我的标签视图和做一些其他逻辑例如。获取实际localDate: 我

  • 容器访问控制 容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现。iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。 容器访问外部网络 容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。 $sysctl net.ipv4.ip_forwardnet.ipv4.ip_forward = 1 如果为 0,

  • 需要你的帮助!这可能是更多的设计角度,但我在我的应用程序中使用这个模式,所以想得到一个想法。 我的问题是直接或间接地从一个控制器访问另一个控制器。是否有任何优雅的设计方法来做到这一点,而不是在另一个控制器中保留一个控制器的引用。 提前致谢

  • 我有两个控制器和。我正在读一本书的内容。来自的txt文件,我希望将该文本放置在的文本区域中。代码在中运行并读取良好,但当打开中的窗口时,从中读取的内容。文本内容在文本区域中不可见。我的显示String mine包含内容,但它不显示在的文本区域中。请帮助任何人。非常感谢。 FXMLDocumentController代码 在中,有一个我删除了和,这样代码就可以工作了。