JavaFX Cursor wait while loading new anchorPane - javafx

I am trying to load a new anchorPane in the existing scene by removing the old anchorPane.Now i need to show the user that loading cursor and the action performed by the user should not happen(like button click or key press).
I have used but Cursor.WAIT but still the action can be performed.
anchorPane.getScene().SetCursor(Cursor.WAIT);
HomeController controller=new HomeController(stage,anchorPane);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/home.fxml"));
loader.setController(controller);
Parent root = null;
try {
root=(Parent) loader.load();
} catch (IOException e) {
LOGGER.error("Message is " + e);
e.printStackTrace();
}
anchorPane.getChildren().remove(0);
anchorPane.getChildren().add(root);
I have added Cursor.WAIT before this code.but i doesn't work.

Cursor.WAIT change only the icon of your cursor but it doesn't prevent you to interact with your view. If you want to prevent an user to interact with your view your could disable the elements like btn.setEnabled(false).
To show the user that you are peforming some background actions and he/she should wait until it's complete use tasks and dialogs.
Task task = new Task(new Runnable() { ... do stuff ... });
Dialog dialog = new Alert(AlertType.INFORMATION);
dialog.setTitle("Wait");
dialog.disableButton(ButtonType.OK);
task.stateProperty().addListener(
(observableValue, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED
|| newState == Worker.State.FAILED
|| newState == Worker.State.CANCELLED) {
dialog.close();
}
});
new Thread(task).start();
dialog.showAndWait();

Related

JFXDialog close on KeyCode.Enter, MouseEvent.Click

When i call JFXDialog, the dialog appear with message and button, all beautiful, than i can close it by pressing the button, but i can not close it by using key event on KeyCode.Enter
JFXDialog is control unit of JFoenix in SceneBuilder.
I have used different methods of events, but i don't have succes to close the dialog.
Can anybody help me to solve the problem?
I use soft and machine:
JavaFx, SceneBuilder
Eclipse IDE for Java Developers Version: 2019-12 (4.14.0)
JDK 10.0.2
Setting part:
//create button
JFXButton button = new JFXButton("Hello there!");
//create message layout
JFXDialogLayout dialogLayout = new JFXDialogLayout();
//control dialog
JFXDialog dialog = new JFXDialog(rootPane, dialogLayout,
JFXDialog.DialogTransition.TOP);
dialogLayout.setHeading(new Label("text"));
dialogLayout.setBody(new Text("text"));
dialogLayout.setActions(button);
button.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) ->{
dialog.close();
});
Below are 2 examples of event methods that i have tried to use.
Event part:
//first method
dialogLayout.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent k) {
if (k.getCode().equals(KeyCode.ENTER)) {
button.fire();
}
}
});
//second method
button.addEventHandler(KeyEvent.KEY_PRESSED, event2 -> {
if(event2.getCode() == KeyCode.ENTER) {
button.fire();
event2.consume();
}
});
dialog.show();

How to stay in the same fxml when calling an Alert Class?

I have created this methode for Email validation
The issue is that the Alert displayed goes on the top of the previous fxml instead of the same and the user have to fulfill all the fields again
I have this method
public boolean validateEmail() {
Pattern p = Pattern.compile("[a-zA-Z0-9][a-zA-Z0-9._]*#[a-zA-Z0-9]+([.][a-zA-Z]+)+");
Matcher m = p.matcher(emailField.getText());
if (m.find() && m.group().equals(emailField.getText())) {
return true;
} else {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Validation of Email");
alert.setHeaderText(null);
alert.setContentText("Please enter a valid Email");
alert.showAndWait();
return false;
}
}
I have a button which onAction calls the method below
public void showSubscription() throws IOException {
Dialog<ButtonType> dialog = new Dialog<>();
dialog.setTitle("New Subscription");
dialog.setHeaderText("Please Fulfill your information to subscribe");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("Registration.fxml"));
try {
dialog.getDialogPane().setContent(fxmlLoader.load());
} catch (IOException e) {
System.out.println("Couldn't load the Dialog");
e.printStackTrace();
return;
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if (result.isPresent() && result.get()==ButtonType.OK) {
RegistrationController controller = fxmlLoader.getController();
if (controller.validateEmail()) {
controller.loadRegistration();
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Information");
alert.setHeaderText(null);
alert.setContentText("Subscription Done Correctly");
alert.showAndWait();
}
}
else {
System.out.println("CANCEL pressed");
}
}
I don't know what to add to make this Alert popup in the same Registration.fxml and not go back to the previous one.
Alert inherits an initOwner(Window) method from Dialog. So you can call initOwner(...) and pass in the window responsible for showing the dialog. There's no direct reference to this, but you can get it from the scene containing the dialog's dialog pane:
alert.initOwner(dialog.getDialogPane().getScene().getWindow());
This line just needs to be called sometime before alert.showAndWait().
If you need the Alert created in the validateEmail() method to have the same owner, just pass a reference to the appropriate window to that method:
public boolean validateEmail(Window mainWindow) {
// ...
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.initOwner(mainWindow);
// ...
alert.showAndWait();
// ...
}
and
RegistrationController controller = fxmlLoader.getController();
if (controller.validateEmail(dialog.getDialogPane().getScene().getWindow())) {
// ...
}

