2012-10-12 41 views
1

我正在创建一个聊天程序,其中包含一个在新版本的“JavaFx场景”构建器中创建的GUI。我有一个扩展应用程序的主要方法,我有一个simpleController(控制所有按钮,标签,anchorPanes等)在我的GUI。使用线程和/或任务更新JavaFx GUI

除此之外,我有一个可以接收和发送消息的服务器应用程序。为了这个目的,我已经创建了下面的简单的协议:

命令/描述:

  • 1 - 请求许可连接,并在同一时间,询问用户 ID(服务器找出有多少用户在线,并添加了ID + 1)
  • 2 - 聊天,客户端发送一个ID和一个字符串消息(例如:21
    你好(注意所有这些都在一个单独的行))
  • 3 - 断开客户端连接。
  • 4 - 显示所有在线客户的列表。
  • 5 - 询问还有谁在线(仅当用户连接 时才会使用此功能,并且他需要知道有多少用户在线,以便 更新GUI)。
  • 10 - 如果服务器返回10条消息,则意味着 客户刚刚做的这个调用是错误或者它不能完成

使用这个简单的逻辑,我应该很容易让用户连接,聊天和断开连接。然而事实证明,本来应该是一项简单的任务已经成为我最糟糕的噩梦。

到目前为止,我的用户没有问题连接到程序,更多的用户可以同时连接。

事情开始变得棘手时,我想在服务器和客户端之间发送和接收消息。

我不知道如何在使用线程时更新我的​​GUI。我已经尝试了解Task类,但我无法看到这是应该用来代替线程还是线程应该将此作为参数

我应该创建一个新的类来侦听输入并使该类扩展线程吗?
该线程是否应该在我的simpleController类中运行?

主要

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; 
      } 
     } 
    } 

} 

客户

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(); 
    } 

}* 

我对真的很抱歉代码有点混乱。简单控制器中的run()方法试图创建simpleController的一个线程。然而,这并没有像我预期的那样工作。 :(

这样做的主要目的是基本上确保了两个人在聊天室可以聊天在一起。所以,所有它做的是更新1或2个文本域。

回答

1

这是旧的,但因为它是那里在谷歌,我想指出,最好的办法是使用

FXObservableList 

Bean的属性,如

DoubleProperty 

哪些是线程安全的。

2

这花了我一点点时间来找到,所以我想我会在这里记录了。

Platform.runLater(new Runnable(){ 
@Override 
public void run() { 
// Update your GUI here. 
} 
}); 
0

如果您使用的是Java 8:

Platform.runLater(() -> { 
      // Update your GUI here.; 
     });