0

I have been stuck on this for a while and I am really at my last hope. I really have no idea what the problem can be. I have a GUI project using what I hope is correct MVP form and my problem is I have a presenter object that becomes null in my view class when being used within any method. So far the gui should load and user should hit the button, the method calls the presenter object's method to do something but it is always null. I tried passing into the view class's constructor, making it a object only within the view class, etc and I can't to fix it. Any help is appreciated. I have no idea what is going on and it does not seem to do this to any other object I think

main.java

package main;

import model.Model;
import presenter.Presenter;
import view.View;

public class Main
{
    public static void main(String[] args) 
    {
        View view = new View();
        Model model = new Model();
        Presenter presenter = new Presenter(view, model);
        view.setPresenter(presenter);
        // this was a way I found on stack overflow to call
        // another class that inhierts the application class
        // and be able to have args passed if needed
        View.launch(View.class, args);
    }

}

View.java

    package view;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import presenter.Presenter;

public class View extends Application
{
    private Presenter presenter;
    private Button test;
    private Views views; 

    public final static String LOGINVIEW = "loginscreen";
    public final static String LOGINVIEWFILE = "FXMLViewLogin.fxml";
    public final static String CHATVIEW = "chatscreen";
    public final static String CHATVIEWFILE = "FXMLViewChat.fxml";

    public View()
    {
        // init Views class
        views = new Views();
    }

    public void setPresenter(Presenter pres)
    {
        this.presenter = pres;
    }

    @Override
    public void start(Stage primaryStage) 
    {
        loadViews();
        primaryStage.setScene(setView(LOGINVIEW));
        primaryStage.setTitle("");
        primaryStage.show();
    }

    private void loadViews()
    {
        views.loadScreen(LOGINVIEW, LOGINVIEWFILE);
        views.loadScreen(CHATVIEW, CHATVIEWFILE);
    }

    private Scene setView(String name)
    {
        return views.setView(name);
    }

    @FXML
    private void test(ActionEvent event) 
    {
        //***********************************************************
        // ALWAYS NULL IN THIS EVENT METHOD METHOD AND ANY OTHER METHOD FOR THAT FACT AFTER setPresenter
        if(presenter == null)
            System.out.println("Why is this null right here?");
    }
}

Presenter.java

package presenter;

import view.View;
import model.Model;

public class Presenter 
{
    private Model model;
    private View view;

    public Presenter(View view, Model model)
    {
        this.model = model;
        this.view = view;

    }

    // any methods start here 
}

Views.java

package view;

import java.util.HashMap;
import javafx.fxml.FXMLLoader;

import javafx.scene.Parent;
import javafx.scene.Scene;


public class Views 
{
    private final HashMap<String, Parent> view;

    public Views() 
    {
        this.view = new HashMap<>();
    }

    public void addView(String name, Parent screen) 
    {
        view.put(name, screen);
    }

    public boolean loadScreen(String name, String file)
    {
        try 
        {
            FXMLLoader myLoader = new FXMLLoader(getClass().getResource(file));
            Parent loadScreen = (Parent) myLoader.load();
            addView(name, loadScreen);
            return true;
        } 
        catch (Exception e) 
        {
            return false;
        }
    }

    public Scene setView(final String name) 
    {
        Scene scene = null;
        if (view.get(name) != null)  
            scene = new Scene(getParentNode(name));   
        unloadView(name);
        return scene;
    }

    private boolean unloadView(String name) 
    {
        return view.remove(name) != null;
    }

