JavaFX setOnClosedRequest in Dialog not fired - javafx

I have a Problem with my JavaFX app. It is devided in to parts - a main Stage and a Stage as a Dialog. When i close the main stage setonclosedrequest is fired as expected, but setoncloserequest of the dialog Stage is never fired. What i do wrong ? Here is my code:
Main App:
public class TestApp extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLDialogLoader loader = new FXMLDialogLoader("de/pasa/fxml/Dialog.fxml");
loader.setController(new DialogController(primaryStage));
loader.loadPrimaryStage(primaryStage, "Main App");
primaryStage.setOnCloseRequest(e->{
System.out.println("Do something before Close");
});
}
}
Controller:
public class DialogController implements Initializable{
#FXML private Button bOpen;
private Stage parentStage = null;
public DialogController(Stage parentStage) {
this.parentStage=parentStage;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
bOpen.setOnAction(e->{
FXMLDialogLoader loader=new FXMLDialogLoader("de/pasa/fxml/Test.fxml", parentStage);
Stage dlgStage=loader.loadDialog();
dlgStage.setOnCloseRequest(t->{
//never reached - not fired, why ?
System.out.println("Do something before Dialog closed");
});
});
}
}
FXMLLoader:
public class FXMLDialogLoader {
private String _fxmlPath=null;
private String _title=null;
private Object _controller=null;
private ResourceBundle _bundle=null;
private Stage _parentStage=null;
private Stage _primaryStage=null;
private Stage stage=null;
private StageStyle _style=null;
private String _iconPath=null;
private LoggerEX _log = LoggerEX.getLogger(FXMLDialogLoader.class);
public FXMLDialogLoader(String fxmlPath){
this(fxmlPath,null);
}
public FXMLDialogLoader(String fxmlPath,Stage parentStage){
this(fxmlPath,parentStage,"Dialog",null,null,StageStyle.UTILITY);
}
public FXMLDialogLoader(String fxmlPath,Stage parentStage,String title,Object controller,ResourceBundle bundle,StageStyle style){
_fxmlPath=fxmlPath;
_parentStage=parentStage;
_controller=controller;
_bundle=bundle;
_title=title;
_style=style;
}
public Stage loadDialog(){
FXMLLoader loader=new FXMLLoader(getClass().getClassLoader().getResource(_fxmlPath));
loader.setController(_controller);
loader.setResources(_bundle);
try {
Parent root=loader.load();
Scene scene=new Scene(root);
if(_primaryStage==null){
stage=new Stage();
}
else{
stage=_primaryStage;
}
if(_iconPath!=null){
stage.getIcons().add(new Image(new FileInputStream(new File(_iconPath))));
}
stage.setTitle(_title);
stage.setScene(scene);
if(_primaryStage==null){
stage.initModality(Modality.WINDOW_MODAL);
}
stage.initStyle(_style);
if(_primaryStage==null){
stage.initOwner(_parentStage);
}
if(_primaryStage==null){
stage.showAndWait();
}
else{
stage.show();
}
stage.centerOnScreen();
}
catch(IOException ex){
ex.printStackTrace();
_log.error(ex);
}
return stage;
}
public Stage getDialogStage(){
return stage;
}
public Stage loadPrimaryStage(Stage primaryStage,String title){
return loadPrimaryStage(primaryStage,title,null);
}
public Stage loadPrimaryStage(Stage primaryStage,String title,String iconPath){
_primaryStage=primaryStage;
setTitle(title);
setIconPath(iconPath);
setStageStyle(StageStyle.DECORATED);
_primaryStage.centerOnScreen();
loadDialog();
return _primaryStage;
}
public void setIconPath(String iconPath){
_iconPath=iconPath;
}
public void setTitle(String title){
_title=title;
}
public void setStageStyle(StageStyle style){
_style=style;
}
public void setController(Object controller){
_controller=controller;
}
public void setResourceBundle(ResourceBundle bundle){
_bundle=bundle;
}
}

You are calling showAndWait() to display the dialog, which, as the method name implies, waits until the dialog is dismissed before returning. Only after the dialog is dismissed do you then register the onCloseRequest handler: by then it is too late to process the event.

Related

JavaFX - How to switch to another tab with mouse click event [duplicate]

