0

I'm currently coding an instant messenger app. I started with a basic client/server setup which is functioning correctly. However, when I launch the Client () class from Login.java (after first running Server.java), the JFrame appears, but completely blank, i.e. the elements such as the conversation panel, user text input field etc. are not present. This is bizarre, because the server indicates that the Client has connected, but I cannot type/see anything in the Client form.

If I launch the Server and connect the client directly (i.e. without launching it from Login.java) both the client and server function perfectly and can converse together.

Strangely, when I launch Client.java from Login.java without the server running, the window appears as it should with elements intact (but obviously unusable since it is not connected to the server). Furthermore, when I close Server.Java, Client.Java reverts to displaying all elements, but again is unusable without the server connection.

Any help is greatly appreciated. Thanks.

Login.Java:

import java.awt.*;//contains layouts, buttons etc.
import java.awt.event.*; //contains actionListener, mouseListener etc.
import javax.swing.*; //allows GUI elements

public class Login extends JFrame implements ActionListener, KeyListener {
    private JLabel usernameLabel = new JLabel("Username/Email:");
    private JLabel userPasswordLabel = new JLabel("Password:");
    public JTextField usernameField = new JTextField();
    private JPasswordField userPasswordField = new JPasswordField();
    private JLabel status = new JLabel("Status: Not yet logged in.");
    private JButton loginButton = new JButton("Login");
    private JButton registerButton = new JButton("New User");

    public Login() {
        super("Please Enter Your Login Details...");//titlebar
        setVisible(true);
        setSize(400, 250);
        this.setLocationRelativeTo(null); //places frame in center of screen
        this.setResizable(false); //disables resizing of frame
        this.setLayout(null); //allows me to manually define layout of text fields etc.
        ImageIcon icon = new ImageIcon("bin/mm.png");
        JLabel label = new JLabel(icon);
        this.add(usernameLabel);
        this.add(userPasswordLabel);
        this.add(usernameField);
        this.add(userPasswordField);
        this.add(loginButton);
        this.add(registerButton);
        this.add(status);
        this.add(label);
        label.setBounds(0, 0, 400, 70);
        usernameLabel.setBounds(30, 90, 120, 30); //(10, 60, 120, 20);
        userPasswordLabel.setBounds(30, 115, 80, 30);//(10, 85, 80, 20);
        usernameField.setBounds(150, 90, 220, 30);
        userPasswordField.setBounds(150, 115, 220, 30);
        loginButton.setBounds(150, 160, 110, 25);
        registerButton.setBounds(260, 160, 110, 25);
        status.setBounds(30, 190, 280, 30);
        status.setForeground(new Color(50, 0, 255)); //sets text colour to blue
        loginButton.addActionListener(this);
        registerButton.addActionListener(this);
        registerButton.setEnabled(false);
        userPasswordField.addKeyListener(this);
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == loginButton) {
            String userName = usernameField.getText();
            String password = userPasswordField.getText();
            if (userName.equals("mick") && password.equals("mick")) {
                status.setText("Status: Logged in.");
                this.setVisible(false);
                new Client("127.0.0.1").startRunning();
            } else {
                status.setText("Status: Password or username is incorrect.");
                status.setForeground(new Color(255, 0, 0)); //changes text colour to red
            }
        }
    }
}

Client.java:

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Date; //timestamp functionality

import javax.swing.*;

public class Client extends JFrame { //inherits from JFrame
        //1. Creating instance variables
    private JTextField userText; //where user inputs text
    private JTextArea chatWindow; //where messages are displayed
    private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
    //fullTimeStamp - MM = months; mm = minutes; HH = 24-hour cloc
    private ObjectOutputStream output; //output from Client to Server
    private ObjectInputStream input; //messages received from Server
    private String message = "";
    private String serverIP;
    private Socket connection;

