close fxml window by code, javafx - java

I need to close the current fxml window by code in the controller
I know stage.close() or stage.hide() do this in fx
how to implement this in fxml? I tried
private void on_btnClose_clicked(ActionEvent actionEvent) {
Parent root = FXMLLoader.load(getClass().getResource("currentWindow.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
}
but it doesn't work!
All help will be greatly appreciated. Thanks!

give your close button an fx:id, if you haven't yet: <Button fx:id="closeButton" onAction="#closeButtonAction">
In your controller class:
#FXML private javafx.scene.control.Button closeButton;
#FXML
private void closeButtonAction(){
// get a handle to the stage
Stage stage = (Stage) closeButton.getScene().getWindow();
// do what you have to do
stage.close();
}

If you have a window which extends javafx.application.Application; you can use the following method.
(This will close the whole application, not just the window. I misinterpreted the OP, thanks to the commenters for pointing it out).
Platform.exit();
Example:
public class MainGUI extends Application {
.........
Button exitButton = new Button("Exit");
exitButton.setOnAction(new ExitButtonListener());
.........
public class ExitButtonListener implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent arg0) {
Platform.exit();
}
}
Edit for the beauty of Java 8:
public class MainGUI extends Application {
.........
Button exitButton = new Button("Exit");
exitButton.setOnAction(actionEvent -> Platform.exit());
}

I implemented this in the following way after receiving a NullPointerException from the accepted answer.
In my FXML:
<Button onMouseClicked="#onMouseClickedCancelBtn" text="Cancel">
In my Controller class:
#FXML public void onMouseClickedCancelBtn(InputEvent e) {
final Node source = (Node) e.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}

If you don't want to overspread your controller with fxml linked methods you can do something like this:
You have to give it a "fx:id", like "closeButton" for example. Should look like this in your FXML file:
<Button fx:id="closeButton" layoutX="876.0" layoutY="74.0" mnemonicParsing="false" textAlignment="CENTER">
Then you can just code the button in your initialize method or wherever you want:
#FXML
Button closeButton
public initialize(){
closeButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e){
((Stage) closeButton.getScene().getWindow()).close();
}
});
}

I'm not sure if this is the best way (or if it works), but you could try:
private void on_btnClose_clicked(ActionEvent actionEvent) {
Window window = getScene().getWindow();
if (window instanceof Stage){
((Stage) window).close();
}
}
(Assuming your controller is a Node. Otherwise you have to get the node first (getScene() is a method of Node)

I found a nice solution which does not need an event to be triggered:
#FXML
private Button cancelButton;
close(new Event(cancelButton, stage, null));
#FXML
private void close(Event event) {
((Node)(event.getSource())).getScene().getWindow().hide();
}

stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
Platform.setImplicitExit(false);
stage.close();
}
});
It is equivalent to hide. So when you are going to open it next time, you just check if the stage object is exited or not. If it is exited, you just show() i.e. (stage.show()) call. Otherwise, you have to start the stage.

finally, I found a solution
Window window = ((Node)(event.getSource())).getScene().getWindow();
if (window instanceof Stage){
((Stage) window).close();
}

Hide doesn't close the window, just put in visible mode.
The best solution was:
#FXML
private void exitButtonOnAction(ActionEvent event){
((Stage)(((Button)event.getSource()).getScene().getWindow())).close();
}

Related

How to change width of button when application is not fullscreen?

I'm making an application with JavaFX and Scene Builder.
I have Main class and controller that is called from main class.
I have a button in the controller that has width - 45 and height - 90
Toggle button is wrapped in StackPane and StackPane is wrapped in AnchorPane
How can I change buttonPrefWidth to 25 when application is not fullscreen and change button's prefWidth again to 45 when application is fullscreen?
Or can I change prefWidth of a button according to size of application?
Main Class:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root =
FXMLLoader.load(getClass().getResource("/card/resources/fxml/card.fxml"));
Scene scene = new Scene(root, 1600, 600);
primaryStage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("style.css")
.toExternalForm());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMaximized(true);
primaryStage.setResizable(true);
primaryStage.getIcons().add(new Image("card/resources/logo-icon.png"));
primaryStage.show();
//adding resize and drag primary stage
ResizeHelper.addResizeListener(primaryStage);
//assign ALT+ENTER to maximize window
final KeyCombination kb = new KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN);
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (kb.match(event)) {
primaryStage.setMaximized(!primaryStage.isMaximized());
primaryStage.setResizable(true);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Controller:
public class Controller implements Initializable {
#FXML private AnchorPane anchorRow;
#FXML private StackPane hBoxCat0;
#FXML private Button btnPalette;
#FXML
public void initialize(URL location, ResourceBundle resources) {
}
}
EDIT:
#Slaw it doesn't work
If you just want to change the prefWidth between two numbers based on whether or not the window is full screen, then you can listen to the fullScreen property of the Stage the Button belongs to.
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
#FXML private Button btnPallet;
#FXML
private void initialize() {
btnPallet.prefWidthProperty().bind(
Bindings.when(Bindings.selectBoolean(btnPallet.sceneProperty(), "window", "fullScreen"))
.then(45)
.otherwise(25)
);
}
}
This will give you warnings at first since the Button won't be part of a Scene or Window at this point of the application. While these warnings are annoying the code should still work.

