What is best way to pass object in JavaFX scene - java

(note, what i newbie in java)
I a little bit stuck in solving the problem of pass object between javafx scenes and classes.
For example, i have class, which waits for data by server; main class and 2 javafx windows.
Let it looks like this:
Listener.java.
Let it work at another thread. When we got "nelo" from server, then it'll means, what user not logged it, and then, we should open Login Window
// some package
// some imports
public class Listener extends Thread {
public void run() {
System.out.println("[INF] Wait for server...");
while(true) {
handle();
}
}
public void handle()
{
try {
byte[] token = new byte[6];
DataInputStream src = new DataInputStream(in);
src.read(token);
String token_val = new String(token);
switch (token_val) {
case "_nelo_":
System.out.println("[INF] Auth required");
break;
}
} catch (IOException e) {
}
}
}
Okay, there nothing weird. Just simple class for listening.
But here my troubles started. I try to explain it. (previosly, Sorry for bad english, i still learn this language)
Lets create login window (imagine that fxml file and controller created :) ):
// some package
// some imports
public class WindowLogin extends Application{
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = new Stage();
try {
URL location = getClass().getResource("../views/WindowLogin.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Parent) fxmlLoader.load(location.openStream());
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void show(){
launch();
}
}
So, when user open application, client will try connect to server.
If connection success, then server ask client for auth (Show login window). Next - user enter login and pass and click "Login" button. (Login Window show some indication of proccess). If auth success - Hide login, else - show some info in window.
As a result, i need access from Listener to Login window Controller. i.e. as i wrote before - different answer from server - different elements displayed.
How i can realize access to LoginWindowController ?
Thanks in advance

I will give you basic guidance for each task:
Connection
If connection with the server is successful then:
Platform.runLater(new Runnable() {
public void run() {
try {
WindowLogin login = new WindowLogin();
login.start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
}
});
Login
Error
You set a blank label on the WindowController and if the user cound't autheticate, than you fill this label.
Succesful login
You could use the same Platform.runLater as I used it before, or you could do something using stackpane and changing it's order ( I strongly recommend to use the Platform.runLater).

Related

Not switching to next FXML file?

Im making a button that switches to the next scene in Javafx, ie switching to the next FXML file.
Here is the code:
public void submitorder(ActionEvent actionEvent) throws IOException {
Customer cust = new Customer();
cust.setOrder(order);
tbl.getCustomers().add(cust);
if (tbl.getCustomers().size() == noOfDiners) {
System.out.println("if statement");
allcustomers = tbl.getCustomers();
try{
System.out.println("This prints");
Window mainWindow = btnSubmitOrder.getScene().getWindow();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("paymentScreen.fxml"));
Parent root = loader.load();
System.out.println("test");
PaymentScreenController psc = loader.getController();
psc.dataReceiver(allcustomers);
mainWindow.getScene().setRoot(root);
} catch(Exception e){
System.out.println(e.getMessage());
}
}
lvOrder.getItems().clear();
}
So that first print statement in the try method prints out so it goes into the try method but it still doesnt switch the scene. Ive used this exact code elsewhere in my program and it works so it dont know what im doing wrong.
Ive also tried not using a try method but i just get an error. In this case nothing happens
That if statement is also correct
Any help would be appreciated thanks

Closing the stage from JavaFX FXML controller class (ConfirmBox)

I'm a beginner in JavaFX, and I am developing a simple app and need to create a confirm box for closing the stage. I have done it without a problem without FXML when I have in the same method the initializing and the closing of the stage. But when I do it with FXML, when I have opened the stage in another class it fails to close it from controller class, even if I create a global stage instance.
public class ConfirmBox {
private Stage confirmBoxStage = new Stage();
boolean confirmClose;
// Confirm box -----------------------------------------------------------------------------------------------------
public boolean confirmClose() {
Parent rootConfirmBox = null;
confirmBoxStage.initModality(Modality.APPLICATION_MODAL);
try {
rootConfirmBox = FXMLLoader.load(getClass().getResource("ConfirmBox.fxml"));;
} catch (IOException e) {
System.out.println("Exception ConfirmBox.java//confirmBoxScene");
e.printStackTrace();
}
Scene confirmBoxScene = new Scene(rootConfirmBox, 640, 480);
confirmBoxStage.setScene(confirmBoxScene);
confirmBoxStage.showAndWait();
return confirmClose;
}
// Closing the confirm box -----------------------------------------------------------------------------------------
public void closeConfirmBox() {
confirmBoxStage.close();
}
}

JavaFX How to split code in the controller

I am having some troubles with splitting the business logic from a single controller into different controllers.
Problem:
At the beginning of my application,i ask user for username and password to perform login.After that,and if the login succeeds,i want to show to the user the main scene which includes some basic operation my app can do.The problem is : to perform any basic operation(for example,find groups the user belongs to) i need to know the username the user used when he logged in.At first, i made a single controller and passed to it the username from the login scene.Here is the login method from the login controller:
private void login(){
boolean loginResult = false;
try {
//Returns True if the user can login with the given username and password
loginResult = userRemote.login(username_field.getText(), password_field.getText());
if (!loginResult) {
Alert alert = new Alert(Alert.AlertType.ERROR, "The username and/or password are incorrect");
alert.showAndWait();
} else {
loadMain();
}
} catch (RemoteException e) {
e.printStackTrace();
Alert alert = new Alert(Alert.AlertType.ERROR, "Unable to connect to the server.Please try again later");
alert.showAndWait();
} catch (IOException e) {
e.printStackTrace();
}
}
If the login succeeds,i load the main scene passing it the username.Here is the code:
FXMLLoader loader = new FXMLLoader(getClass().getResource("../view/fxml/main.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
controller.init(username_field.getText());
Stage stage = (Stage) ( (Node) (sign_in_btn) ).getScene().getWindow();
Scene scene = new Scene(root);
scene.getStylesheets().add("/gui/view/css/style.css");
stage.setScene(scene);
In the Controller i save the username in a field,here is the init method that is called :
void init(String username) throws IOException {
this.username = username;
//some other code
}
After that i have the username in the my Controller of the main Scene,but the problem is that because of so many operation the controller has to do,the code in that controller is huge(about 800 lines of code).
I want to ask if there is any way to pass the username to other controllers from a single controller?
The operations my application performs are : finds tasks of the user,finds groups of the user,creates tasks,creates groups,deletes tasks,delete groups.
I use a group of toggle buttons that make the nav bar :
So whenever the user clicks any of the toggle buttons,an appropriate operation is performed using the username he gave when he logged in.
I want each toggle button to load a single fxml view,and each of the views to have its own controller that does the appropriate action using the username.But i don't know how to save the username and pass it to those controllers.
Right know i use a single controller that doesn't use any fxml files,it just creates the appropriate gui,depending on the toggle button that was clicked,and performs the business logic.

Java FX 8 using Platform.runLater() in Application init() method to display Alert / Login boxes

Please bear with me as this is going to be a pretty detailed and specific requirement. I also looked into numerous questions already listed on stackoverflow regarding Platform.runLater() usage. But I couldn't find an appropriate response. If someone can identify the correct question and mark this as a duplicate I would be great full all the same. Also I'm a newbie to JavaFX programming, so if I need to modify the architecture, please let me know.
I'm creating a stand-alone JavaFX application to run some unit tests based on user-defined requirements. Before running the actual tests, I need to make sure that the end-user is using the test with latest libraries available, by comparing the manifest files from remote Artifactory repo and the manifest files from jars on the current classpath. I want to store the credentials for Artifactory so that I can reuse them for subsequent executions. If the build numbers from remote and local manifest doesn't match, then I want to display an Error Alert window informing the user. I want to use a pre-loader to display a gif and appropriate messages in each of these steps.
public class UI extends Application
{
String username=null, password=null;
Manifest remoteManifest, localManifest;
#Override
public void init() {
notifyPreloader("Loading Stored Credentials");
loadStoredCredentials();
if(username == null && password == null) {
notifyPreloader("Requesting New Credentials");
getNewCredentials();
}
notifyPreloader("Reading remote manifest");
readRemoteManifest();
notifyPreloader("Reading local manifest");
readLocalManifest();
notifyPreloader("Comparing manifests");
compareManifests();
}
private void getNewCredentials() {
Platform.runLater(new Runnable() {
public void run() {
// Login window for new credentials
//Save credentials
}
});
}
private void readRemoteManifest() {
// REST API call to read remote manifest
if(HttpStatus.SC_UNAUTHORIZED) { // Stored credentials might have been read the first time which are expired, so try again.
getNewCredentials();
readRemoteManifest();
} else {
// update remote manifest object
}
}
private void readLocalManifest() {
// Update local manifest object
}
private void showAlert() {
Platform.runLater( new Runnable() {
// Display Alert window
});
}
private void compareManifests() {
if(remoteManifest == null) {
showAlert();
}
if(localAlert == null) {
showAlert();
}
if(remoteBuildNumber != localBuildNumber) {
showAlert();
}
}
#Override
public void start(Stage primaryStage){
//UI to select options and run tests
}
}
I have three issues with this approach.
If I don't user Platform.runLater() for Alert Windows and Login Windows, then I get an error saying Not on FX application thread; currentThread = JavaFX Application Thread error?
If I use Platform.runLater() then even though the login window is active, the remaining alert windows also show up immediately without waiting to read the login credentials.
If I manually create the file to store current credentials, then any alert window that I have shows up twice.
Let me know if you need any additional info.
Thanks in advance.
EDIT-1:
Someone gave me an answer to fix the first two issues. But now the answer is missing. If they can re-post the answer, it would be helpful for others.
The solution was to move the Platform.runLater() code to compareManifests() method from showAlert() method. Instead I moved the Platform.runLater() to init() method. Now I only have one call to runLater().
The modified code to fix the first two issues.
public class UI extends Application
{
String username=null, password=null;
Manifest remoteManifest, localManifest;
#Override
public void init() {
Platform.runLater( new Runnable() {
public void run() {
notifyPreloader("Loading Stored Credentials");
loadStoredCredentials();
if(username == null && password == null) {
notifyPreloader("Requesting New Credentials");
getNewCredentials();
}
notifyPreloader("Reading remote manifest");
readRemoteManifest();
notifyPreloader("Reading local manifest");
readLocalManifest();
notifyPreloader("Comparing manifests");
compareManifests();
}
});
}
private void getNewCredentials() {
// Login window for new credentials
//Save credentials
}
private void readRemoteManifest() {
// REST API call to read remote manifest
if(HttpStatus.SC_UNAUTHORIZED) { // Stored credentials might have been read the first time which are expired, so try again.
getNewCredentials();
readRemoteManifest();
} else {
// update remote manifest object
}
}
private void readLocalManifest() {
// Update local manifest object
}
private void showAlert() {
// Display Alert window
}
private void compareManifests() {
if(remoteManifest == null) {
showAlert();
}
if(localAlert == null) {
showAlert();
}
if(remoteBuildNumber != localBuildNumber) {
showAlert();
}
}
private void loadStoredCredentials() {
// Read the credentials from a local file
}
#Override
public void start(Stage primaryStage){
//UI to select options and run tests
}
}
Issue 3 is still occurring, there are two login windows being displayed now.
Thanks.

Progress indicator remains indeterminate and there is no download

I have written a piece of code for downloading a file from internet (in background service) and showing the progress of download in a popup stage. The code compiles successfully and there is no runtime error. However no download takes place and progress indicator remains indeterminate.
The code is tailored for illustrating my point. Please have a look at it and let me understand where I have gone wrong.
Thanks!
public class ExampleService extends Application {
URL url;
Stage stage;
public void start(Stage stage)
{
this.stage = stage;
stage.setTitle("Hello World!");
stage.setScene(new Scene(new StackPane(addButton()), 400, 200));
stage.show();
}
private Button addButton()
{
Button downloadButton = new Button("Download");
downloadButton.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e)
{
FileChooser fileSaver = new FileChooser();
fileSaver.getExtensionFilters().add(new FileChooser.ExtensionFilter("PDF", "pdf"));
File file = fileSaver.showSaveDialog(stage);
getDownloadService(file).start();
}
});
return downloadButton;
}
private Service getDownloadService(File file)
{
Service downloadService = new Service()
{
protected Task createTask()
{
return doDownload(file);
}
};
return downloadService;
}
private Task doDownload(File file)
{
Task downloadTask = new Task<Void>()
{
protected Void call() throws Exception
{
url = new URL("http://www.daoudisamir.com/references/vs_ebooks/html5_css3.pdf");
// I have used this url for this context only
org.apache.commons.io.FileUtils.copyURLToFile(url, file);
return null;
}
};
showPopup(downloadTask);
return downloadTask;
}
Popup showPopup(Task downloadTask)
{
ProgressIndicator progressIndicator = new ProgressIndicator();
progressIndicator.progressProperty().bind(downloadTask.progressProperty());
Popup progressPop = new Popup();
progressPop.getContent().add(progressIndicator);
progressPop.show(stage);
return progressPop;
// I have left out function to remove popup for simplicity
}
public static void main(String[] args)
{
launch(args);
}}
The line:
org.apache.commons.io.FileUtils.copyURLToFile(url, file);
...doesn't provide you any information about the progress of your download (there is no callback or any other indication of its progress). It just downloads something without giving you feedback.
You will have to use something else that gives you feedback on the progress.
Take a look at this questions answers for solutions with feedback (it is for Swing, but you should be able to adapt them for JavaFX): Java getting download progress
You bind the ProgressIndicator's progress property to the Task's progress property, so that changes in the latter will be reflected in the former. However you never actually update your Task's progress.
If you want the progress indicator to show something, you're going to have to call updateProgress(workDone, max) within your task's body (or elsewhere). And that might be tricky if the download logic you're using doesn't give you any progress callbacks. (You could, perhaps, spawn a thread to repeatedly check the size of the file on the filesystem and use that as your current workDone; but you'd need to know what the eventual/complete size of the file would be in order to turn this into a percentage, which may or may not be easy.)

Categories

Resources