我希望我的应用程序从数据库中自动刷新Vbox中的内容。我在initialize方法中启动了线程。为什么我的Gui冻结了。是否有更好的方法来执行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();
}
}
在代码中,我启动了线程,我想运行refreshContent方法。我也尝试过实现Runnable接口。但同样的问题也出现了。
答案 0 :(得分:1)
您正在创建新主题。但是,从这个新线程中,您立即发布Runnable
以在使用无限循环处理与DB连接的javaFX应用程序线程上运行,因此您将阻止应用程序线程。
要不阻止应用程序线程在另一个线程上执行任务的长时间运行部分,然后使用Platform.runLater
更新UI。
您也可能不应该初始化结果集循环中的行...
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");
}
}
此外:
ListView
ListView
会有所帮助。如果您不想使用ListView
,则应尝试尽可能多地重复使用现有Label
,而不是使用新实例替换它们......