I have two .fxml and two Controller.
At first, the Guest Information (blue) is shown and whenever the "Add" button is clicked, then it will pop up another stage (grey/white) to search for a Guest with ICnumber.
My plan when I done searching for a Guest(grey), I will click the "Add Guest" button, the stage(grey) will close and all the value will be passed to the Guest Information (blue).
#FXML //Guest Information (blue stage)
void addGuest(ActionEvent event) throws IOException {
iclb.setText("ok"); //ignore this
Parent root = FXMLLoader.load(getClass().getResource("Guest.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle("Hotel System - Guest Information");
stage.setResizable(false);
stage.show();
}
public void addGuestInfo(String icno) {
iclb.setText(icno); // this is the label for IC Number
}
--
#FXML //Search Guest (grey stage)
void addGuest(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MenuDraft.fxml"));
Parent root = loader.load();
MenuController menu = loader.getController();
menu.addGuestInfo(ictf.getText());
Stage stage = (Stage) addbt.getScene().getWindow();
stage.close();
}
So far I manage to search a Guest and able to close the grey stage by clicing the "Add Guest" button, but those value didn't pass to the Guest Information (blue stage).
Im very new in using Javafx... anyone can give me a hand on this?
In your second ("grey") controller you can do this:
public class AddGuestController {
// I assume you have a Guest class to encapsulate the data in the form
private Guest guest = null ;
public Guest getGuest() {
return guest ;
}
#FXML
private void addGuest(ActionEvent event) {
guest = new Guest( /* data from form controls... */ );
addbt.getScene().getWindow().hide();
}
}
Then back in the first ("blue") controller, you can use stage.showAndWait() to block execution until the window closes, and check if a guest was created:
#FXML //Guest Information (blue stage)
private void addGuest(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Guest.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle("Hotel System - Guest Information");
stage.setResizable(false);
stage.showAndWait();
AddGuestController controller = loader.getController();
Guest guest = controller.getGuest();
if (guest != null) {
// update view from guest:
iclb.setText(guest.getIcNumber();
// etc.
}
}
Related
I am making a JavaFX app. I have create a Menuitem About. Upon clicking on the About Menuitem it will display a new window with some info about my app. The window is a Anchor Pane with custom close button. I have set the stage undercoated at run time. I want to close this window without closing my main application. I don't want to set its visibility turn off on method call. I see some solution in net like Window existingWindow = ((Node) event.getSource()).getScene().getWindow(); but i can't use this as am getting error similar to this Menu item not cast node javafx scene. How can I achieve this goal?
Actually this is not my own answer, but I managed to understand #James_D. I usually create to manage open windows, otherwise I have to write a lot of code And this is solution code.
In your controller class:
#FXML
void openAnotherWindow(ActionEvent actionEvent) {
try {
OpenWindow.openWindowMenuItem(someLabel, "views/some.fxml", "Title", 600, 400,
false, "resources/pictures/some_icon.png");
} catch (IOException e) {
e.printStackTrace();
}
}
And OpenWindow class
public class OpenWindow {
public static void openWindowMenuItem(Node label, String recource, String title,
int width, int height, boolean resizeable, String icon) throws IOException {
Parent root = FXMLLoader.load(Objects.requireNonNull(OpenWindow.class.getClassLoader().getResource(recource)));
Stage stage = new Stage();
Scene scene = new Scene(root, width, height);
if (icon != null) {
stage.getIcons().add(new Image(icon));
}
stage.setTitle(title);
stage.setResizable(resizeable);
stage.setScene(scene);
stage.show();
// close current window
label.getScene().getWindow().hide(); // this is key point
}
}
You can do it event without extra class. Hope it will help and again thanks to #James_D
I have two classes, the first meant to control the modality of the 2nd class.
It has 2 Button: btn1 set the modality to none, btn2 sets the modality to APPLICATION_MODAL.
I can press only one button (it creates the window with the new stage with wanted modality) but when I close this window and I try to press the other button i always get the "Cannot set owner once stage has been set visible"
//My control class:
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start( Stage stage) {
stage.setTitle("Blank Stage 1");
Button okBtn = new Button("OK");
Button okBtn2 = new Button("OK");
VBox root = new VBox();
root.getChildren().add(okBtn);
root.getChildren().add(okBtn2);
Scene scene = new Scene(root, 200, 100);
stage.setScene(scene);
stage.setTitle("A Dialog Box");
stage.show();
okBtn.setOnAction(e -> {
try {
showDialog();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
});
okBtn2.setOnAction(e -> {
try {
showDialog(stage, APPLICATION_MODAL);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
});
}
private void showDialog(Window owner, Modality modality) throws Exception {
BlankStage MyC = new BlankStage();
MyC.start(BlankStage.classStage, owner, modality);
}
private void showDialog() throws Exception {
BlankStage MyC = new BlankStage();
MyC.start(BlankStage.classStage);
}
}
//This is my2nd class:
public class BlankStage extends Application {
public static void main(String[] args) {
Application.launch(args);
}
static Stage classStage = new Stage();
public void start(Stage primaryStage, Window owner, Modality modality) {
classStage = primaryStage;
primaryStage.initOwner(owner);
primaryStage.initModality(modality);
primaryStage.setTitle("Blank Stage");
primaryStage.setHeight(100);
primaryStage.setWidth(300);
primaryStage.show();
}
#Override
public void start(Stage primaryStage) throws Exception {
classStage = primaryStage;
primaryStage.setTitle("No Modality Stage");
primaryStage.setHeight(100);
primaryStage.setWidth(300);
primaryStage.show();
}
}
i tried to use
- close(); and hide(); (actually they are the same). no effect.
- platform.exit(), of course it closes my whole application :)
- Showandwait in booth classes (I got more errors)
have no idea how could I close the 2nd Window permanently (or reset the modality values...:( )
Your question itself holds the answer: Cannot set owner once stage has been set visible.
Stage#initOwner method's javadoc:
Specifies the owner Window for this stage, or null for a top-level,
unowned stage. This must be done prior to making the stage visible.
#param owner the owner for this stage.
#throws IllegalStateException if this property is set after the stage
has ever been made visible.
#throws IllegalStateException if this stage is the primary stage.
#defaultValue null
if it is so... so be it.:)
Meanwhile I found a workaround.
I added some simple lines in Control Class:
private void showDialog(Window owner, Modality modality) throws Exception {
MyCalenderModal MyC = new MyCalenderModal();
System.out.println(MyCalenderModal.classStage.getModality());
if (MyCalenderModal.classStage.getModality()==NONE) {
MyC.start(MyCalenderModal.classStage, owner, modality);
}
else MyC.start(MyCalenderModal.classStage);
}
It checks whether the 2nd window already has a modality. If yes its only shows the stage.
I have to keep in my mind, if I opened a window, I can not close it anymore until my application runs.
I'm facing an issue with JavaFX 8u40 where creating two or more modal windows will cause a system beep on Mac OS X when closing the children windows.
The example below creates a modal window who's a child of another modal window. When I close the child modal window, my system beeps (the same way it beeps if I try to click on the parent modal window).
The problem seems related to stage.initOwner(...) where closing the child modal window tries to access the parent modal window before the showAndWait() loop is finished.
I just want to confirm I'm not doing anything wrong before filing a bug report.
public class TestDialog extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Button showModalButton = new Button("Show Modal Window");
showModalButton.setOnAction(e -> {
Stage modalStage = new Stage();
modalStage.initModality(Modality.WINDOW_MODAL);
modalStage.initOwner(stage);
Button createInnerModalButton = new Button("Create inner modal window");
createInnerModalButton.setOnAction(e2 -> {
Stage innerModalStage = new Stage();
innerModalStage.initModality(Modality.WINDOW_MODAL);
innerModalStage.initOwner(modalStage);
Button closeInnerModalButton = new Button("Close");
closeInnerModalButton.setOnAction(e3 -> {
innerModalStage.close();
});
VBox innerVBox = new VBox(
new Label("This is an inner modal window"), closeInnerModalButton);
innerModalStage.setScene(new Scene(innerVBox));
innerModalStage.showAndWait();
});
VBox vBox = new VBox(
new Label("This is a modal window"), createInnerModalButton);
modalStage.setScene(new Scene(vBox));
modalStage.showAndWait();
});
stage.setScene(new Scene(showModalButton));
stage.show();
}
}
Following is my code to show popup windows in my JavaFx Desktop Application.
public boolean popup(Object parent, ViewModelBase viewModel, AsyncCommand cancelCommand) {
javafx.scene.layout.Pane root = null;
try
{
if(!IOC.platformInfo.isPlatformThread())
{
return PlatformUtil.runAndWait(()->
{
return popup(parent,viewModel,cancelCommand);
});
}
String name = viewModel.getClass().getSimpleName();
name = Pattern.compile("(viewModel|Controller)$",Pattern.CASE_INSENSITIVE)
.matcher(name).replaceAll("View");
FXMLLoader loader = new FXMLLoader(com.technoinn.videoprospector.ui.fx.service.WindowService
.class.getResource(String.format("/fxml/%s.fxml",name))
, null, new JavaFXBuilderFactory(), new IocControllerFactory());
if(viewModel instanceof ControllerBase)
{
loader.setController(viewModel);
}
root = loader.load();
if(!(viewModel instanceof ControllerBase))
{
Object controller = loader.getController();
if(controller instanceof ControllerBase)
{
((ControllerBase)controller).setViewModel(viewModel);
}
}
jfxtras.scene.control.window.Window window =
new jfxtras.scene.control.window.Window(viewModel.getDisplayName());
window.getContentPane().getChildren().add(root);
window.setPrefSize(root.getPrefWidth(), root.getPrefHeight());
window.setMinSize(root.getPrefWidth(), root.getPrefHeight());
CloseIcon closeIcon = new CloseIcon(window);
window.getLeftIcons().add(closeIcon);
Scene scene = new Scene(window);
// Scene scene = new Scene(root);
scene.getStylesheets().add(FxModule.StyleFile);
Stage stage = new Stage(StageStyle.UNDECORATED);
stage.setResizable(true);
stage.setMinWidth(root.getPrefWidth());
stage.setMinHeight(root.getPrefHeight());
viewModel.addPropertyChangeListener(ViewModelBase.closeCommand,
(x)->
{
if(x.getNewValue()!=null && x.getNewValue()==Boolean.TRUE)
{
stage.close();
}
});
closeIcon.setCursor(Cursor.HAND);
closeIcon.setOnAction((x)->
{
if(cancelCommand!=null)
cancelCommand.beginExecution();
else
stage.close();
});
/*
stage.setOnCloseRequest((WindowEvent event) -> {
if(cancelCommand!=null)
cancelCommand.beginExecution();
else
stage.close();
});*/
stage.setScene(scene);
stage.centerOnScreen();
stage.initModality(Modality.APPLICATION_MODAL);
if(!parentWindows.isEmpty())
{
stage.initOwner(parentWindows.peek());
stage.initModality(Modality.WINDOW_MODAL);
}
parentWindows.push(stage);
stage.showAndWait();
parentWindows.pop();
}catch(Exception exp)
{
Logger.getGlobal().log(Level.SEVERE,"Error in popup",exp);
}
return true;
}
Problem is, popup shows well and in proper size on my machine.(Dev Machine). But size on target client machine is unpredictable. Sometimes it is very small and sometimes it does not even show the content pane of the popup window. Client machine has jRE 1.8_31. Any idea what can be wrong. Client machine size is same as that of my dev machine.
Thanks
Most probably you are calling next code too soon:
window.setPrefSize(root.getPrefWidth(), root.getPrefHeight());
window.setMinSize(root.getPrefWidth(), root.getPrefHeight());
and
stage.setMinWidth(root.getPrefWidth());
stage.setMinHeight(root.getPrefHeight());
Most layout values are being calculated only after scene is shown. Try to move such code after call to
stage.showAndWait();
I'm working on a mini application where I need to display to users 2 windows at the same time.
I'm working with JavaFx Scene Builder 2.0 on NetBeans 8.0.1
is it possible to do this? if so, how it can be done ?
Thank you!
By "screen" I assume you mean "window".
Just create a second stage in your start() method and do exactly the same with it as you do your primary stage:
public class MyApp extends Application {
#Override
public void start(Stage primaryStage) {
Stage anotherStage = new Stage();
try {
FXMLLoader loader = new FXMLLoader(...); // FXML for primary stage
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
FXMLLoader anotherLoader = new FXMLLoader(...) ; // FXML for second stage
Parent anotherRoot = anotherLoader.load();
Scene anotherScene = new Scene(anotherRoot);
anotherStage.setScene(anotherScene);
anotherStage.show();
} catch (Exception exc) {
exc.printStackTrace();
}
}
public static void main(String[] args) { launch(args); }
}