How to handle wrong drop location in JavaFx?

In my GUI I create some dices (ImageView) and I can drag and drop them in one specific GridPane. When I drop a dice into the specific GridPane, the dice disappears from the initial location and it moves to the right position. This works fine only if I choose the right drop location.
The problem is how can I manage the wrong drop location?
Actually if I drop a dice in a wrong location (like outside the Gridpane) the dice disappears like it was moved to the right position.
I want to restore the dice to the original location if the dice isn't placed to the GridPane.
Is there a method can help me to check if I drop into the right location? Or something can prevent to drop into the wrong location?
You can check the transferMode property of the DragEvent passed to the onDragDone event:
dragSource.setOnDragDone(evt -> {
if (evt.getTransferMode() == null) {
System.out.println("drag aborted");
} else {
System.out.println("drag successfully completed");
}
});
Note: this requires you to mark the drag gesture as completed in the onDragDropped event handler using setDropCompleted. Example:
#Override
public void start(Stage primaryStage) {
Button source = new Button("Not dragged yet");
Button target = new Button("target");
HBox root = new HBox(20, source, target);
source.setOnDragDetected(evt -> {
Dragboard db = source.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
});
source.setOnDragDone(evt -> {
source.setText(evt.getTransferMode() == null ? "failure" : "success");
});
target.setOnDragOver(evt -> {
if (evt.getDragboard().hasString()) {
evt.acceptTransferModes(TransferMode.COPY);
evt.consume();
}
});
target.setOnDragDropped(evt -> {
String value = evt.getDragboard().getString();
target.setText(value);
evt.setDropCompleted(true);
evt.consume();
});
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

How to ensure each Controller can see the model and is only initialized once?

In my mainController I'm using the following method to change views:
#FXML
public void handleChangeView(ActionEvent event) {
try {
String changeButtonID = ((Button) event.getSource()).getId();
FXMLLoader loader = new FXMLLoader(getClass().getResource("../../resources/view/" + changeButtonID + ".fxml"));
mainView.setCenter(loader.load());
} catch (IOException e){
e.printStackTrace();
}
}
Now this is working but I have two problems:
1) With each button click the controller of the loaded FXML file fires again. For example in my other controller I have:
Timeline counterTimeline = new Timeline(new KeyFrame(Duration.seconds(1), e -> System.out.println("Test")));
counterTimeline.setCycleCount(Animation.INDEFINITE);
counterTimeline.play();
With each click it seems a new Timeline is created and set to play - how can I ensure this doesn't happen? It seems like every time a change view button is clicked the controller for it is re-initialized.
2) How can I ensure each controller can see the model while still using the above method to change views? I'd rather avoid dependancy injections because I honestly can't wrap my head around it - after 6 hours trying to get afterburner.fx to work I can't handle it.
You can create a new fxml nodes only once per type:
private final Map <String, Parent> fxmls = new HashMap<>();
#FXML
public void handleChangeView(ActionEvent event) {
try {
String changeButtonID = ((Button) event.getSource()).getId();
Parent newOne = fxmls.get(changeButtonID);
if (newOne == null) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("../../resources/view/" + changeButtonID + ".fxml"));
newOne = loader.load();
fxmls.put(changeButtonID, newOne):
}
mainView.setCenter(newOne);
} catch (IOException e){
e.printStackTrace();
}
}

[A]How to use setFullScreen methode in javafx?

I have a stage with these properties
stage = new Stage(StageStyle.DECORATED);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.setTitle("My App");
stage.getIcons().add(new Image(icon-address));
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("start.fxml"));
fxmlLoader.setController(this);
...
...//and other properties
It is in full screen in this stage. I have a button and each time I click on it , a method of another class is called and the reference of this stage is passed to it.
For example, if I have two classes Start and ButtonClicked
In Start, I have this :
Button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
buttonClicked a = new buttonClicked ();
try {
a.render(stage);
} catch (Exception ex) {
Logger.getLogger(menuController.class.getName())
.log(Level.SEVERE, null , ex);
}
}
});
Now, the render method is called and I have the following code inside render :
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("buttonclicked.fxml"));
fxmlLoader.setController(this);//set Controller for our fxml file
loader = fxmlLoader.load();//loader is a stackPane because buttonclick.fxml has stackPane
stage.setScene(new Scene(loader));
stage.setFullScreen(true);
...
The problem is, if user clicks on button, stage become a 1024x700(because i have pictures in start.fxml and buttonclicked.fxml. The size of both the picture is 1024x700
After a moment, it becomes full screen. How can i fix this ?
I want to kill the delay in full screen
Thanks
Try
stage.getScene().setRoot(loader);
in render method.
By doing this, the creation of a new scene is eliminated. Therefore I guess, some UI related updates and calculations that must be done after the scene has been shown, are also eliminated.

Resources