【发布时间】:2019-03-25 17:01:22
【问题描述】:
我正在尝试实现一个交换消息的客户端-服务器 JavaFx 应用程序。我正在尝试将文本(服务器端)从处理客户端请求的线程附加到 TextArea,该线程通过放置在与控制器通信的模型中的方法传递客户端请求。
例如: 在处理客户端请求的线程中,如果用户成功登录 --> 我调用模型中的方法 setLogMessages("user logged in.") 并设置我的 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) Platform SE 二进制文件已停止工作”错误消息。这是什么原因造成的?
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) Platform SE 二进制文件已停止工作”错误消息。
【问题讨论】:
-
您不得从 fx 应用程序线程更改场景图中的任何内容:在您的特定上下文中,将侦听器中区域中的文本更新到已更改的日志列表在后台线程上。将该设置包装到 Platform.runlater() 应该可以工作
-
@kleopatra 你在说哪个设置? logTextArea.appendText(logMessages.get(i));或 serverModel.setLogMessages("用户连接成功。"); ?我尝试在 Platform.RunLater 中添加 LogController 的所有 serverModel.changeObserver() 但仍然无法正常工作。你能给我一个例子吗?也许我以错误的方式使用 Platform.runLater()。
-
日志消息列表中只有一个 ListChangeListener .. ;)
-
更改您的示例 - 并确保它是 minimal reproducible example
-
错了——你不必包装监听器的注册,而是监听器更新 textArea 的行
标签: java multithreading javafx model-view-controller