[英]Gui freezes when using thread
I want my application to auto-refresh the content in the Vbox from the database. 我希望我的应用程序从数据库自动刷新Vbox中的内容。 I have started the thread in the initialize method.
我已经在initialize方法中启动了线程。 Why does my Gui freezes.
为什么我的桂冻结了。 Is there any better way to perform such threading operation for GUI refreshing.
有没有更好的方法来执行此类线程操作以进行GUI刷新。
package Messanger.ChatWindow;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.TextAlignment;
import Messanger.Login.Login;
import java.io.IOException;
import Messanger.Settings.Settings;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javax.swing.JOptionPane;
public class Controller implements Initializable {
Settings set = new Settings();
VBox msg_vbox = new VBox();
@FXML
ScrollPane scrlpane;
@FXML
TextField message;
protected Model md;
public Controller() throws SQLException {
this.md = new Model();
}
@FXML
protected void Settings() {
try {
set.loadView();
} catch (IOException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
}
@FXML
protected void Logout() throws IOException {
Login lgin = new Login();
lgin.loadView();
ChatWindow.cW.close();
}
protected synchronized void refreshContent() throws SQLException {
ResultSet messageArry = md.getMessages();
while (messageArry.next()) {
msg_vbox.getChildren().clear();
//new label text with message.
Label set_text = new Label();
set_text.setText(messageArry.getString("username") + " Says: \n" + messageArry.getString("message"));
set_text.setStyle("-fx-padding:10;"
+ "-fx-width:100%;"
+ "-fx-background-color:teal;"
+ " -fx-background-insets: 5;"
+ "-fx-font-size:15;"
+ "-fx-background-radius: 3;");
set_text.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
set_text.setWrapText(true);
set_text.setTextAlignment(TextAlignment.JUSTIFY);
set_text.setPrefWidth(600);
//VBox wrapper
msg_vbox.getChildren().addAll(set_text);
msg_vbox.setPrefWidth(600);
//Further wrapped by ScrollPane
scrlpane.fitToHeightProperty();
scrlpane.setContent(msg_vbox);
scrlpane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
scrlpane.vvalueProperty().bind(msg_vbox.heightProperty()); //sets the scroll view to new element.
}
}
@FXML
protected void sendMessage() {
//new label text with message.
Label set_text = new Label();
set_text.setText(Messanger.Login.Controller.SESSION_usrname + " Says: \n" + message.getText());
set_text.setStyle("-fx-padding:10;"
+ "-fx-width:100%;"
+ "-fx-background-color:teal;"
+ " -fx-background-insets: 5;"
+ "-fx-font-size:15;"
+ "-fx-background-radius: 3;");
set_text.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
set_text.setWrapText(true);
set_text.setTextAlignment(TextAlignment.JUSTIFY);
set_text.setPrefWidth(600);
//VBox wrapper
msg_vbox.getChildren().addAll(set_text);
msg_vbox.setPrefWidth(600);
//Further wrapped by ScrollPane
scrlpane.fitToHeightProperty();
scrlpane.setContent(msg_vbox);
scrlpane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
scrlpane.vvalueProperty().bind(msg_vbox.heightProperty()); //sets the scroll view to new element.
message.setText("");
}
@FXML
protected void check_key(KeyEvent ae) throws SQLException {
if (ae.getCode().equals(KeyCode.ENTER)) {
if (md.addMessage(Messanger.Login.Controller.SESSION_usrname, message.getText())) {
sendMessage();
} else {
JOptionPane.showMessageDialog(null, "Message Sending failed \n "
+ "Please Check Your Internet Connection", "Error ", JOptionPane.INFORMATION_MESSAGE);
}
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
scrlpane.setStyle("-fx-background:#32AED8");
scrlpane.setPrefHeight(300);
try {
refreshContent();
} catch (SQLException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
Service<Void> service = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
while (true) {
try {
refreshContent();
} catch (SQLException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("asd");
}
}
});
return null;
}
};
}
};
service.start();
}
}
As in the code i've started the thread and i want to run the refreshContent method. 如代码中所示,我已经启动线程,并且我想运行refreshContent方法。 I've also tried it implementing the Runnable interface.
我也尝试过实现Runnable接口。 But same problem occurs.
但是发生同样的问题。
You are creating a new thread. 您正在创建一个新线程。 However from this new thread you immediately post a
Runnable
to be run on the javaFX application thread that is handling the connection to the DB using a infinite loop, so you are blocking the application thread. 但是,从这个新线程中,您会立即发布一个
Runnable
,以便在使用无限循环处理与数据库的连接的javaFX应用程序线程上运行,因此您将阻塞应用程序线程。
To not block the application thread do the long-running parts of the task on a different thread, then use Platform.runLater
to update the UI. 为了不阻塞应用程序线程,请在另一个线程上执行长时间运行的任务,然后使用
Platform.runLater
更新UI。
Also you probably shouldn't initialize the rows in the result set loop... 同样,您可能不应该在结果集循环中初始化行...
private List<Node> refreshedContent() {
List<Node> result = new ArrayList<>();
ResultSet messageArry = md.getMessages();
while (messageArry.next()) {
// initialize nodes not yet attached to a scene
Label set_text = new Label();
set_text.setText(messageArry.getString("username") + " Says: \n" + messageArry.getString("message"));
set_text.setStyle("-fx-padding:10;"
+ "-fx-width:100%;"
+ "-fx-background-color:teal;"
+ " -fx-background-insets: 5;"
+ "-fx-font-size:15;"
+ "-fx-background-radius: 3;");
set_text.setPrefSize(600, Region.USE_COMPUTED_SIZE);
set_text.setWrapText(true);
set_text.setTextAlignment(TextAlignment.JUSTIFY);
result.add(set_text);
}
return result;
}
@Override
protected Void call() throws Exception {
while (true) {
// do long-running operation
List<Node> newContent = refreshedContent();
Platform.runLater(new Runnable() {
@Override
public void run() {
// there should be no need to do this over and over again
// you should move it outside of the task
msg_vbox.setPrefWidth(600);
//scrlpane.fitToHeightProperty(); // does nothing anyway...
scrlpane.setContent(msg_vbox);
scrlpane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
scrlpane.vvalueProperty().bind(msg_vbox.heightProperty()); //probably won't work the intended way...
// update ui
msg_vbox.getChildren().setAll(newContent);
}
});
// do more long-running operations
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("asd");
}
}
Furthermore: 此外:
ListView
ListView
ListView
would help in this case. ListView
会有所帮助。 If you do not want to use a ListView
you should try reusing existing Label
s as much as possible instead of replacing them with new instances... ListView
,则应尝试尽可能重用现有的Label
,而不是用新的实例替换它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.