如何使用ObservableList将文本追加到TextArea

时间:2019-03-25 17:01:22

标签: java multithreading javafx model-view-controller

我正在尝试实现交换消息的客户端服务器JavaFx应用程序。我试图从一个线程中将文本(服务器端)附加到TextArea上,该线程处理通过模型中放置的与控制器通信的方法传递的客户端请求。

例如: 在处理客户端请求的线程中,如果用户成功登录-> ,则调用模型中的方法setLogMessages(“ user login ..”),并设置我的observableList - > 将字符串发送到控制器,该控制器应将它们附加到TextArea。

我写了这段代码:

服务器型号

public class ServerModel {

        private ObservableList<String> observableLogMessages;

        //other code

        /**
        * This method starts the server connection.
        */
        public void startServerConnection() {
           serverRequests.serverConnection();
        }

        public void setLogMessages(String logMessage) {

          observableLogMessages = FXCollections.observableArrayList();
          ArrayList<String> messagesList = new ArrayList<>();
          messagesList.add(logMessage);
          observableLogMessages.setAll(messagesList);
        }

        public ObservableList<String> getLogMessages() {
            return observableLogMessages;
        }

        public void changeObserver(ListChangeListener<String>messagesChangeListener) {
           observableLogMessages.addListener(messagesChangeListener);
        }

// other code

}

服务器控制器

public class LogController {

private final ServerModel serverModel = ServerModel.builServerModel();

@FXML
private ResourceBundle resources;

@FXML
private URL location;

@FXML
private AnchorPane logAnchorPane;

@FXML
public TextArea logTextArea;

@FXML
private JFXButton logClearButton;

@FXML
void initialize() {
    logTextArea.setEditable(false);

    serverModel.changeObserver((ListChangeListener.Change<? extends String> messagesChange) -> {
        if (messagesChange.next() && messagesChange.wasAdded()) {
            ObservableList<String> logMessages = serverModel.getLogMessages();
            for (int i = 0; i < logMessages.size(); i++) {
                logTextArea.appendText(logMessages.get(i)); 
            }
        }
    });
}

}

处理客户请求的线程

public class ServerRequests {

   //other code 

   public void serverConnection() {
      ServerSocket serverSocket = null;

    try {
        //initialize the Server Socket class
        serverSocket = new ServerSocket(PORT);
    } catch (IOException e) {
        System.out.println("I/O error: " + e);
    }
    while (true) {
        System.out.println("waiting for clients...");
        try {
            clientSocket = serverSocket.accept(); 
            ClientRequest clientRequest = new ClientRequest(clientSocket);
            Runnable runnable = clientRequest;
            Thread thread = new Thread(runnable);
            thread.setDaemon(true);
            thread.start();

        } catch (IOException e) {
            System.out.println("I/O error: " + e);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ServerRequests.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

 public class ClientRequest extends Thread {
      // other code
      public ClientRequest(Socket socket) throws ClassNotFoundException {
             // other code
      }

 @Override
    public void run() {

      // if user successfully login add, this message to the TextArea.
      serverModel.setLogMessages("User successfully connected.");
    }
    // other code
  }
}

如果运行此代码,则显示消息“用户已成功连接”。 未添加到TextArea 中,并且我也尝试在模型中打印observableList大小,即使我尝试添加多个消息,该大小也始终为1。 我在这里阅读了许多类似的问题,并试图通过使用Platform.runLater()进行修复,但我的TextArea仍然没有任何反应,我不明白为什么!

更新

我试图在日志中添加一个按钮,只是为了查看单击是否返回一条消息。我发现我什至无法点击它,因为一切都卡住了(服务器端),它给我“ Java(TM)平台SE二进制文件已停止工作”的错误消息。是什么原因造成的?

enter image description here

LogController建议后更新

public class LogController {

//serverModel
ObservableList<String> logMessages;

@FXML
private AnchorPane logAnchorPane;

@FXML
private TextArea logTextArea;

@FXML
private Label serverLogLabel;

@FXML
private JFXButton logClearButton;

@FXML
void initialize() {
    logTextArea.setEditable(false);
    logTextArea.appendText("Appending");   //This append text correctly
    Platform.runLater(() -> {
        serverModel.changeObserver((ListChangeListener.Change<? extends String> messagesChange) -> {
            if (messagesChange.next() && messagesChange.wasAdded()) {
                ObservableList<String> logMessages = serverModel.getLogMessages();
                for (int i = 0; i < logMessages.size(); i++) {
                    logTextArea.appendText(logMessages.get(i));
                }
            }
        });
    });
    logClearButton.setOnAction((ActionEvent event) -> {
        System.out.println("Clear clicked");
    });

}

}

仍然无法在TextArea上打印,并且仍然在打开时卡住,并且显示“ Java(TM)平台SE二进制文件已停止工作”错误消息。

1 个答案:

答案 0 :(得分:1)

我可能注意到的一个可能的问题是,您每次都会为新消息创建一个新的可观察列表,并使用setAll将列表设置为您的observableList。因此,通过此实现,您永远不可能使observableList包含超过1个项目。

您需要在外部创建observableList实例,并使用addAll()或将消息直接添加到observableList。

private ObservableList<String> observableLogMessages = FXCollections.observableArrayList();    
public void setLogMessages(String logMessage) {
       ArrayList<String> messagesList = new ArrayList<>();
       messagesList.add(logMessage);
       observableLogMessages.addAll(messagesList);
    }

private ObservableList<String> observableLogMessages = FXCollections.observableArrayList();
public void setLogMessages(String logMessage) {
   observableLogMessages.add(logMessage);
}