gpt4 book ai didi

java - 如何在 javaFX 中将光标更改为 WAIT 的同时线程化后台任务?

转载 作者:行者123 更新时间:2023-12-01 21:19:08 24 4
gpt4 key购买 nike

我有一个应用程序,在登录时通过接口(interface)类访问数据库。登录过程导致应用程序在访问数据库时一段时间内没有响应,因此我一直在研究线程和等待游标以使其顺利运行。我尝试通过网络上的许多示例和堆栈溢出来使用线程,但我的方法似乎不起作用,我收到 java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4 异常,我不确定如何从这里继续。我试图做的是在后台线程运行 loginLoadEverything() 方法时将光标更改为 WAIT 模式(尽管我没有在其中包含代码,因为它太长了)。这是我的 Controller 类:

package main.java.gui;

import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import main.java.databaseInterface.BackendInterface;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.CountDownLatch;

public class LoginController implements Initializable {


private BackendInterface backendInterface;
private DashboardController dashboardController;
private StudentsController studentsController;
private ConsultationController consultationController;
private CreateStudentController createStudentController;
private CreateConsultationController createConsultationController;

@FXML
TextField username;

@FXML
PasswordField password;

@FXML
Button loginButton;

@FXML
Label loginLabel;

@FXML
public void loginButtonPress(ActionEvent event) {

Service<Void> service = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {

loginLoadEverything();

final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
@Override
public void run() {
try {

Scene s1 = loginLabel.getScene();
s1.setCursor(Cursor.WAIT);

} finally {
latch.countDown();
}
}
});
latch.await();
return null;
}
};
}
};
service.start();

}

public void loginLoadEverything() {

//chance to true when complete
if (username.getText().isEmpty() == false || password.getText().isEmpty() == false) {

loginLabel.setText("Please enter data in the fields below");

} else {

username.setText("-----");
password.setText("-----");
//initialises backend interface with username and password
backendInterface = new BackendInterface(username.getText(), password.getText().toCharArray());

// Open a connection to the database

if (backendInterface.openConnection()) {

//return and print response
System.out.println(backendInterface.getConnectionResponse());

//directs the user to the dashboard after successful login
try {
if (backendInterface.getAllStudents() &&
backendInterface.getAllConsultations() &&
backendInterface.getCourses() &&
backendInterface.getConsultationCategories() &&
backendInterface.getConsultationPriorities()) {


FXMLLoader loader1 = new FXMLLoader();
loader1.setLocation(getClass().getResource("/main/res/dashboard.fxml"));
loader1.load();
Parent p = loader1.getRoot();
Stage stage = new Stage();
stage.setScene(new Scene(p));
stage.show();

//set instances to the dashboard controller
dashboardController = loader1.getController();
dashboardController.setBackendInterface(backendInterface); //pass backendInterface object to controller
dashboardController.setDashboardController(loader1.getController()); //pass dashboard as reference

//load images
Image logoutImage = new Image(getClass().getResourceAsStream("images/logout.png"));
Image userImage = new Image(getClass().getResourceAsStream("images/users.png"));
Image calendarImage = new Image(getClass().getResourceAsStream("images/calendar.png"));
Image leftArrowImage = new Image(getClass().getResourceAsStream("images/leftArrow.png"));
Image notepadImage = new Image(getClass().getResourceAsStream("images/notepad.png"));

//set images
dashboardController.studentLabel.setGraphic(new ImageView(userImage));
dashboardController.logoutLabel.setGraphic(new ImageView(logoutImage));
dashboardController.consultationLabel.setGraphic(new ImageView(notepadImage));

} else {
system.out.println(backendInterface.getExceptionMessage);
}


@Override
public void initialize(URL location, ResourceBundle resources) {



}

最佳答案

这里您可能不需要Service:您只需要一个Task

call()方法是在后台线程上执行的方法。它应该执行需要很长时间才能执行的工作(即连接到数据库并从中获取数据),并且不得执行任何 UI 工作,因为对 UI 的更改必须 在 FX 应用程序线程上进行。您收到异常的原因是您正在从后台线程创建并显示一个 Stage

所以基本思想是让任务从数据库获取数据并返回;然后使用任务的 onSucceeded 处理程序来显示 UI,并使用任务的结果。 (onSucceeded 处理程序在 FX 应用程序线程上执行,允许您安全地修改此处的 UI。)

我不知道你的类是如何实现的,等等,但以下内容可能会起作用。重要的是,您不要在与 UI 交互的后台线程中执行任何操作。

@FXML
public void loginButtonPress(ActionEvent event) {

if (( ! username.getText().isEmpty()) || (! password.getText().isEmpty()) ) {

loginLabel.setText("Please enter data in the fields below");

} else {

// I assume you want these values before you set them to "-----", no???
final String uName = username.getText();
final char[] pw = password.getText().toCharArray();

username.setText("-----");
password.setText("-----");

// create task for retrieving data:

Task<BackendInterface> loadDataTask = new Task<BackendInterface>() {

@Override
public BackendInterface call() throws Exception {

BackendInterface backendInterface = new BackendInterface(uName, pw);
if (backendInterface.openConnection()) {

if (backendInterface.getAllStudents() &&
backendInterface.getAllConsultations() &&
backendInterface.getCourses() &&
backendInterface.getConsultationCategories() &&
backendInterface.getConsultationPriorities()) {

return backendInterface ;
}
}

// maybe throw an exception here, depending on your requirements...
return null ;
}

};

// show UI on task completion:

loadDataTask.setOnSucceeded(e -> {

BackendInterface backendInterface = loadDataTask.getValue();

if (backendInterface == null) {
// something went wrong... bail, or probably show error message...
return ;
}

FXMLLoader loader1 = new FXMLLoader();
loader1.setLocation(getClass().getResource("/main/res/dashboard.fxml"));
Parent p = loader1.load();
DashboardController controller = loader.getController();
controller.setBackendInterface(backendInterface);

Stage stage = new Stage();
stage.setScene(new Scene(p));
stage.show();

// etc etc with your Images, etc (not sure why this isn't done in DashboardController though...)

// set cursor back to default:
loginLabel.getScene().setCursor(Cursor.DEFAULT);
});

loadDataTask.setOnFailed(e -> {
// show error message or otherwise handle database exception here
});

// set cursor to WAIT:
loginLabel.getScene().setCursor(Cursor.WAIT);

// and run task in a background thread:
Thread t = new Thread(loadDataTask);
t.start();

}

关于java - 如何在 javaFX 中将光标更改为 WAIT 的同时线程化后台任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39441812/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com