    //2. Constructor (GUI)
    public Client(String host) { //host=IP address of server
        super("Mick's Instant Messenger [CLIENT]");
        serverIP = host; //placed here to allow access to private String ServerIP
        userText = new JTextField();
        userText.setEditable(false);
        userText.addActionListener(
                new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        sendMessage(event.getActionCommand()); //For this to work, must build sendData Method
                        userText.setText(""); //resets userText back to blank, after message has been sent to allow new message(s)
                    }
                }
        );
        add(userText, BorderLayout.SOUTH);
        chatWindow = new JTextArea();
        add(new JScrollPane(chatWindow), BorderLayout.CENTER); //allows you to scroll up and down when text outgrows chatWindow
        chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
        chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
        setSize(400, 320);
        this.setLocationRelativeTo(null); //places frame in center of screen
        setVisible(true);
    }

    //3. startRunning method
    public void startRunning() {
        try {
            connectToServer(); //unlike Server, no need to wait for connections. This connects to one specific Server.
            setupStreams();
            whileChatting();
        } catch (EOFException eofException) {
            //Display timestamp for disconnection
            showMessage("\n\n" + fullTimeStamp);
            showMessage("\nConnection terminated by CLIENT! ");
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } finally {
            closeCrap();
        }
    }

    //4. Connect to Server
    void connectToServer() throws IOException {
        showMessage(" \n Attempting connection to SERVER... \n");
        connection = new Socket(InetAddress.getByName(serverIP), 6789);//Server IP can be added later
        showMessage(" Connected to: " + connection.getInetAddress().getHostName()); //displays IP Address of Server
    }

    //5. Setup streams to send and receive messages
    private void setupStreams() throws IOException {
        output = new ObjectOutputStream(connection.getOutputStream());
        output.flush();
        input = new ObjectInputStream(connection.getInputStream());
        showMessage("\n Streams are now setup! \n");
    }

    //6. While chatting method
    private void whileChatting() throws IOException {
        //Display timestamp for connection
        showMessage("\n" + fullTimeStamp);
        ableToType(true);
        String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
        do {
            try {
                message = (String) input.readObject(); //read input, treat as String, store in message variable
                showMessage("\n" + message);
            } catch (ClassNotFoundException classNotfoundException) {
                showMessage("\n I don't know that object type");
            }
            //***broken by timestamp?***    
        } while (!message.equalsIgnoreCase("SERVER " + "[" + timeStamp + "]" + ": " + "END")); //Conversation happens until Server inputs 'End'

    }

    //7. Close the streams and sockets
    private void closeCrap() {
        showMessage("\n\nClosing streams and sockets...");
        ableToType(false);//disable typing feature when closing streams and sockets
        try {
            output.close();
            input.close();
            connection.close();
        } catch (IOException ioException) {
            ioException.printStackTrace(); //show error messages or exceptions
        }
    }

    //8. Send Messages to Server
    private void sendMessage(String message) {
        try {
            String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
            output.writeObject("CLIENT" + " [" + timeStamp + "]" + ": " + message);
            output.flush();
            showMessage("\nCLIENT" + " [" + timeStamp + "]" + ": " + message);
        } catch (IOException ioexception) {
            chatWindow.append("\n Error: Message not sent!");
        }
    }

    //9.change/update chatWindow
    private void showMessage(final String m) {
        SwingUtilities.invokeLater(
                new Runnable() {
                    public void run() {
                        chatWindow.setEditable(false); //disallows text editing in chatWindow
                        chatWindow.append(m); //appends text, which was passed in from above
                    }
                }
        );
    }

    //10. Lets user type
    private void ableToType(final boolean tof) {
        SwingUtilities.invokeLater(
                new Runnable() {
                    public void run() {
                        userText.setEditable(tof); //passes in 'true'
                    }
                }
        );
    }
}
Naili
  • 1,564
  • 3
  • 20
  • 27
mickm
  • 281
  • 2
  • 6
  • 20

3 Answers3

0

Check this question that will help you show the Login JFrame (you will need to create that frame) from the main JFrame How to make a JFrame button open another JFrame class in Netbeans?

Community
  • 1
  • 1