    private Parent getParentNode(String name)
    {
        return view.get(name);
    }

}
Tanner Summers
  • 689
  • 1
  • 8
  • 26
  • It's impossible to say without seeing the code you use to initialize the FXML. Most probable reason is you use `FXMLLoader#load` without using `setController`, so you end up with a new instance of `View`, which hasn't got a presenter set. Also - it's not a good idea to have the `Application` class same as the controller. See here: http://stackoverflow.com/questions/33303167/javafx-can-application-class-be-the-controller-class – Itai Dec 29 '15 at 18:12
  • Updated original post – Tanner Summers Dec 29 '15 at 18:13
  • So indeed - calling `load` without calling `setController` means the `FXMLLoader` creates a new instance. See linked question and answer. – Itai Dec 29 '15 at 18:14
  • @brso05 it's JavaFX usinf FXML theres a FXML file that controls the UI elements and it has a event set up so when the user clicks the button, it calls test, that part works since i get null exception along with my nice little system print message lol – Tanner Summers Dec 29 '15 at 18:14
  • Calling `View.launch(...)` also creates a new instance... You never set the presenter on the `View` instance on which `start(...)` is invoked. – James_D Dec 29 '15 at 18:14
  • @sillyfly another post said that as long as the fxml file states the controller, such as the line I have in mine "fx:controller="view.View" there is no need to do the setController in the actual code, is this statement not correct – Tanner Summers Dec 29 '15 at 18:17
  • @James_D is there another way of doing this? I can't find any good guide on how this all works so I am going off random post and guides =/ – Tanner Summers Dec 29 '15 at 18:18
  • 1
    @TannerSummers It looks like you are confusing "class" and "object". You need to understand the difference between the two. Just because you set the controller with `fx:controller` to the current class, it does not mean the controller is the current object. Similarly, if you create a new `View` instance in code, it is not the same object as the one the framework creates for you. I recommend stepping back and learning some Java basics before you try using something like a UI framework. – James_D Dec 29 '15 at 18:20
  • @james_D I understand, I am just a little frustrated with this at the moment, the object is the instance of the class, the class is like the blueprint or the specification is how I learned it, but for the sake of my sanity lol I would really like to alteast get this working before I start school again. I am understanding what you guys are telling me to some point but still a little lost on what exactly I need to do to fix it, what I am hearing is I am basically screwing up in two different spots, creating two different instances – Tanner Summers Dec 29 '15 at 18:25
  • It's not really clear to me what you're trying to do. JavaFX really already implements the MVP pattern for you, and you're somehow trying to recreate it. The FXML files are the views and the "controllers" you specify are their presenters. The `Application` subclass you write represents the entire application, and should be used just to start things up. Perhaps you can explain what you're actually trying to achieve. – James_D Dec 29 '15 at 18:28
  • @james_D I can honestly say I did not know that. I wanted a project for my resume, I had a GUI project that was pretty poorly designed but worked, I wanted to implement it using a pattern such as MVP to make it look more professional and since I had some experience with JavaFX and none with any other UI framework, I thought to use that but never did I think to look at javafx as a MVP pattern. – Tanner Summers Dec 29 '15 at 18:32
  • Maybe look at http://stackoverflow.com/questions/32342864/applying-mvc-with-javafx The OP asked about MVC but the presented solution is really MVP ("passive view"). – James_D Dec 29 '15 at 18:37
  • @james_D ok I will read this, thank you, but for this current situation, do you think I should try to fix this or just restart using the controllers as the presenters, fxml files as the views and I implement the rest? since if what your saying is i am doing mvp in an already mvp setting, I will just be making things a lot harder for myself. There is more to this project then what was posted, and I rather not waste all that work you know – Tanner Summers Dec 29 '15 at 18:40
  • Can't honestly advise you more on that without substantially more information. I always start with the model, then generate view-presenter (i.e. fxml-controller) pairs, etc. In a large application, you might end up with more structure, e.g. nested views, etc. So (simple example) you might have a model which just represents the current user and if they are authenticated. Have a presenter that observes that state and updates with a login screen if not authenticated and a chat screen if authenticated. The login has view-presenter and the chat has view-presenter etc. – James_D Dec 29 '15 at 18:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99239/discussion-between-tanner-summers-and-james-d). – Tanner Summers Dec 29 '15 at 18:49

0 Answers0