Ahmed M. Hassan
Ahmed M. Hassan

Reputation: 1286

Exception in Application constructor - Cannot Start a Class

**I'm unable to create a constructor from "GUIController".. The program runs if i delete this line "GUIController(){myModel = new TheModel(this)" but i still need it in other part. Please help!

**

package theclient;

import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;


public class GUIController extends Application {

    TheModel myModel;

    GUIController(){
        myModel = new TheModel(this);
    }

    //public void init(){}

    public TextArea myTextArea;
    public TextField myTextField;

    // Button and text field actions
    public void myButtonAction() {
        sendMsg();
    }

    public void myTextFieldAction() {
        sendMsg();
    }

    // Append coming message
    public void displayMsg(String comingMSG) {
        System.out.println("Receive 01");
        myTextArea.appendText(comingMSG);
    }

    public void sendMsg() {
        try {
            System.out.println("Send 01");
            myModel.myChatServer.tellOthers(myTextField.getText());
        } catch (RemoteException ex) {
            Logger.getLogger(GUIController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("GUI.fxml"));

        Scene scene = new Scene(root, 600, 400);

        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
    }

    public static void main(String[] args) throws Exception {
        new GUIController();
        launch(args);
    }
}

The Second class. I'd be thankful if you can suggest any edits to the code. Thanks in advance for your efforts.

package theclient;

import common.ChatServerInt;
import common.ClientInt;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TheModel implements ClientInt {

    public GUIController myCtrl;
    ChatServerInt myChatServer;

    TheModel(GUIController myCtrl) {
        this.myCtrl = myCtrl;
    }

    public ChatServerInt connection() {
        if (myChatServer == null) {
            try {
                Registry reg = LocateRegistry.getRegistry(1111);
                myChatServer = (ChatServerInt) reg.lookup("ChatService");
                myChatServer.register(this);
                myChatServer.tellOthers("I'm here!");
            } catch (RemoteException | NotBoundException ex) {
                Logger.getLogger(TheModel.class.getName()).log(Level.SEVERE, null, ex);
            }
        } return myChatServer;
    }

    @Override
    public void receive(String msg) throws RemoteException {
        myCtrl.displayMsg(msg);
    }
}

Upvotes: 0

Views: 71

Answers (1)

mlinkus
mlinkus

Reputation: 89

Following the Model-view-controller design pattern, the model shouldn't be holding a reference to its controller. If the controller needs to respond to changes in the model's data, then this can be done with properties and listeners. The model holds a property (here, a StringProperty) and the controller listens for changes to the property.

For your code, this means storing the msg in a StringProperty. The controller, after constructing the model, attaches a ChangeListener that calls displayMsg when the model receives a message.

Using a property and listener, TheModel no longer stores a reference to GUIController and does not take a GUIController as a parameter in its constructor.

GUIController would look something like this:

public class GUIController extends Application {
 ...
TheModel myModel;
 ...
GUIController(){
    myModel = new TheModel();
    // Listen for changes in the msg StringProperty and call displayMessage when it changes
    myModel.getMsgProperty().addListener(msg -> this.displayMsg(msg));
}
 ...

Note that the constructor for GUIController no longer needs to pass this to the constructor TheModel. (In general, avoid passing this outside of the constructor. An object is not fully constructed until the constructor returns.)

TheModel would look something like this:

public class TheModel implements ClientInt {
 ...
private StringProperty msgProperty;
 ...
//  remember to add a getter and setter for msgProperty!
 ...
@Override
public void receive(String msg) throws RemoteException {
    // When a message is received, listeners attached to msgProperty will execute when setValue is called
    msgProperty.setValue(msg);
}

Upvotes: 2

Related Questions