java 使用线程和/或任务更新 JavaFx Gui
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12860896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Updating the JavaFx Gui with threads and or Tasks
提问by Marc Rasmussen
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.
我正在创建一个聊天程序,其中包含我在新版本的 JavaFx 场景构建器中创建的 GUI。我有一个扩展应用程序的主要方法,我的 GUI 中有一个 simpleController(控制所有按钮、标签、anchorPanes 等)。
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!
- 1 - 请求连接权限,同时请求用户ID(服务器找出有多少用户在线并添加ID+1)
- 2 - 聊天,客户端发送一个 ID 和一个字符串消息(例如:21
Hello(注意所有这些都在单独的行上)) - 3 - 断开客户端。
- 4 - 显示所有在线客户端的列表。
- 5 - 询问还有谁在线(这仅在用户连接时使用,他需要知道有多少用户在线才能更新 GUI)。
- 10 - 各种错误,如果服务器返回 10 消息,则意味着客户端刚刚执行的调用是错误的或者无法
完成!
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.
我不知道如何在使用线程时更新我的 GUI。我试图阅读 Task 类,但我无法看到是否应该使用它而不是线程或线程应该将它作为参数。
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?
我应该创建一个新类来侦听输入并使该类扩展线程吗? 或者
线程是否应该在我的 simpleController 类中运行?
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. :(
我真的很抱歉代码有点乱。简单控制器中的 run() 方法试图创建 simpleController 的线程。然而,这并没有像我预期的那样工作。:(
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.
这样做的主要目的基本上是确保聊天室中的两个人可以一起聊天。所以,它所要做的就是更新 1 或 2 个文本区域。
采纳答案by BAR
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
Bean 属性如
DoubleProperty
Which are thread safe.
哪些是线程安全的。
回答by Pronob
Please check this out if you have not done that already
如果您还没有这样做,请检查一下
回答by Mike Karrys
This took me a little time to find so I thought I would document it here.
这花了我一点时间才找到,所以我想我会在这里记录下来。
Platform.runLater(new Runnable(){
@Override
public void run() {
// Update your GUI here.
}
});
回答by O.Badr
If you're using Java 8 :
如果您使用的是 Java 8:
Platform.runLater(() -> {
// Update your GUI here.;
});