-1

So I am making a small program with JavaFX to familiarize myself with it.

I'm pretty sure there is some basic understanding of how javafx works that seems to elude me though, since I'm having some issues I can't find the solution for. Despite researching them thoroughly on google.

Currently I have a setup where I use eclipse and scenebuilder 1.1 (since 2.0 gave me all kinds of trouble).

I have a pretty simple setup with a main application which loads the initial main application window.

public class Main extends Application {
        @Override 
        public void start(final Stage stage) throws Exception { 
           Parent root = FXMLLoader.load(getClass().getResource("/application/ApplicationWindow.fxml"));        
            Scene scene = new Scene(root);
            stage.getIcons().add(new Image("/application/bug3.png"));
            stage.setResizable(true);
            stage.setTitle("Simple Bugtracker");
            stage.setMinHeight(500);
            stage.setMinWidth(800);
            stage.setScene(scene);
            stage.show();
        }        

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

It seems to work fine. I then created a controller class, which contains the properly fx:id'et gui elements as field values, which works fine aswell I can manipulate them with java code.

I'm having two issues so far though.

1) When I delete something from one of my listviews, I have managed to fix the update issue so it removes it from the listview right away by adding a if null scenario. But when I create a new instance of my object type, the listview doesnt update until I restart the program?

2) Second I'm having trouble with a simple int field value in my controller class, I wanna use its current value in a method im calling (set on a button in scenebuilder), but it always seems to insist that even though the value is set correctly, it's still it's original value from when it was instantiated during launch.

This is my quite large, controller class.

public class MyController implements Initializable {

    // Logic related fields
    public ProjectList<Project> projectList = new ProjectList<Project>();
    public int currentProjectIndex = -1;
    public Bug currentBug;

    // Listview buffers
    public ObservableList<Project> projectsListBuffer = FXCollections.observableArrayList();
    public ObservableList<Bug> unsolvedListBuffer = FXCollections.observableArrayList();
    public ObservableList<Bug> solvedListBuffer = FXCollections.observableArrayList();

    // GUI related fields

    @FXML public ListView<Project> projectsListView;
    @FXML public ListView<Bug> unsolvedListView;
    @FXML public ListView<Bug> solvedListView;


    @FXML public TextArea topDisplayArea;
    @FXML public Button btnCreateProject;

    @FXML public TextField titleFieldCreateProject;
    @FXML public TextArea descriptionAreaCreateProject;

    @FXML public AnchorPane createProjectWindow;
    @FXML public AnchorPane projectsListViewAnchor;

    @FXML public Label projectTitleLabel;
    @FXML public Button createBugButton;

    @FXML public TextField titleFieldCreateBug;
    @FXML public TextArea descriptionAreaCreateBug;

    public Stage createProjectStage;
//  public Stage createBugStage;


    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        // load data from file system
        try {
            loadData();
        } catch (IOException e) {           
            e.printStackTrace();
        }
        // Instantiate gui field values
//      projectsListView = new ListView();
//      unsolvedListView = new ListView();
//      solvedListView = new ListView();
//
//
//      topDisplayArea = new TextArea();
//      btnCreateProject = new Button();
//
//      titleFieldCreateProject = new TextField();
//      descriptionAreaCreateProject = new TextArea();
//
//      createProjectWindow = new AnchorPane();
//      projectsListViewAnchor = new AnchorPane();
//
//      projectTitleLabel = new Label();
//      createBugButton = new Button();
//      
//      titleFieldCreateBug = new TextField();
//      descriptionAreaCreateBug = new TextArea();


        updateListBuffers();

        projectsListView.setPrefHeight( getScreenH() );
        projectsListView.setItems(projectsListBuffer);
        unsolvedListView.setPrefHeight( getScreenH() );
        unsolvedListView.setItems(unsolvedListBuffer);

        // settings on necessary gui items

        topDisplayArea.setPrefHeight( getScreenH() );
        topDisplayArea.setPrefWidth( getScreenW() );
        topDisplayArea.setEditable(false);
        topDisplayArea.setBackground(null); // something to be done here for transparent logo in background of all project descriptions etc.