So I'm trying to load and save Images into an imageView where the location of the image is chosen through a file browser. I've been working on this for several days now and I'm gonna have a stroke if I can't get it fixed. I've tried everything I can think of. Thank you in advance for helping.
UPDATED:
Here is my main class:
public class Main extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
public Main(){}
#Override
public void start(Stage primaryStage) throws Exception{
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Help Please");
initRootLayout();
showScreen();
}
public void initRootLayout(){
try{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
RootLayout controller = loader.getController();
controller.setMain(this);
primaryStage.show();
}catch(Exception e ){e.printStackTrace();}
}
public void showScreen(){
try{FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/sample.fxml"));
BorderPane sample = (BorderPane)loader.load();
rootLayout.setCenter(sample);
Controller controller = loader.getController();
controller.setMain(this);
}catch (Exception e){e.printStackTrace();}
}
public Stage getPrimaryStage(){return primaryStage;}
public static void main(String[] args) {
launch(args);
}
}
Here is the rootLayout:
public class RootLayout {
private Main main;
private Controller controller = new Controller();
public void setMain(Main main){this.main = main;}
#FXML
private void handleOpen(){
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
"PNG files (*.png)","*png");
fileChooser.getExtensionFilters().add(extensionFilter);
File file = fileChooser.showOpenDialog(main.getPrimaryStage());
if(file!= null){
controller.updateImage(file.toURI().toString());
}
}
}
And here is the controller:
public class Controller implements Initializable {
#FXML
ImageView imageView = new ImageView();
String imageURL;
Main main = new Main();
public void setMain(Main main){
this.main = main;
}
public void updateImage(String url){
if(url.length()>=1){
Image image = new Image(url);
imageView.setImage(image);
System.out.println(url);
}
else{
System.out.println(url);
System.out.println("image invalid");
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
Two things:
Never assign a field whose value is to be injected by an FXMLLoader (e.g. #FXML fields). Doing so is a waste of resources at best and introduces subtle bugs at worst. For instance, if you were to leave the imageView field uninitialized you'd be getting a NullPointerException which would indicate a problem with your setup. Since you do initialize the field, however, you don't get any errors and there's a false impression of the code working.
In your RootLayout controller class, you have:
private Controller controller = new Controller();
That instance of Controller you just created is not linked to any FXML file. And since you initialize the imageView field (see first point) you end up updating an ImageView which is not being displayed anywhere; this is where not initializing said field would have given a nice indication of there being a problem. The solution is to pass the Controller instance created by the FXMLLoader to the RootLayout instance created by the other FXMLLoader.
Also, in the same class you have:
Main main = new Main();
Which is also unnecessary since the created instance of Main is both not the correct instance and is replaced by the call to #setMain(Main) almost immediately.
Assuming your FXML files (which you did not provide) are correct, the Java classes should look more like:
Main.java
public class Main extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private RootLayout rootLayoutController;
public Main() {}
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Help Please");
initRootLayout();
showScreen();
}
public void initRootLayout() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
// store RootLayout instance in field so #showScreen()
// can reference it
rootLayoutController = loader.getController();
rootLayoutController.setMain(this);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void showScreen() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/sample.fxml"));
BorderPane sample = (BorderPane) loader.load();
rootLayout.setCenter(sample);
Controller controller = loader.getController();
controller.setMain(this);
// set Controller instance on RootLayout instance
rootLayoutController.setController(controller);
} catch (Exception e) {
e.printStackTrace();
}
}
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
RootLayout.java
public class RootLayout {
private Main main;
private Controller controller;
public void setMain(Main main) {
this.main = main;
}
public void setController(Controller controller) {
this.controller = controller;
}
#FXML
private void handleOpen() {
FileChooser fileChooser = new FileChooser();
// Note extensions should be prefixed with "*."
FileChooser.ExtensionFilter extensionFilter =
new FileChooser.ExtensionFilter("PNG files (*.png)", "*.png");
fileChooser.getExtensionFilters().add(extensionFilter);
File file = fileChooser.showOpenDialog(main.getPrimaryStage());
if (file != null) {
controller.updateImage(file.toURI().toString());
}
}
}
Controller.java
public class Controller implements Initializable {
#FXML ImageView imageView; // leave uninitialized, will be injected
String imageURL;
Main main;
public void setMain(Main main) {
this.main = main;
}
public void updateImage(String url) {
if (url.length() >= 1) {
Image image = new Image(url);
imageView.setImage(image);
System.out.println(url);
} else {
System.out.println(url);
System.out.println("image invalid");
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {}
}
Note: Did not test new code.

JavaFX FadeTransition in after init is finished via controler

I have this Application:
public class FOO extends Application {
private Scene scene;
#Override
public void start(Stage stage) throws Exception {
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
#Override
public void init() throws Exception {
URL resource = FXMLTabPaneController.class.getResource("FXMLTabPane.fxml");
System.out.println(resource);
Parent root = FXMLLoader.load(resource);
scene = new Scene(root);
}
}
And this as a controler:
public class FXMLTabPaneController implements Initializable {
#FXML
private TabPane tabPane;
#FXML
private AnchorPane anchorPane;
#Override
public void initialize(URL url, ResourceBundle rb) {
FadeTransition fadein = new FadeTransition(Duration.seconds(5), tabPane);
fadein.setFromValue(0);
fadein.setToValue(1);
fadein.play();
}
}
I wanted to show the Tabpane slowly after app start but it start with app Tabpane already seen.
Try this:
public class FXMLTabPaneController {
#FXML
private TabPane tabPane;
#FXML
private AnchorPane anchorPane;
#FXML
private void initialize() {
}
public void show(WindowEvent event) {
FadeTransition fadein = new FadeTransition(Duration.seconds(5), tabPane);
fadein.setFromValue(0);
fadein.setToValue(1);
fadein.play();
}
}
and FOO class
public class FOO extends Application {
private Scene scene;
private FXMLTabPaneController controller;
#Override
public void init() throws Exception {
super.init();
URL resource = FXMLTabPaneController.class.getResource("FXMLTabPane.fxml");
System.out.println(resource);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(resource);
Parent root = loader.load();
controller = loader.getController();
scene = new Scene(root);
}
#Override
public void start(Stage stage) throws Exception {
stage.setOnShown(controller::show);
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}

How to get reference to another controller - JavaFX

Let's say I've got 3 views and 3 controllers:
LogInController, LogInView
MainMenuController, MainMenuView
ListOfPatientsInternalMedicineController, ListOfPatientsInternalMedicineView.
An internalMedicineButtonClicked method change my scene to another (with some other content) but in this new scene, I want to have a button which allows me to go back to MainMenu (goBacktoMainMenuButtonClicked() method). And here occures my problem. How am I able to get reference to MainMenuController (the one which is corresponding with fxml file, created in LogInController) to fill setController() method.
public class LogInController {
MainMenuController mainMenuController = new MainMenuController();
#FXML
private JFXTextField logInTextField;
#FXML
private JFXButton logInButton;
#FXML
private JFXPasswordField passwordTextField;
#FXML
void logInButtonClicked(ActionEvent event) throws IOException {
LogInDAO logInDAO = new LogInDAO();
if(logInDAO.checkIfLoginAndPasswordIsCorrect(logInTextField.getText(),passwordTextField.getText()))
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MainMenu.fxml"));
Window window = logInButton.getScene().getWindow();
Stage stage = (Stage) window;
loader.setController(mainMenuController); // here i'm passing original controller corresponding with fmxl
stage.setScene(new Scene(loader.load()));
}
else
{
(...)
}
}
}
MainMenuCotroller class:
public class MainMenuController {
ContentOfPatientTableView patientTableViewModel = new ContentOfPatientTableView();
(..)
#FXML
void internalMedicineButtonClicked(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/ListOfPatientsInternalMedicineView.fxml"));
Button button = (Button) event.getSource();
Scene scene = button.getScene();
Stage stage = (Stage) scene.getWindow();
loader.setController(new ListOfPatientsInternalMedicineController(patientTableViewModel));
stage.setScene(new Scene(loader.load()));
}
And ListOfPatientsInternalMedicineController class;
public class ListOfPatientsInternalMedicineController {
IPatientDAO patientDAO = new PatientDAO();
ContentOfPatientTableView patientTableViewModel;
public ListOfPatientsInternalMedicineController(ContentOfPatientTableView content) {
patientTableViewModel=content;
}
#FXML
public void goBacktoMainMenuButtonClicked(ActionEvent event)
{
FXMLLoader loader = new FXMLLoader(MainMenuController.class.getResource("/fxml/MainMenuView.fxml");
loader.setController(?????????); // Here if I will pass new MainController() i will create new instance, not this which is corresponding with fxml file. How am I able to refer to instance MainController created in LogInController ?
}
}
Consider using another model to represent the current view. You could implement this along the following lines:
public class ViewState {
private final ContentOfPatientTableView patientTableViewModel ;
private final ReadOnlyObjectWrapper<Parent> currentView = new ReadOnlyObjectWrapper<>();
private Parent logInView ;
private Parent mainMenuView ;
private Parent listOfPatientsMainMedicineView ;
public ViewState(ContentOfPatientTableView patientTableViewModel) {
this.patientTableViewModel = patientTableViewModel ;
}
public ReadOnlyObjectProperty<Parent> currentViewProperty() {
return currentView.getReadOnlyProperty();
}
public void showLogIn() {
if (logInView == null) {
try {
FXMLLoader loader = new FXMLLoader("/fxml/LogIn.fxml");
loader.setController(new LogInController(this));
logInView = loader.load();
} catch (IOException exc) {
// fatal...
throw new UncheckedIOException(exc);
}
}
currentView.set(logInView);
}
public void showMainMenu() {
// similarly...
}
public void showListOfPatientsMainMedicineView() {
// ...
}
}
Now your LogInController can do:
public class LogInController {
private final ViewState viewState ;
#FXML
private JFXTextField logInTextField;
#FXML
private JFXButton logInButton;
#FXML
private JFXPasswordField passwordTextField;
public LogInController(ViewState viewState) {
this.viewState = viewState ;
}
#FXML
void logInButtonClicked(ActionEvent event) {
LogInDAO logInDAO = new LogInDAO();
if(logInDAO.checkIfLoginAndPasswordIsCorrect(logInTextField.getText(),passwordTextField.getText()))
{
viewState.showMainMenu();
}
else
{
(...)
}
}
}
Similarly,
public class MainMenuController {
private final ViewState viewState ;
public MainMenuController(ViewState viewState) {
this.viewState = viewState ;
}
#FXML
void internalMedicineButtonClicked(ActionEvent event) throws IOException {
viewState.showListOfPatientsMainMedicineView();
}
}
and similarly for the other controller.
Note that you are instantiating each controller in ViewState, so just give that class access to each of the other models it may need.
Finally, you boot all this up with
public class MyApp extends Application {
#Override
public void start(Stage primaryStage) {
ViewState viewState = new ViewState(/* pass models here...*/);
viewState.showLogIn();
Scene scene = new Scene(viewState.currentViewProperty().get());
scene.rootProperty().bind(viewState.currentViewProperty());
primaryStage.setScene(scene);
primaryStage.show();
}
}

How can I open a new Scene from a different class

I have a simple button that i want to click and open a new scene but i made the new scene in another class but it doesn't work and it does not show my errors either.
Here is my Controller class
public class Controller
{
public TextField txtUsername;
public TextField txtEmail;
public TextField txtPass;
public TextField txtPhone;
public Button btnLogin;
}
public void buttonClicked()
{
Chattingform chattingform = new Chattingform ();
}
Here is my Chattingform class
public class Chattingform extends Application
{
#Override
public void start (Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Chattingform.fxml"));
try {
Parent root = fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setOpacity(1);
stage.setTitle("Exchat");
stage.setScene(new Scene (root, 450, 450));
stage.showAndWait();
}catch ( IOException io )
{
JOptionPane.showMessageDialog (null, "Could not open ");
}
}
From my experince, all JavaFX Controllers have:
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}

Close the login page in javafx when open a new stage

Hi I am creating a login page and a dashboard page I want to close or hide my login page and Show Dashboard When I Click on Login Button. but its not working
public class LoginController implements Initializable {
#FXML
private TextField txtUser;
#FXML
private PasswordField txtPassword;
#FXML
private Label message;
#FXML
private Label lblUser;
#FXML
private Label lblPassword;
#FXML
private void OpenDashBoard(ActionEvent event) {
try {
FxmlMethods object = new FxmlMethods();
// showFxml method usd for open a new window named DashBoard.fxml
object.showFxml("/DashBoard/DashBoard.fxml", "/ DashBoard/DashboardStyle.css", "Dash Board");
} catch (Exception exception) {
exception.printStackTrace();
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
And My Main Class is :
public class DATACOLLECTION extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Login.fxml"));
stage.getIcons().add(new Image("/images/icon.png"));
Scene scene = new Scene(root);
stage.setTitle("Login");
stage.setScene(scene);
scene.getStylesheets().addAll(this.getClass().getResource("Login.css").toExternalForm());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
please help me
I am using this and its working Thanks to all for your Response.
#FXML
private void CloseAction(ActionEvent event) {
Stage stage = (Stage) Close.getScene().getWindow();
stage.close();
}

Resources