csharpwinphonexaml
  • 3,659
  • 10
  • 32
  • 63
  • thanks for your response. I've built a login form in Eclipse (See code), but cannot implement the suggested approach. Please see edited post. – mickm Apr 07 '14 at 12:08
  • @user3029329 Sorry for missing one thing the Client constructor requires a host `public Client(String host)` so when you call `new Client()` you should do `new Client("host here")` – csharpwinphonexaml Apr 07 '14 at 12:16
  • Thanks. When i input "new Client().setVisible(true);" new Client() is red underlined, despite Client () being in the same package (Please see my source code). Compiler says "The constructor Client() is undefined". I can run the form, but when I click the button, the console gives the following error: Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problem: The constructor Client() is undefined at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341) . . . – mickm Apr 07 '14 at 12:20
  • Apologies, I'm not sure I understand your last comment. How would I implement your suggestion, in light of my attached code? Thanks. – mickm Apr 07 '14 at 12:27
  • @user3029329 How do you give the ip address to the client? – csharpwinphonexaml Apr 07 '14 at 12:30
  • Thank you. As I'm running it on my LocalHost, I'm using "127.0.0.1". I've just input 'newClient("127.0.0.1").setVisible true;' and a new Client window now shows up, but it is not functional, i.e. it doesn't connect to server, cannot send receive messages like it can when I launch Client.Java directly. – mickm Apr 07 '14 at 12:45
  • Is the Server running? Specify the problems – csharpwinphonexaml Apr 07 '14 at 12:46
  • Apologies. Yes, server is running. When I use launch 'Client.java' it connects normally with full functionality. However, when I launch 'Client.Java' from the login form, it does not connect to Server and there is no chat functionality. There is nothing displayed in the Client's text field and the option to input text is disabled (the default when no connection has occurred). – mickm Apr 07 '14 at 12:50
  • I attempted using 'new Client("127.0.0.1").startRunning();' instead. It now successfully makes a connection with the server, but no elements (no text, textFields etc.) are displayed in the Client window. – mickm Apr 07 '14 at 13:09
  • can you post the code you normally use to launch the Client? – csharpwinphonexaml Apr 07 '14 at 13:10
  • `import javax.swing.JFrame; public class ClientTest { public static void main(String[] args) { Client charlie; charlie = new Client("127.0.0.1"); //Server IP Address would be placed here, where not localhost. charlie.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //ensures process closes when 'X' is clicked charlie.startRunning(); } }` – mickm Apr 07 '14 at 13:36
  • It's probably something to do with thread. You should put the client object in a new thread. –  Apr 07 '14 at 22:47
0

Consider changing this code

@Override
public void actionPerformed(ActionEvent e) {
    this.setVisible(false);
    new Client().setVisible(true);

}

to this:

@Override
public void actionPerformed(ActionEvent e) {
    Client charlie = new Client("127.0.0.1"); //Server IP Address would be placed here, where not       
    localhost.charlie.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //ensures process closes when 'X' is clicked      
    charlie.setVisible(true);
    charlie.startRunning(); 
}
csharpwinphonexaml
  • 3,659
  • 10
  • 32
  • 63
  • Thanks again for all your help. I tried this, but again with the same result, i.e. Client successfully connects to Server (according to Server output), but Client is just a grey featureless window with no options. Strangely, this doesn't happen when I launch client directly. – mickm Apr 07 '14 at 13:51
0

Replace this

new Client("127.0.0.1").startRunning();

by

Thread t1 = new Thread(new Runnable() {
    public void run(){
        Client client = new Client("127.0.0.1");
        client.startRunning();
    }
});  
t1.start();
Naili
  • 1,564
  • 3
  • 20
  • 27
  • Thanks for your suggestion. I've tried this, but the same issue still exists. – mickm Apr 07 '14 at 22:48
  • You genius! It works with your new thread suggestion. Thank you so much. This issue has been annoying me all day!!! Can you explain why it worked? – mickm Apr 07 '14 at 22:52
  • You ran the client in the same thread than the GUI, which was the reason GUI was freezing (waiting on the client). –  Apr 07 '14 at 23:00
  • Aha.. I completely understand now. Thank you very much for teaching me something new. – mickm Apr 07 '14 at 23:03