        // ved dobbeltklik i projektlisten, vælg project og sæt titel
        projectsListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent click) {

                if (click.getClickCount() == 2) {
                    //Use ListView's getSelected Item
                    currentProjectIndex = projectsListView.getSelectionModel().getSelectedIndex();
                    Project currentProject = projectList.get(projectsListView.getSelectionModel().getSelectedIndex());
                    projectTitleLabel.setText(currentProject.getTitle());
                    System.out.println( "Selected project:"+currentProject.getTitle());                 
                    solvedListView.setItems(unsolvedListBuffer);
                    for (Bug b : currentProject.solvedBugs) {
                        System.out.println(b.getTitle()+"\n"+b.getErrorDescription());
                    }
                    updateListBuffers();
                }
            }
        });

        // ved dobbeltklik i uløste bugs listen, sæt top display område
        unsolvedListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent click) {
                if (click.getClickCount() == 2) {
                    //Use ListView's getSelected Item
                    currentBug = unsolvedListView.getSelectionModel().getSelectedItem();
                    topDisplayArea.setText(currentBug.getErrorDescription());
                }
            }
        });

        solvedListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent click) {
                if (click.getClickCount() == 2) {
                    //Use ListView's getSelected Item
                    currentBug = solvedListView.getSelectionModel().getSelectedItem();
                    topDisplayArea.setText(currentBug.getErrorDescription());
                }
            }
        });

        // custom listview cell for the projects listview
        projectsListView.setCellFactory(new Callback<ListView<Project>, ListCell<Project>>() {
            @Override
            public ListCell<Project> call(ListView<Project> p) {

                ListCell<Project> cell = new ListCell<Project>() {
                    @Override
                    protected void updateItem(Project t, boolean bln) {

                        super.updateItem(t, bln);

                        if (t != null) {
                            // program a custom cell with several items in it
                            Text text = new Text();
                            Text text2 = new Text();
                            text.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text.setText(t.getTitle());
                            text2.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text2.setText(t.getCreationDate().toLocaleString());
                            text.setFont(Font.font ("Verdana", 12));
                            text2.setFont(Font.font ("Verdana", 10));
                            text.setFill(Color.BLACK);
                            text2.setFill(Color.TEAL);
                            AnchorPane pane = new AnchorPane();     
                            pane.setPrefHeight(90);
                            pane.setPrefWidth(300);
                            ImageView imageView = new ImageView();
                            imageView.setImage(new Image("/application/project1.png"));
                            imageView.setFitHeight(60);
                            imageView.setFitWidth(60);
                            Image imageOk = new Image(getClass().getResourceAsStream("/application/selectionicon.png"));

                            Button deleteButton = new Button("Delete");
                            deleteButton.setLayoutX(233);
                            deleteButton.setLayoutY(60);
                            text.setLayoutX(70);
                            text.setLayoutY(30);
                            text2.setLayoutX(70);
                            text2.setLayoutY(50);
                            pane.getChildren().addAll(imageView, text, text2, deleteButton);

                            // delete actionevent           
                            deleteButton.setOnAction(new EventHandler<ActionEvent>() {
                                @Override 
                                public void handle(ActionEvent e) { 

                                    Alert alert = new Alert(AlertType.CONFIRMATION);
                                    alert.setTitle("Confirm deletion");
                                    alert.setHeaderText("Are you sure you want to delete this project?");
                                    Optional<ButtonType> result = alert.showAndWait();
                                    if (result.get() == ButtonType.OK){
                                        int selIndex = projectsListView.getSelectionModel().getSelectedIndex();
                                        if (selIndex>-1) {
                                            projectsListBuffer.remove(selIndex);
                                            projectList.remove(selIndex);                           
                                            projectsListView.setItems(projectsListBuffer);
                                            projectList.save();
                                        }

                                    } else {
                                        System.out.println("DENIED!!");
                                    }                                                               
                                }
                            });

                            setPrefWidth(0);
                            setGraphic(pane);
                        } else {
                            setText(null);
                            setGraphic(null);
                        }
                    }
                };
                return cell;
            }
        });

        // custom listview cell for the unsolved bugs listview
        unsolvedListView.setCellFactory(new Callback<ListView<Bug>, ListCell<Bug>>() {
            @Override
            public ListCell<Bug> call(ListView<Bug> p) {

                ListCell<Bug> cell = new ListCell<Bug>() {
                    @Override
                    protected void updateItem(Bug t, boolean bln) {
                        super.updateItem(t, bln);

                        if (t != null) {
                            // program a custom cell with several items in it
                            Text text = new Text();
                            Text text2 = new Text();
                            text.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text.setText(t.getTitle());
                            text2.wrappingWidthProperty().bind(p.widthProperty().subtract(15));
                            text2.setText(t.getCreationDate().toLocaleString());
                            text.setFont(Font.font ("Verdana", 12));
                            text2.setFont(Font.font ("Verdana", 10));
                            text.setFill(Color.BLACK);
                            text2.setFill(Color.TEAL);
                            AnchorPane pane = new AnchorPane();     
                            pane.setPrefHeight(90);
                            pane.setPrefWidth(300);
                            ImageView imageView = new ImageView();
                            imageView.setImage(new Image("/application/bug3.png"));
                            imageView.setFitHeight(60);
                            imageView.setFitWidth(60);
                            Image imageOk = new Image(getClass().getResourceAsStream("/application/selectionicon.png"));

                            Button selectButton = new Button("Select"); 
                            Button deleteButton = new Button("Delete");
                            selectButton.setLayoutX(233);
                            selectButton.setLayoutY(60);
                            deleteButton.setLayoutX(180);
                            deleteButton.setLayoutY(60);
                            text.setLayoutX(70);
                            text.setLayoutY(30);
                            text2.setLayoutX(70);
                            text2.setLayoutY(50);
                            pane.getChildren().addAll(imageView, text, text2);

                            deleteButton.setOnAction(new EventHandler<ActionEvent>() {
                                @Override 
                                public void handle(ActionEvent e) {                          
                                    projectsListBuffer.remove(projectsListView.getSelectionModel().getSelectedIndex());
                                    projectList.remove(projectsListView.getSelectionModel().getSelectedIndex());                            
                                    projectsListView.setItems(projectsListBuffer);
                                    projectList.save();
                                }
                            });

                            setPrefWidth(0);
                            setGraphic(pane);
                        } else {
                            setText(null);
                            setGraphic(null);
                        }
                    }
                };

                return cell;
            }
        });


    }

    // loads and show the create project window from it's fxml file (CreateProjectWindow.fxml)
    public void showCreateProjectWindow() {
        try {
            Parent root1 = FXMLLoader.load(getClass().getResource("/application/CreateProjectWindow.fxml"));    
            createProjectStage = new Stage();
            Scene scene = new Scene(root1);         
            createProjectStage.setScene(scene);  
            createProjectStage.setMinWidth(374);
            createProjectStage.setMinHeight(416);
            createProjectStage.setResizable(false);
            createProjectStage.show();          
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    // actionevent method that creates a new project   MANGLER AT FIKSE DET SÅ LISTVIEWET OPDATERER SIG MED DET SAMME
    public void createProject() {
        String title = titleFieldCreateProject.getText();
        String description = descriptionAreaCreateProject.getText();
        Project project = new Project(title, description, new Date());
        projectList.add(project);
        projectsListBuffer.add(project);
        projectList.save();
        updateListBuffers();
        projectsListView.setItems(projectsListBuffer);      

    }

    // loads and show the create project window from it's fxml file (CreateProjectWindow.fxml)
    public void showCreateBugWindow() {
        try {
            Parent root1 = FXMLLoader.load(getClass().getResource("/application/CreateBugWindow.fxml"));    
            createProjectStage = new Stage();
            Scene scene = new Scene(root1);         
            createProjectStage.setScene(scene);  
            createProjectStage.setMinWidth(374);
            createProjectStage.setMinHeight(416);
            createProjectStage.setResizable(false);
            createProjectStage.show();          
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    // actionevent method that creates a new bug   MANGLER AT FIKSE DET SÅ LISTVIEWET OPDATERER SIG MED DET SAMME
        public void createBug() {
            if (currentProjectIndex >-1) {
                String title = titleFieldCreateBug.getText();
                String description = descriptionAreaCreateBug.getText();
                System.out.println(title+"\n"+description);
                Bug bug = new Bug(title, description, new Date());
                projectList.get(currentProjectIndex).unsolvedBugs.add(bug);
                unsolvedListBuffer.add(bug);
                projectList.save();         
                updateListBuffers();
            } else {
                System.out.println("Failed creation.");
            }
        }

    // load, clear and reload buffers
    public void updateListBuffers() {
        if (currentProjectIndex>-1) {
            unsolvedListBuffer.clear();     
            for (int i=0; i<projectList.get(currentProjectIndex).unsolvedBugs.size(); i++) {            
                unsolvedListBuffer.add( projectList.get(currentProjectIndex).unsolvedBugs.get(i) );         
            }
            solvedListBuffer.clear();           
            for (int i=0; i<projectList.get(currentProjectIndex).solvedBugs.size(); i++) {          
                solvedListBuffer.add( projectList.get(currentProjectIndex).solvedBugs.get(i) );         
            }
//          unsolvedListView.setItems(null);
//          solvedListView.setItems(null);
            unsolvedListView.setItems(unsolvedListBuffer);
            solvedListView.setItems(solvedListBuffer);
        }   
        projectsListBuffer.clear();     
        for (int i=0; i<projectList.size(); i++) {          
            projectsListBuffer.add( projectList.get(i) );           
        }   
//      projectsListView.setItems(null);
        projectsListView.setItems(projectsListBuffer);

    }

    // file system related methods

    public void loadData() throws IOException {
        File fil = new File("Project_Data.dat");
        if ( !fil.exists() ) {
            fil.createNewFile();
            projectList = new ProjectList<Project>();
            projectList.save();
        } else {
            projectList = ProjectList.load();
        }
    }

    // practical methods

    public double getScreenH() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return screenSize.getHeight();
    }

    public double getScreenW() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        return screenSize.getWidth();
    }

}

The value I'm having trouble with is the currentProjectIndex, it seems to save it's value correctly but when the "createBug()" method is run with the click of a button, it says it's still -1 (as when it was initialized)?

Also regarding the first issue, as you can see I'm calling a window to create a new project or bug and then running the createProject() or createBug() methods, via the click of a button. But it's like the field value in the controller (selectedProjectIndex) isn't saved when I run certain methods?

So in short I can succesfully create projects, save them to a file. But the listview doesnt update before the program is retarted.

Second I can't create any bugs, because the selectedProjectIndex is always perceived as -1 for some reason?

EDIT: Updated controller class with new suggestions.

Stacktrace when I try to open a new window using either showCreateProjectWindow() or showCreateBugWindow() methods.

/C:/Users/Giuseppe/Dropbox/Java/BugTracker/bin/application/CreateProjectWindow.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.load(Unknown Source)
    at application.MyController.showCreateProjectWindow(MyController.java:320)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at sun.reflect.misc.Trampoline.invoke(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(Unknown Source)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
    at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
    at javafx.event.Event.fireEvent(Unknown Source)
    at javafx.scene.control.MenuItem.fire(Unknown Source)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(Unknown Source)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$341(Unknown Source)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$$Lambda$313/1964728071.handle(Unknown Source)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
    at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
    at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
    at javafx.event.Event.fireEvent(Unknown Source)
    at javafx.scene.Scene$MouseHandler.process(Unknown Source)
    at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
    at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$282/1128114225.get(Unknown Source)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
    at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
    at com.sun.glass.ui.View.notifyMouse(Unknown Source)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
    at com.sun.glass.ui.win.WinApplication$$Lambda$36/2117255219.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
    at application.MyController.updateListBuffers(MyController.java:399)
    at application.MyController.initialize(MyController.java:114)
    ... 65 more
ObedMarsh
  • 433
  • 4
  • 19
  • First: your `createBug()` method is called as a handler for the `createBugButton`, is that right? (And it's not called from anywhere else.) As far as I can see, `currentProjectIndex` is only changed after a double click on the list (or am I missing something?). So I assume you are double-clicking the list, then pressing the button, to test. (This seems like it could be a non-intuitive user experience, but that's a different issue.) – James_D Feb 18 '15 at 17:39
  • And second, there's something weird in your stack trace. The exception occurs when you load another FXML file in the `showCreateProjectWindow()` method; however the null pointer exception is actually thrown from a method in the same controller. Are you using controllers from the same controller class for different FXML files? That is always a bad idea. – James_D Feb 18 '15 at 17:42

1 Answers1

1

Your question is almost impossible to answer as you have it, because you have way more code than you need to reproduce the problem(s), but you don't include crucial elements (such as the FXML files). It would be better to create a small, simple, complete example from scratch that demonstrates the problems, instead of posting the entirety of one of your controller classes.

Here are some general things that may apply to the issues you are seeing.

Here is the basic process that occurs when the FXMLLoader's load(...) method is invoked:

  1. The FXMLLoader loads the FXML file.
  2. If the root element has a fx:controller attribute, and no controller has previously been set, the loader converts the string to a Class. If a controllerFactory has been set on the loader, then a constructor is retrieved as the result of passing the Class to the controller factory's call(...) method. Otherwise, a controller is instantiated via the specified class' no-argument constructor. (If a controller had previously been set, then the load process terminates with an exception.)
  3. The loader parses the FXML file, creating the specified objects, and passing them to each others' various set methods as determined by the FXML structure. When an object is created that has an fx:id attribute, and a controller has been created (by any means), then a @FXML-annotated field in the controller with the same name as the fx:id value, if one exists, is initialized to that object.
  4. If a controller has been created, and it has an initialize() method, the initialize() method is invoked.
  5. The load method completes by returning the reference to the object corresponding to the root element.

Here are some consequences of this, from a coding perspective:

Declaring and initializing an @FXML-annotated field, such as:

@FXML
private Label myLabel = new Label();

is always redundant. If the fx:id is correctly set up, then myLabel will be reassigned a new value during the load process, and the original initialized value will be discarded. Worse, if the fx:id is not correctly set up, anything that is done with myLabel will apply to a label that is not part of the scene graph, so you will get unexpected results that are hard to debug (basically, the operations will succeed but will have no visible effect in the UI). If you don't initialize the field, then if the fx:id is not set up correctly it will fail immediately with a NullPointerException, which you can then easily debug.

Similarly, reinitializing a @FXML-annotated field in the initialize() method is always a disaster:

@FXML
private Label myLabel ;

public void initialize() {
    myLabel = new Label(...);
    // ...
}

In this case myLabel is first initialized by the FXML loader, but then when the initialize() method is invoked it is replaced by a different label that is not part of the scene graph. Thus operations on myLabel will succeed but will have no visible effect in the UI.

Secondly, in the "standard" controller setup, in which you don't call setController or setControllerFactory on the FXMLLoader, but specify the controller class via the fx:controller attribute, each FXMLLoader creates one instance of the corresponding controller class. From your stack trace, it looks like both ApplicationWindow.fxml and CreateProjectWindow.fxml use the same controller class. This is always a bad idea: each instance of the shared controller class will only have @FXML-annotated fields initialized when they correspond to FXML elements defined by the specific FXML file. Obviously they will not be aware of each other's data. You should create a different controller class for each FXML file. If they need to share data, use techniques outlined in this question. Often, you can manage this by creating and exposing an observable property in one controller, and observing it from the other, as in the example below.

Here's a simple example that has some of the same structure I'm guessing your example has. It might help to study and understand this. Everything here goes in a single package called "application" (including the FXML files).

Data model class: Person.java

package application;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
    private final StringProperty firstName = new SimpleStringProperty();
    private final StringProperty lastName = new SimpleStringProperty();

    public Person(String firstName, String lastName) {
        setFirstName(firstName);
        setLastName(lastName);
    }

    public final StringProperty firstNameProperty() {
        return this.firstName;
    }

    public final String getFirstName() {
        return this.firstNameProperty().get();
    }

    public final void setFirstName(final String firstName) {
        this.firstNameProperty().set(firstName);
    }

    public final StringProperty lastNameProperty() {
        return this.lastName;
    }

    public final String getLastName() {
        return this.lastNameProperty().get();
    }

    public final void setLastName(final String lastName) {
        this.lastNameProperty().set(lastName);
    }

    @Override
    public String toString() {
        return getFirstName() +" "+getLastName();
    }
}

Main fxml file: PersonList.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>

<BorderPane xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="application.PersonListController">
    <center>
    <ListView fx:id="personList" />
</center>
    <bottom>
        <HBox spacing="5">
            <padding>
                <Insets top="10" bottom="10" left="10" right="10" />
            </padding>
            <Button text="New..." onAction="#newPerson" />
            <Button text="Edit..." onAction="#editPerson" fx:id="editButton" />
        </HBox>
    </bottom>
</BorderPane>

Main controller: PersonListController.java:

package application;

import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.stage.Stage;


public class PersonListController {
    @FXML
    private ListView<Person> personList ;
    @FXML
    private Button editButton ;

    public void initialize() {

        // list created so it fires updates if either the firstName or lastName change:
        ObservableList<Person> people = FXCollections.observableArrayList(person -> 
            new Observable[] {person.firstNameProperty(), person.lastNameProperty()});

        people.addAll(new Person("Jacob", "Smith"),
                new Person("Isabella", "Johnson"),
                new Person("Ethan", "Williams"),
                new Person("Emma", "Jones"),
                new Person("Michael", "Johnson"));
        personList.setItems(people);

        editButton.disableProperty().bind(
                Bindings.isNull(personList.getSelectionModel().selectedItemProperty()));
    }

    @FXML
    private void newPerson() throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("PersonEditor.fxml"));
        Parent root = loader.load();

        PersonEditorController controller = loader.getController();
        controller.personProperty().addListener((obs, oldPerson, newPerson) -> {
            if (newPerson != null) {
                personList.getItems().add(newPerson);
            }
        });

        showEditorWindow(root);
    }


    @FXML
    private void editPerson() throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("PersonEditor.fxml"));
        Parent root = loader.load();

        PersonEditorController controller = loader.getController();
        controller.setPerson(personList.getSelectionModel().getSelectedItem());

        showEditorWindow(root);
    }

    private void showEditorWindow(Parent root) {
        Scene scene = new Scene(root, 350, 200);
        Stage stage = new Stage();
        stage.initOwner(personList.getScene().getWindow());
        stage.setScene(scene);
        stage.show();
    }

}