How to check is mouse cursor is on the button in Java FX?

I'm new to Java and I'm wondering if it is possible to check if mouse cursor is for example on the button? I mean not getting clicking events but just moving cursor on the button.
I had working code getting click and then printing something, but I want to change it a little and I can't find out why it doesn't work.
public class Main extends Application implements EventHandler<MouseEvent> {
Button button;
Stage window;
Scene scene;
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Where's the button?");
button.setText("Click me!");
button.setOnMouseMoved(this);
StackPane layout = new StackPane();
layout.getChildren().add(button);
Scene scene = new Scene(layout, 300,350);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
#Override
public void handle(MouseEvent actionEvent) {
System.out.println("You clicked the button!");
}
}
I have made small code for you. Take a look. It prints in the console "Ho-Ho-Ho-Hovereed!" once you hover over your button.
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Hover over me.'");
btn.hoverProperty().addListener((event)->System.out.println("Ho-Ho-Ho-Hovereeed!"));
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Mouse manpulation example in JavaFX!");
primaryStage.setScene(scene);
primaryStage.show();
}
i guess you can do that with event handler or css, like...
button.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
System.out.println("Cursor Over Button");
}
});
or/with styles (css)
.button:hover{
-fx-background-color: red;
}
Each Node provides a hover property to track whether the mouse cursor is hovering over it or not. By using a simple listener, you can detect when the mouse starts and stops hovering:
button.hoverProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
System.out.println("Hovering...");
} else {
System.out.println("Retreating...");
}
});
With this listener, newValue will always be true if the mouse is currently hovering over the button and change to false when the mouse leaves the area.
There is also a useful check on a Node - isHover() You can use it on MouseEvents to check if the mouse is hovering over the needed node. Such a tip ;)
button.setOnMouseEntered( (event ) -> {
button.setTranslateX(button.getTranslateX() + 20);
button.setTranslateY(button.getTranslateY() + 20);
});`
Replace button.setOnMouseMoved(this); with my code. This will do!

JavaFX actions on elements of one window from another window

Please help me solve the problem. There are two fxml files and their controllers:
sample.fxml, its controller ControllerMain (main window of the program)
find_win.fxml, its ControllerFind controller (modal window "text search")
In the modal window find_win.fxml there is a TextField into which the search text is entered, and the Find button, when clicked, ControllerFind must process the click and call the search method and highlight the search text in the TextArea element of the sample.fxml window.
<fx: include source = "sample.fxml" fx: id = "textAreaOne" />
and the inheritance of the ControllerMain by the ControllerFind controller does not help to achieve a solution - in the first case the entire window markup is included in the modal window completely, in the second case, the java.lang.reflect.InvocationTargetException is returned during an operation on the TextArea.
How to implement actions on elements of one window from another window?
I've found a solution elsewhere. Thanks to Comrade Antizam, who tried to help, but did not quite understand what I needed.
The solution described here is .
In short, it is necessary to create an instance of a controller-parent and a method that takes an instance of a controller-parent as a parameter in the controller-child. When a new window is opened from a controller-parent, get an instance of the controller-child and indicate to it through the created method "this".
Further, in the controller-child, it will be possible to access the elements of the parent controller.
controller-parent:
package sample;
public class ControllerMain {
private ControllerFind children; // controller-child
//main-window
#FXML
public TextArea textAreaOne;
#FXML
public MenuItem findMenuItem;
public void findAction(ActionEvent actionEvent) {
try {
Stage stageFind = new Stage();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXML/find_win.fxml"));
Parent root = loader.load();
stageFind.setTitle("Find");
stageFind.setMinHeight(200);
stageFind.setMinWidth(150);
stageFind.setResizable(false);
stageFind.setScene(new Scene(root));
stageFind.getIcons().add(new Image("image/search.png"));
stageFind.initModality(Modality.NONE);
stageFind.show();
children = loader.getController(); //getting controller of window find_win.fxml
children.setParent(this); //setting parent of the controller-child - this
} catch (IOException e) {
e.printStackTrace();
}
}
}
controller-child:
package sample.Controllers;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import sample.Classes.DialogManager;
import sample.ControllerMain;
public class ControllerFind {
//Window "Find"
#FXML public TextField searchTextField;
#FXML public Label findTextLabel;
#FXML public Button okTextFindButton;
#FXML public Button cancelTextFindButton;
private String text;
private ControllerMain controller;
public void setParent (ControllerMain controller){
this.controller = controller;
}
public ControllerFind getThis(){
return this;
}
public void initialize(){
System.out.println("psvm");
}
public void textFindOkButtonAction(ActionEvent actionEvent) {
text = (searchTextField.getText());
if (text.equals("")) {
DialogManager.showInfoDialog("Error!", "Enter text what you are looking for!");
} else {
if (controller.textAreaOne.getText() != null && !controller.textAreaOne.getText().isEmpty()) {
int index = controller.textAreaOne.getText().indexOf(text);
if (index == -1) {
DialogManager.showInfoDialog("Result", "There isn't text what you are looking for");
} else {
controller.textAreaOne.selectRange(index, index + text.length());
}
} else {
DialogManager.showInfoDialog("Error", "TextArea is empty!");
}
}
}
public void textFindCancelButtonAction(ActionEvent actionEvent) {
Node source = (Node) actionEvent.getSource();
Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
}
Vis-a-vis windows communication in this situation, it's optimal to use TextInputDialog something like this:
#Override
public void start(Stage primaryStage){
Button btn=new Button("Click");
VBox vbox=new VBox();
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(btn);
Scene scene=new Scene(vbox, 200,200);
btn.setOnAction(e->
{
TextInputDialog dialog=new TextInputDialog();
Optional<String> result = dialog.showAndWait();
if (result.isPresent()){
System.out.println(result.get());
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
but text highlighting is not something that can be done easy.
You could do String search of TextArea text, compare it to result from another window then highlight it via
textArea.getSelectedRange(firstIndex, lastIndex);
firstIndex and lastIndex being indexes of textArea text for the word we are searching. Then having button on every click displaying next word occurancy inside text and highlighting it. But if you insist on highlighting every instance of word at the same time I would suggest using RichTextFX.

Eliminating Previous Scene After New Scene Is Shown

I am just beginning to learn JAVAFX and I have run into a problem now. I have a login screen and after I clicked login, a dialog box appeared and the problem is I don't know how to eliminate the login screen after the dialog has showed up. Please help me. This is my code
Main.java (contains login screen)
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginScreen.fxml"));
primaryStage.setTitle("Weltes Mart O2 Tank Module");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
LoginController.java (showing a dialog box)
public class LoginController {
#FXML private Text loginStatusMessage;
#FXML private Button btnLogin;
#FXML public void handleLoginButton(ActionEvent event){
System.out.println("BUTTON PRESSED");
try {
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginSuccessDialog.fxml"));
Stage primaryStage = new Stage();
primaryStage.setScene(new Scene(root));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
You can use any Node in a Scene to get a reference to that scene. You can use a Scene to get the Window that contains it. You can close that window.
Assuming the Node fields are actually injected by the loader, you can close the Stage using this code:
btnLogin.getScene().getWindow().hide();

How to minimize(iconify) FXML app?

How can i assign a handler to minimize(iconify) app to a #FXML private HBox minBtn; (custom button made with Shape) button from Controller's public void initialize(URL, ResourceBundle) method? setIconified(boolean) method is in Stage class and i can't get him in my Controller class.
You can access to the Stage by
minBtn.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
((Stage) ((Node) arg0.getSource()).getScene().getWindow()).setIconified(true);
// OR
((Stage) minBtn.getScene().getWindow()).setIconified(true);
}
});

Categories

Resources