I am creating a chat program that contains a GUI that I have created in the new version of the JavaFx Scene builder. I have a main method that extends application and i have a simpleController (that controls all the buttons, labels, anchorPanes, etc) in my GUI.
Other than that, I have a server application that can receive and send messages. For this purpose, I have created the following simple protocol:
Commands / Description:
- 1 – Ask for permission to connect and at the same time, ask for a user ID (server finds out how many users are online and adds the id+1)
- 2 – Chat, the client sends an ID and a String message (Example: 21
Hello (note all of these are on a separate line)) - 3 – Disconnects the client.
- 4 – Shows a list of all the clients online.
- 5 – Ask who else is online (this is only used when a user is connecting and he needs to know how many users are online in order to update the GUI).
- 10 – Error of all sorts if the server returns the 10 message it means
that the call the client just did was an error or that it could not
be completed!
Using this simple logic, it should be fairly easy for me to make users connect, chat and disconnect. However, it turned out that what should have been a simple task has turned out to be my worst nightmare.
So far my users has no problem connecting to the program and more users can connect at the same time.
Where things start to get tricky is when I want to send and receive messages between server and client.
I do not know how I can update my GUI while using a thread. I have tried to read up on the Task class, but I am unable to see whether this should be used instead of a thread or the thread should have this as a parameter.
Should I create a new class that listens for input and make that class extend thread? OR
Should the thread be running in my simpleController class?
Main
public class Main extends Application{ public static void main(String[] args) throws IOException{ Application.launch(Main.class, (java.lang.String[]) null); } @Override public void start(Stage primaryStage) throws Exception { try { AnchorPane page = (AnchorPane) FXMLLoader.load(Main.class.getResource("testingBackground.fxml")); Scene scene = new Scene(page); primaryStage.setScene(scene); primaryStage.setTitle("Chatten"); primaryStage.show(); } catch (Exception ex) { java.util.logging.Logger.getLogger(Main.class.getName()).log( java.util.logging.Level.SEVERE, null, ex); } } }
simpleController
import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Scanner; import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; import com.sun.glass.ui.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.concurrent.Task; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.text.Text; /* * evt ret array listen med commands da jeg selv kan styre hvilke commands der kommer ind og ud! og brugeren faktisk * aldrig selv kan vælge! */ public class SimpleController extends Thread implements Initializable{ public Button btn_Connect; public AnchorPane pictureFrame; public Socket socket = new Socket(); public PrintWriter pw; public Scanner input; public int clientId = 1; public Client client = new Client(socket, pw, input, clientId); // options! public TextField txt_userName; public TextField textField_chat; // send button public Button Send; /* * current client that the user i connected with, this client is used to send commands and tell other clients who is connected on * what "ingame chat persons" */ public static int currentClientId; // chatperson username public Label lbl_userName2; public Label lbl_userName3; public Label lbl_chatPerson2; public Label lbl_Chatperson1_userName; //Pictures of chat person public Label chatPerson3; public Label chatPerson1; // chat persons textfield public TextArea txt_ChatPerson1; //public TextField txt_ChatPerson1; public TextField txt_ChatPerson2; public TextField txt_ChatPerson3; @Override public void initialize(URL location, ResourceBundle resources) throws NullPointerException { try { client.connect(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } pictureFrame.setMaxSize(409, 373); txt_ChatPerson1.setMinWidth(50); txt_ChatPerson1.setPrefWidth(50); txt_ChatPerson1.setMaxWidth(300); txt_ChatPerson1.setText(" "); btn_Connect.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) throws NullPointerException { connectMeWithOthers(1); } }); Send.setOnAction(new EventHandler<ActionEvent>() { // WORK IN PROGReSS!! @Override public void handle(ActionEvent event) { /* * new line code: */ String x = textField_chat.getText(); txt_ChatPerson1.setText(x); txt_ChatPerson1.setVisible(true); System.out.println("x" +x); txt_ChatPerson1.textProperty().addListener(new ChangeListener<String>() { @Override public void changed( ObservableValue<? extends String> observable, String oldValue, String newValue) { // txt_ChatPerson1.setPrefRowCount(5); txt_ChatPerson1.setPrefWidth(txt_ChatPerson1.getText().length()*7); //txt_ChatPerson1.setPrefHeight(txt_ChatPerson1.getText().length()*3); } }); txt_ChatPerson1.autosize(); client.SendChat(x); } }); } /** * this method connect the client to the other clients who are online on the server! * the method calls it self after the user has established connection in order to load the other chat persons online * if the client is the online user online then it will only load the user * @param id */ protected void connectMeWithOthers(int id) { try { int responseId = client.sendCommando(id); System.out.println(" response id "+responseId); // finds whom is connected and tries to connect to a spot that is avalibul! //Response is the ID of the chat persons switch (responseId) { case 1: currentClientId = client.reciveCommando(); client.setClientId(currentClientId); client.sendString(txt_userName.getText()); connectMeWithOthers(5); break; case 5: int times = client.reciveCommando(); int o = 0; System.out.println("times: "+times); while (o != times) { int j = client.reciveCommando(); System.out.println("j"+ j); String name = client.reciveString(); System.out.println("Name " +name); createUser(j, name); o++; } start(); break; case 10: System.out.println("Connection fail chat room is full! Please try again later!"); case 8: start(); break; default: break; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void createUser(int j, String reciveChat) { if (j == 1) { chatPerson1.setVisible(true); lbl_Chatperson1_userName.setVisible(true); lbl_Chatperson1_userName.setText(reciveChat); }else if (j == 2) { lbl_chatPerson2.setVisible(true); lbl_userName2.setVisible(true); lbl_userName2.setText(reciveChat); }else if (j == 3){ chatPerson3.setVisible(true); lbl_userName3.setVisible(true); lbl_userName3.setText(reciveChat); }else { Image img = new Image(getClass().getResourceAsStream("Figur.png")); Label test2 = new Label("", new ImageView(img)); test2.setLayoutX(50); test2.setLayoutY(30); test2.setPrefSize(1000, 1000); pictureFrame.getChildren().addAll(test2); test2.setVisible(true); } } /* * denne metode er en rewrite af run metoden. */ public void StartClient(){ ClientListner cl = new ClientListner(client); Task task = new Task<String>() { @Override protected String call() throws Exception { // TODO Auto-generated method stub return null; } }; Thread t = new Thread(task); cl.start(); while (true) { if (cl.recived) { } } } /* * Run metoden er brugt til at recive data fra andre users og update GUI'en skal muligvis rewrites!? * */ public void run(){ System.out.println("Thread started"); System.out.println(client.getSocket().isConnected()); ClientListner cl = new ClientListner(client); while (client.getSocket().isConnected()) { int key = 10; if (cl.recived) { try { key = client.reciveCommando(); System.out.println("jeg er her"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("Key "+key); switch (key) { // case 2 er recive chat: case 2: // først find ud af hvilket ID der har sendt chatten: int y = 0; try { y = client.reciveCommando(); System.out.println("y" + y); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // derefter få beskeden og send den så ud til resten. String says = client.reciveChat().toString(); if (y == 1) { txt_ChatPerson1.setText(client.reciveChat()); }else if (y == 2) { }else { chatPerson3.setVisible(true); txt_ChatPerson3.setVisible(true); txt_ChatPerson3.setText(client.reciveChat()); } break; default: break; } } } }
Client
import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.util.Scanner; public class Client { // disse var static public final static int portNumber = 6040; public Socket socket; private PrintWriter pw; private Scanner input; private int clientId; /** * @param args * @throws IOException */ public Client(Socket socket, PrintWriter pw, Scanner input, int clientId){ this.socket = socket; this.pw = pw; this.input = input; this.clientId = clientId; } public void connect() throws IOException{ // du kan vælge at bruge inetadressen til at connecte i socketet. InetAddress adr = InetAddress.getByName("localhost"); socket = new Socket("localhost", portNumber); input=new Scanner(socket.getInputStream()); pw = new PrintWriter(socket.getOutputStream()); } /** * This method sends the message (that the client(chat person) writes to the user) * @param x * @throws NullPointerException * @throws IOException */ public void SendChat(String x) throws NullPointerException{ pw.println(2); pw.flush(); pw.println(SimpleController.currentClientId); pw.flush(); pw.println(x); pw.flush(); } public int sendCommando(int id) throws IOException{ System.out.println("Jeg sender"+ id); pw.println(id); pw.flush(); /* * this part of the program sends a command to the server if the command is 1 then 1 is = Connect. * the program then ask the server is the server is full or is it ok to connect? * if the response is not 10 then the program will allow a connection to happen the return type will be the Id of which * the chat person becomes! */ // should the method return 0 the Application will do NOTHING! switch (id) { case 1: int k = reciveCommando(); if (k== 10) { return 10; }else if (k < 3) { System.out.println("returned k" + k); return k; }else { return 10; } /* * Closes the connection with the server! */ case 3: socket.close(); return 0; case 5: int y = reciveCommando(); return y; default: return 0; } } /* * this method recives a command from the server! the comands can be found in the ChatCommands.txt * returns the command as an integer! */ public int reciveCommando() throws IOException{ Integer i = input.nextInt(); return i; } /** * Gets a String response from the server. This method i used to create other users and give them the correct username. * * @param i * @return * @throws IOException */ public String getStringResponse(int i) throws IOException { pw.print(i); pw.flush(); String x = input.nextLine(); return x; } /* * Work in progress - client getter og setter methoder! */ public Socket getSocket(){ return socket; } public Scanner getInput(){ return input; } public PrintWriter getPw(){ return pw; } public int getClientId(){ return clientId; } public void setClientId(int i ){ clientId = i; } public String reciveChat(){ String x = getInput().next(); return x; } public String reciveString(){ String x =input.next(); return x; } public void sendString(String x){ pw.println(x); pw.flush(); } }*
I am really sorry about the code being kind of messy. The run() method in the simple controller was an attempt to make a thread of the simpleController. However, this did not work as I expected. 🙁
The main goal of this is basically to make sure that the two people in the chat room can chat together. So, all it has to do is update 1 or 2 textareas.
Advertisement
Answer
This is old but since it was up there in google I would like to point out your best bet is to use
FXObservableList
or
Bean Properties like
DoubleProperty
Which are thread safe.