Editor fxml: PersonEditor.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>

<GridPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.PersonEditorController">
    <Label text="First Name:" GridPane.columnIndex="0"
        GridPane.rowIndex="0" />
    <Label text="Last Name:" GridPane.columnIndex="0"
        GridPane.rowIndex="1" />
    <TextField fx:id="firstNameTF" GridPane.columnIndex="1"
        GridPane.rowIndex="0" />
    <TextField fx:id="lastNameTF" GridPane.columnIndex="1"
        GridPane.rowIndex="1" />
    <HBox GridPane.columnIndex="0" GridPane.rowIndex="2"
        GridPane.columnSpan="2" spacing="5">
        <padding>
            <Insets top="5" bottom="5" left="5" right="5" />
        </padding>
        <Button text="OK" onAction="#submit" />
        <Button text="Cancel" onAction="#cancel" />
    </HBox>
</GridPane>

Controller for editor: PersonEditorController.java:

package application;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;

public class PersonEditorController {
    @FXML
    private TextField firstNameTF ;
    @FXML
    private TextField lastNameTF ;

    private final ObjectProperty<Person> person = new SimpleObjectProperty<>();

    public ObjectProperty<Person> personProperty() {
        return person;
    }
    public final Person getPerson() {
        return personProperty().get();
    }
    public final void setPerson(Person person) {
        personProperty().set(person);
    }

