Search code examples
javajavafxjava-17

JavaFX scene refuses to load, even though it worked before


I was creating a JavaFX application when something I tried froze the program and I had to close it manually. However, instead of killing the program in IntelliJ, I instead clicked the X to close it. After this point, the window refused to open, getting stuck at stage.setScene().

I've cleared my build caches, I've regenerated the run task, I've restarted my computer, I've switched computers, and in those attempts it only loaded once or twice and then never again. I've tried switching from FXML to plain Java, setting the scene to a childless node (which seems to load) and then setting the node to a fully furnished Java one (which then it gets stuck).

Here is my code for what I have.

package gg.hipposgrumm.jsr_launcher;

import gg.hipposgrumm.jsr_launcher.scenes.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class JSRLauncherMain extends Application {
    public static Stage popup;

    @Override
    public void start(Stage stage) throws IOException {
        stage.setTitle("JSR Launcher");
        // Everything before this point executes.
        stage.setScene(new Scene(Home.create()));
        // Nothing after this point executes.
        stage.setMinWidth(240);
        stage.setMinHeight(120);
        stage.show();

        // More Code
    }

    public static void main(final String[] args) {
        launch();
    }
}
package gg.hipposgrumm.jsr_launcher.scenes;

import gg.hipposgrumm.jsr_launcher.JSRLauncherMain;
import gg.hipposgrumm.jsr_launcher.util.Game;
import gg.hipposgrumm.jsr_launcher.util.saving.ServerInfo;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;

import java.io.IOException;

public class Home {
    public final BorderPane window;
    private final ComboBox<LoginInfo> accounts;
    private final ComboBox<ServerInfo> servers;

    private Home() {
        accounts = new ComboBox<>();
        accounts.setPromptText("Not Logged In");
        servers = new ComboBox<>();
        servers.setPromptText("No Server Selected");

        Button accountButton = new Button("Manage Accounts");
        accountButton.setOnAction((event) -> {
            try {
                JSRLauncherMain.popupLogin(false);
            } catch (IOException e) {
                throw new IllegalStateException("Failed to open the Login menu please report with the following stacktrace: ", e);
            }
        });
        Button serverButton = new Button("Manage Servers");
        serverButton.setOnAction((event) -> {
            try {
                // TODO: Make this open the server menu.
                JSRLauncherMain.popupLogin(false);
            } catch (IOException e) {
                throw new IllegalStateException("Failed to open the Server menu please report with the following stacktrace: ", e);
            }
        });
        BorderPane footer = new BorderPane(
                null,
                null,
                new HBox(servers, serverButton),
                null,
                new HBox(accounts,accountButton));
        footer.setPadding(new Insets(5));
        window = new BorderPane(new TabPane(
                // Tabs added here.
        ), null, null, footer, null);
        window.setMinSize(240, 120);
        window.setMaxSize(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
        window.setPrefSize(800, 400);

        window.setUserData(this);
    }


    public static Parent create() {
        Home home = new Home();
        home.update();
        return home.window;
    }

    public void update() {
        // This does a thing.
    }
}

I wish I could include a repo but I currently want to keep the project private until release.


Solution

  • As other said without a minimum reproductible example, it is not possible to give you a precise answer. However, "it works once and not after" is typical of an application using a system resource (file, port...) and not releasing it properly.

    In JavaFX, it's usually because the cross button doesn't send the interupt signal and stop the JVM. It just close the main Stage and stop the JavaFX framework. If other thread are created, then the JVM is kept alive by them and resources are not released (you should still have the process open in background).

    Identify which resources could be lock and clean them properly after usage or when the stage close by doing :

    public class JSRLauncherMain extends Application {
    
        @Override
        public void start(Stage stage) throws IOException {
            stage.setTitle("JSR Launcher");
            
                 
            // More Code
        }
        
        @Override
        public void stop() {
          // clear ressources
        }
    

    Edit to use Applciation.stop() as comment suggest.