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!

andre-3000
  • 73
  • 1
  • 2
  • 11

1 Answers1

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:

Community
  • 1
  • 1
DVarga
  • 21,311
  • 6
  • 55
  • 60
  • Thank you, I tried nearly what you suggested, but I missed to add a leading slash before the path! Thank you for the answer! – andre-3000 May 31 '16 at 13:03