1

I'm currently trying to build a Client-Server application with a login and logout function. In LoginViewController I'm creating a client-object. I want to be able to use this very object in ClientViewController, e.g. for logout. How can I pass this object from LoginViewController to ClientViewController? Since the login was successfull I dont want to instantiate a new object, I want to use the object which passed the login and is currently active on the server-side.

How can this be achieved?


Main.java

public class Main extends Application {
    private static Stage primaryStage;
    private static BorderPane mainLayout;

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        showLoginView();
    }

    public static void showLoginView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("LoginView.fxml"));
        mainLayout = loader.load();
        Scene scene = new Scene(mainLayout, 540, 400);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    public static void showClientView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("ClientView.fxml"));
        mainLayout = loader.load();
        Scene scene = new Scene(mainLayout, 900, 600);
        primaryStage.setScene(scene);
        primaryStage.setResizable(true);
        primaryStage.show();
    }
}

LoginViewController.java

public class LoginViewController implements Initializable {
    @FXML
    private Main main;
    @FXML
    private TextField username;
    @FXML
    private PasswordField password;
    @FXML
    private Button login;
    @FXML
    private Button register;

    private Client client;

    private Login userLogin;

    private String loginStatus;

    @FXML
    private Label loginInfo;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        loginInfo.setVisible(false);
    }

    @FXML
    public void login() throws IOException {
        loginStatus = "timeout";
        loginInfo.setVisible(false);
        client = new Client("127.0.0.1", 3250, this); // Client object created
        userLogin = new Login(username.getText(), password.getText());
        client.setOnConnected(() -> client.sendToServer(userLogin));
        client.start();
        int waitForLoginStatusCounter = 0;
        while(loginStatus.equals("timeout")) {
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            waitForLoginStatusCounter++;
            if(waitForLoginStatusCounter >= 20) {
                break;
            }
        }
        if(loginStatus.equals("success")) {
            main.showClientView();
        }
        else if(loginStatus.equals("failed")) {
            loginInfo.setVisible(true);
            loginInfo.setText("Login failed: Wrong username or password");
        }
        else {
            loginInfo.setVisible(true);
            loginInfo.setText("Timeout: Check connection");
        }
    }

    public String getLoginStatus() {
        return loginStatus;
    }

    public void setLoginStatus(String loginStatus) {
        this.loginStatus = loginStatus;
    }
}

ClientViewController.java

public class ClientViewController implements Initializable {

    @FXML
    private Main main;
    @FXML
    private TreeView<String> treeview;
    @FXML
    private Button logout;

    private Client client;

    private String username;

    private Logout userLogout;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    }

    @FXML
    public void logout() throws IOException {
        userLogout = new Logout(username);
        client.sendToServer(userLogout); // Null at this point
        main.showLoginView();
    }
}

Client.java (sends and receives objects from server)

public class Client extends Thread {
    private String ip;
    private int port;
    private Socket socket;
    private ObjectOutputStream oos;
    private ObjectInputStream ois;
    private Runnable onConnected;
    private LoginViewController lvc;
    private RegisterViewController rvc;

    public void setOnConnected(Runnable onConnected) {
        this.onConnected = onConnected;
    }

    public Client(String ip, int port, LoginViewController lvc) {
        this.ip = ip;
        this.port = port;
        this.lvc = lvc;
    }

    public Client(String ip, int port, RegisterViewController rvc) {
        this.ip = ip;
        this.port = port;
        this.rvc = rvc;
    }

    public void run() {
        try {
            socket = new Socket(ip, port);
            oos = new ObjectOutputStream(socket.getOutputStream());
            ois = new ObjectInputStream(socket.getInputStream());
            if(onConnected != null) {
                onConnected.run();
            }
            while (true) {
                try {
                    Object obj = ois.readObject();
                    if (obj instanceof Login) {
                        String loginStatus = ((Login) obj).getLoginStatus();
                        lvc.setLoginStatus(loginStatus);
                    }
                    else if(obj instanceof Register) {
                        String registerStatus = ((Register) obj).getRegisterStatus();
                        rvc.setRegisterStatus(registerStatus);
                    }
                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendToServer(Object obj) {
        try {
            oos.writeObject(obj);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Slamdunk
  • 424
  • 1
  • 8
  • 20
  • I think that this is what you are looking for http://stackoverflow.com/questions/12166786/multiple-fxml-with-controllers-share-object – FilipRistic Apr 15 '17 at 18:15
  • That problem seems to be similar to mine, though I cant grasp how to implement this solution with my code. Traditionally I would have passed the client-object when constructing the ClientViewController. But since this is JavaFX, I cant do it like that. – Slamdunk Apr 15 '17 at 20:20

1 Answers1

2

Problem solved after implementing the following code:

LoginViewController.java

    if(loginStatus.equals("success")) {
        main.showClientView(client); // Passing the client-object to showClientView method
    }

Main.java

public static void showClientView(Client client) throws IOException { // Taking the client-object as an argument from LoginViewController
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(Main.class.getResource("ClientView.fxml"));
    mainLayout = loader.load();

    ClientViewController cvc = loader.getController(); // This did the "trick"
    cvc.setClient(client); // Passing the client-object to the ClientViewController

    Scene scene = new Scene(mainLayout, 900, 600);
    primaryStage.setScene(scene);
    primaryStage.setResizable(true);
    primaryStage.show();
}

ClientViewController.java

public void setClient(Client client) { // Setting the client-object in ClientViewController
    this.client = client;
}
Slamdunk
  • 424
  • 1
  • 8
  • 20
  • does it good practice in javafx . because we can pass object through constructor of controller as well? and for better readability prospective which is better ? – mcd Jul 07 '17 at 04:53