0

I created a JavaFX application that is nearly completed. I exported it as a runnable JAR. When opening this JAR I only see a blank window. i followed some other answers from stackoverflow but I did not get it working. It works only in the Eclipse IDE!

My screens controller:

package gui;

import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;

public class ScreensController extends StackPane {

	private HashMap<String, Node> screens = new HashMap<>();
	public static String sourcePath = "";
	private CoreService coreService;
	
	public ScreensController(){
		super();
	}
	
	
	public void addScreen(String name, Node screen) { 
	       screens.put(name, screen); 
	   } 
	
	public boolean loadScreen(String name, String resource) { 
		System.out.println("ID: "+name);
		System.out.println("Resource: "+resource);

		String file = System.getProperty("user.dir")+"\\bin\\"+resource;
//		System.out.println(file);
		
	    try { 
	       FXMLLoader myLoader = new FXMLLoader();
	       File f = new File(file);
	       URL url = f.toURI().toURL();
	       myLoader.setLocation(url);
//	       System.out.println("Location: "+myLoader.getLocation());
	       
	       Parent loadScreen = (Parent) myLoader.load(); 
	       ControlledScreen myScreenControler = 
	              ((ControlledScreen) myLoader.getController()); 
	       myScreenControler.setScreenParent(this); 
	       addScreen(name, loadScreen); 
	       System.out.println("Anzahl Screens: "+screens.size());
	       return true; 
	     }catch(Exception e) { 
	    	 System.out.println("Fehler beim Laden von "+file);
	    	 System.out.println(e.getMessage()); 
	    	 return false; 
	     }
	     
	} 

	
	public boolean setScreen(final String name) { 
		@SuppressWarnings("unused")
		Node screenToRemove;
        if(screens.get(name) != null){   //screen loaded
        	 if(!getChildren().isEmpty()){    //if there is more than one screen
        		 	getChildren().add(0, screens.get(name));     //add the screen
        		 	screenToRemove = getChildren().get(1);
        		 	getChildren().remove(1);                    //remove the displayed screen
        	 }else{
        		 getChildren().add(screens.get(name));       //no one else been displayed, then just show
        	}
        	return true;
         }else {
        	 System.out.println("Screen hasn't been loaded!!! \n");
        	 return false;
         }     
	}
	
	public boolean unloadScreen(String name) { 
		if(screens.remove(name) == null) { 
			System.out.println("Screen didn't exist!!!"); 
	        return false; 
	      } else { 
	           return true; 
	       } 
	}

	public void print() {
		Set<String> keys = screens.keySet();
		Iterator<String> it = keys.iterator();
		while (it.hasNext()){
			System.out.println("Key: "+it.next());
		} 
		
	} 
	
	public CoreService getCoreService(){
		return this.coreService;
	}
	
	public void setCoreService(CoreService coreService){
		this.coreService = coreService;
	}
	
}

And here I use it:

package gui;


import java.util.Optional;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class MainMenu extends Application {

    private Stage mainStage;
    private static CoreService coreService;
	
	public static final String MAIN_SCREEN = "main";
	public static final String MAIN_SCREEN_FXML = "gui\\MainMenu.fxml";	
	
	@Override
	public void start(Stage primaryStage) {
		
		this.mainStage = primaryStage;
	
		ScreensController mainContainer = new ScreensController();
		
		mainContainer.loadScreen(MainMenu.MAIN_SCREEN, MainMenu.MAIN_SCREEN_FXML);	
		
		mainContainer.setCoreService(MainMenu.coreService);
		
		mainContainer.setScreen(MainMenu.MAIN_SCREEN);
		Group root = new Group();
		root.getChildren().addAll(mainContainer);
		Scene scene = new Scene(root);
		primaryStage.setScene(scene);
		primaryStage.setOnCloseRequest(confirmCloseEventHandler);
		primaryStage.show();
		
	}
	
    private EventHandler<WindowEvent> confirmCloseEventHandler = event -> {
    	//Source: http://stackoverflow.com/questions/29710492/javafx-internal-close-request
        Alert closeConfirmation = new Alert(
                Alert.AlertType.CONFIRMATION,
                "Are you sure you want to exit?"
        );
        Button exitButton = (Button) closeConfirmation.getDialogPane().lookupButton(
                ButtonType.OK
        );
        exitButton.setText("Exit");
        closeConfirmation.setHeaderText("Confirm Exit");
        closeConfirmation.initModality(Modality.APPLICATION_MODAL);
        closeConfirmation.initOwner(mainStage);

        closeConfirmation.setX(mainStage.getX() + 150);
        closeConfirmation.setY(mainStage.getY() - 300 + mainStage.getHeight());

        Optional<ButtonType> closeResponse = closeConfirmation.showAndWait();
        if (!ButtonType.OK.equals(closeResponse.get())) {
            event.consume();
        }
    };
	
	public static void main(String[] args, CoreService aService) {	
		// Weitergeben des CoreServices
		coreService = aService;
		launch(args);
	}

}

I do not see where the error is. When I start the program from command line it says that the MainMenu.fxml file could not been found. In my application it is in the package gui. -> gui/MainMenu.fxml

Would be nice if someone find my error!

1 Answer 1

0

What the error message tells you, that the FXML file cannot be located.

You could try to:

Change this ...

public static final String MAIN_SCREEN_FXML = "gui\\MainMenu.fxml"; 

... to ...

public static final String MAIN_SCREEN_FXML = "/gui/MainMenu.fxml"; 

And to change this ...

FXMLLoader myLoader = new FXMLLoader();
File f = new File(file);
URL url = f.toURI().toURL();
myLoader.setLocation(url);

... to (and you don't need the variables file and f)...

FXMLLoader myLoader = new FXMLLoader(getClass().getResource(resource));

Some references:

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, I tried nearly what you suggested, but I missed to add a leading slash before the path! Thank you for the answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.