    public void initialize() {
        personProperty().addListener((obs, oldPerson, newPerson) -> {
            if (newPerson != null) {
                firstNameTF.setText(newPerson.getFirstName());
                lastNameTF.setText(newPerson.getLastName());
            }
        });
    }

    @FXML
    private void submit() {
        if (person.get() == null) {
            person.set(new Person(firstNameTF.getText(), lastNameTF.getText()));
        } else {
            person.get().setFirstName(firstNameTF.getText());
            person.get().setLastName(lastNameTF.getText());
        }
        close();
    }

    @FXML
    private void cancel() {
        close();
    }

    private void close() {
        firstNameTF.getScene().getWindow().hide();
    }
}

Application: Main.java:

package application;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("PersonList.fxml"));
            Scene scene = new Scene(root,400,400);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322
  • I removed the FXML annotation from by bufferedlists. But when I don't initialize the field variables, I can't making any custom cells or do anything else with them in the initialize method? – ObedMarsh Feb 18 '15 at 16:51
  • It just gives null pointer exceptions since they are never initialized? – ObedMarsh Feb 18 '15 at 16:57
  • In most tutorials I found where they use scene builder, they always had them initialized? And yes the id's are correct cuz the actions are being launched and cell views look correct in the listviews. – ObedMarsh Feb 18 '15 at 16:59
  • Well it seems to actually work even though they arent initialized the errors occur when I try to load the new windows from a new fxml file for some reason. Still hasn't solved the org. issues though. – ObedMarsh Feb 18 '15 at 17:02
  • Updated the question with changes and stacktrace of new issue. – ObedMarsh Feb 18 '15 at 17:11
  • Rewrote answer from scratch. I can't address your question directly as you won't post an executable example, but maybe the example and explanation will help. – James_D Feb 18 '15 at 18:55
  • So in a very short version learn to separate controllers, focus on how to pass data between them. Got it. I will study your answer more extensively. I think that passes for an answer. – ObedMarsh Feb 18 '15 at 21:27