У меня есть приложение, которое после входа в систему обращается к базе данных через класс интерфейса. Процесс входа в систему заставляет приложение не реагировать на период, пока оно попадает в базу данных, и поэтому я просматриваю потоки и ожидающий курсор, чтобы это можно было запустить плавно. Я попытался использовать потоки через многие примеры в Интернете и переполнение стека, но мой метод, похоже, не работает, я получаю java.lang.IllegalStateException: не в потоке приложения FX; currentThread = Thread-4 exception, и я не уверен, как это исходить отсюда. Я пытаюсь изменить курсор на режим WAIT, пока этот фоновый поток запускает метод loginLoadEverything() (хотя я не включил в него код, поскольку он слишком длинный). Вот мой класс контроллера:Как нарисовать фоновое задание, изменяя курсор на WAIT в javaFX?
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) {
}
Метод 'call()' - это метод, выполняемый в фоновом потоке. Он должен выполнять работу, которая занимает много времени, и ** не должна ** выполнять какой-либо пользовательский интерфейс. Сейчас кажется, что только пользовательский интерфейс работает. Где выполняется фактическая работа с базой данных, из вашего кода это не ясно. Есть и другие проблемы - например. вы меняете курсор на 'WAIT' * после того, как * все остальное в методе' call() 'завершено, что, безусловно, не то, что вы хотите. Но вам нужно уточнить, где в первую очередь занята фактическая трудоемкая работа. –
Спасибо за отзыв Джеймс, я добавил остальную часть кода для метода loginLoadEverything. Этот метод обеспечивает доступ к базе данных из класса BackendInterface. Как вы можете видеть, методы из класса BackendInterface называются здесь, создавая трудоемкую работу. Затем я пытаюсь вызвать этот метод loginLoadEverything в методе call(). И да, это правильно, мне придется изменить курсор, чтобы подождать более подходящим образом, чтобы отразить трудоемкий процесс, но не уверен, как этого добиться. – Philayyy
См. Ответ. Похоже, вам нужно реструктурировать часть вашего кода, поскольку недостаточно чистого разделения между доступом к базе данных и пользовательским интерфейсом. Вы должны иметь возможность делать все фоновые работы в одном фрагменте кода и инкапсулировать результаты в какой-то объект - неясно, будет ли ваш объект backendInterface работать для этого или нет. Затем задача может выполнять работу с базой данных и возвращать этот объект, а обработчик 'onSucceeded' может отображать пользовательский интерфейс, настраивая его из объекта. Когда вы работаете, курсор тривиален. –