How to close a dialog box programmatically - javafx

please I need some assistance. I have this java fx project I am working on. The idea is to prevent the default windows close button behavior, and only close the dialog if login is successful.
Below is how I am able to set the dialog and prevent dialog closing.
public class MainController extends Application implements Initializable{
// Create a dialog
private Dialog<Pair<String, String>> dialog = new Dialog<>();
/*Login resources*/
#FXML // fx:id="loginBtn"
private Button loginBtn; // Value injected by FXMLLoader
#FXML // fx:id="usernameTxt"
private TextField usernameTxt; // Value injected by FXMLLoader
#FXML // fx:id="loginProgressIndicator"
private ProgressIndicator loginProgressIndicator; // Value injected by FXMLLoader
#FXML // fx:id="passwordTxt"
private PasswordField passwordTxt; // Value injected by FXMLLoader
#FXML // fx:id="statusLbl"
private Label statusLbl; // Value injected by FXMLLoader
#FXML
void login(ActionEvent event) {
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
stage.fireEvent(
new WindowEvent(
stage,
WindowEvent.WINDOW_CLOSE_REQUEST
)
);
}
/*Main Menu resources*/
#FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;
#FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;
#FXML // fx:id="visitBtn"
private Button visitBtn; // Value injected by FXMLLoader
#FXML // fx:id="reportBtn"
private Button reportBtn; // Value injected by FXMLLoader
#FXML // fx:id="setupBtn"
private Button setupBtn; // Value injected by FXMLLoader
#FXML
void report(ActionEvent event) {
}
#FXML
void setup(ActionEvent event) {
}
#FXML
void visit(ActionEvent event) {
System.out.println("Visit Button Pressed.");
}
/**
* The main entry point for all JavaFX applications.
* The start method is called after the init method has returned,
* and after the system is ready for the application to begin running.
* <p>
* <p>
* NOTE: This method is called on the JavaFX Application Thread.
* </p>
*
* #param primaryStage the primary stage for this application, onto which
* the application scene can be set. The primary stage will be embedded in
* the browser if the application was launched as an applet.
* Applications may create other stages, if needed, but they will not be
* primary stages and will not be embedded in the browser.
*/
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Main Menu - PEHCS Point of Sale");
primaryStage.setScene(scene);
primaryStage.show(); //This will display the main menu
dialog.setTitle("Login - PEHCS Point of Sale");
dialog.setHeaderText(null);
// Get the Stage.
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
// Add a custom icon.
stage.getIcons().add(new Image(this.getClass().getResource("activa.jpg").toString()));
/*This section prevents the dialog from closing when we press on the window X button*/
Window window = dialog.getDialogPane().getScene().getWindow();
window.setOnCloseRequest(new EventHandler<WindowEvent>() {
/**
* Invoked when a specific event of the type for which this handler is
* registered happens.
*
* #param event the event which occurred
*/
#Override
public void handle(WindowEvent event) {
event.consume();
}
});
/*Set th content of that dialog to be the login.fxml resource file*/
dialog.getDialogPane().setContent(FXMLLoader.load(getClass().getResource("login.fxml")));
Optional<Pair<String, String>> result = dialog.showAndWait();
result.ifPresent(usernamePassword -> {
System.out.println("Username=" + usernamePassword.getKey() + ", Password=" + usernamePassword.getValue());
});
}
/**
* Called to initialize a controller after its root element has been
* completely processed.
*
* #param location The location used to resolve relative paths for the root object, or
* <tt>null</tt> if the location is not known.
* #param resources The resources used to localize the root object, or <tt>null</tt> if
*/
#Override
public void initialize(URL location, ResourceBundle resources) {
assert visitBtn != null : "fx:id=\"visitBtn\" was not injected: check your FXML file 'main2.fxml'.";
assert reportBtn != null : "fx:id=\"reportBtn\" was not injected: check your FXML file 'main2.fxml'.";
assert setupBtn != null : "fx:id=\"setupBtn\" was not injected: check your FXML file 'main2.fxml'.";
assert loginBtn != null : "fx:id=\"loginBtn\" was not injected: check your FXML file 'login.fxml'.";
assert usernameTxt != null : "fx:id=\"usernameTxt\" was not injected: check your FXML file 'login.fxml'.";
assert loginProgressIndicator != null : "fx:id=\"loginProgressIndicator\" was not injected: check your FXML file 'login.fxml'.";
assert passwordTxt != null : "fx:id=\"passwordTxt\" was not injected: check your FXML file 'login.fxml'.";
assert statusLbl != null : "fx:id=\"statusLbl\" was not injected: check your FXML file 'login.fxml'.";
}
public static void main(String[] args) {
launch(args);
}
The window close event is being consume in the on start method and it works. Now I want to close this dialog in th login methos. This is where I am stuck. Please I need help.
Thanks in advance.

To close the window programmatically, all you need is
#FXML
void login(ActionEvent event) {
dialog.close();
}
Note that this will not trigger an onCloseRequest handler, which is only invoked for an external request to close the window (see docs).

Related

How to access JavaFx node elements values in methods of FXML Controller class?

It seems values of nodes (textfields, checkboxes, etc...) can only be accessed via an event listener on them. Why am I saying that ?
- First I'm new to JavaFx
- Second : below is the scenario I'm using
public class FXMLDocumentController implements Initializable {
#FXML
private JFXCheckBox myCheckBox;
#FXML
private JFXButton myButton;
#Override
public void initialize(URL url, ResourceBundle rb) {
myCheckBox.addEventHandler(MouseEvent.MOUSE_CLICKED, (e)->{
if(myCheckBox.isSelected()){
System.out.Println("Printed from event handler");
});
myButton.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
myMethod();
});
}
public void myMethod(){
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
for(Node node : root.getChildrenUnmodifiable()){
if(node.getId().equals("myCheckBox"){
JFXCheckBox myChk = (JFXCheckBox) node;
if(myChk.isSelected()){
System.out.Println("Printed from my inner method");
}
System.out.Println(myChk.isSelected());
}
}
}
}
What happend is when I check the box, the event handler does how supposed. It prints Printed from event handler. But right afetr that, when clicking myButton, the myMethod always prints false.
When I use a class variable indicating if the checkbox is selected and read it in myMethod, it says the check box has been checked ...
What is going on ?
The same thing happens with textfields ...

How to add a actionListener to a label in JavaFx

i'm trying to add an ActionListener to a label whitch pop out whenever user types wrong password or login.
Here is my Login Controller
public class LoginController implements Initializable {
#FXML
private Label label;
#FXML
private TextField LoginField;
#FXML
private PasswordField PasswdField;
#FXML
private Button LogInButton;
#FXML
private Label IncorrectDataLabel;
//private String uri = "http://google.com";
#FXML
private void LogIn(ActionEvent event) throws IOException {
if(LoginField.getText().equals("MKARK")&&PasswdField.getText().equals("KACZOR1"))
{
Parent parent = FXMLLoader.load(getClass().getResource("/fxmlFiles/MainScreen.fxml"));
Scene MainScene = new Scene(parent);
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
stage.setScene(MainScene);
stage.show();
}
else
{
IncorrectDataLabel.setVisible(true);
// <------------------- Here I want to bind hyperlink to a label with would open the google site, whenever user clicks it.
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
How am i able to fix that issue? I've tried many times (setOnAction, addMouseListener) but nothing worked :(.
If You dont mind i would also ask about the public void initialize function. What is it for? It pop out automatically when i created the class.
Thanks in advance
Labels do not fire action events. You could use a listener for mouse clicked events, e.g:
#FXML
private void gotoGoogle() {
// open url etc
}
and in the FXML file
<Label fx:id="IncorrectDataLabel" onMouseClicked="#gotoGoogle" ... />
However, it probably makes more sense to use a Hyperlink for this, which would give the user better visual feedback that it was something on which they were expected to click. Just replace the label with
<Hyperlink fx:id="IncorrectDataLabel" onAction="#gotoGoogle" text="..." ... />
and update the type in the controller accordingly:
#FXML
private Hyperlink IncorrectDataLabel ;
You need the appropriate import for javafx.control.Hyperlink in both the FXML file and in the controller.
Off-topic note: use proper Java naming conventions for your variable and method names.

Accessing node from outside its controller JavaFX - MVC

I'm building a weather application. There are 2 scenes with 2 controller files. One is a main screen and the other one is for "settings". The main FXML contains a label, which must be turned on/off in the settings page, if the user does not want to see that extra bit of information. My question is how to setVisible that label from the controller class of the setting page, if it's possible at all.
Thanks for your help
I'm assuming the settings scene only comes up when the user clicks a button on the main screen. I have had to handle the same situation in my code recently. Here is a great tutorial that handles this situation:
http://code.makery.ch/library/javafx-2-tutorial/part1/
1.) In your MainScene Controller you will reference the main class and call its function to pop up the Settings Scene.
2.) In your main class you will have a function that pops up the Settings Scene
3.) After the Settings Scene is closed it will pass the value back to the MainScene Controller through the Main class and based on the returned value you can set the label.
1.) Your MainController for your Main scene will have a reference to the main class and a function to call the Settings Scene through the main class.
public class MainController {
#FXML
private Label label;
#FXML
private Button Settings;
// Reference to the main application
private MainApp mainApp;
/**
* The constructor.
* The constructor is called before the initialize() method.
*/
public MainController() {
}
/*Tie this function to your button that pops up Settings */
private void handleSettingsButton() {
/* Here you call a function in the main class and pass the label
* to the settings scene controller */
boolean show = mainApp.showSettingsScene(label);
if (show) {
label.isVisible("True");
}
else {
label.isVisible("False");
}
}
/**
* Is called by the main application to give a reference back to itself.
*
* #param mainApp
*/
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
}
2.) In your main class (not to be confused with your main scene) you load the Main scene and call the setMainApp function to give your controller a reference back to the Main Class.
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Main");
/*Right when the app is loaded the MainScene shows up.*/
try {
// Load the root layout from the fxml file
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/MainScene.fxml"));
/* Get a reference to the controller instance of the main Scene */
mainSceneController = loader.getController();
/*Allow the controller to talk to the main class */
mainSceneController.setMainApp(this);
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
// Exception gets thrown if the fxml file could not be loaded
e.printStackTrace();
}
}
/**
* Returns the main stage.
* #return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
/*This function referenced in your main controller will show the Settings
*Scene and wait to see what the user has selected for the visible or not
*visible selection. We need to pass the label to it as well, so we
*accurately load the Settings Scene with the current state of the label
*/
public boolean showSettingsScene(Label label) {
try {
// Load the fxml file and create a new stage for the popup
FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/SettingsScene.fxml"));
settingsSceneController = loader.getController();
/* Here we send the label to the controller instance of the Settings
* Scene */
controller.setLabel(label);
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Settings");
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
/* Show the dialog and wait until the user closes it*/
dialogStage.showAndWait();
/*Return the value that the user has selected for visible or not */
return controller.isShowOrHide();
} catch (IOException e) {
// Exception gets thrown if the fxml file could not be loaded
e.printStackTrace();
return false;
}
}
public static void main(String[] args) {
launch(args);
}
}
3.) Your Settings Scene Controller will look something like the following:
import...
public class SettingsSceneController{
#FXML private ComboBox showOrHide;
private Stage dialogStage;
private Boolean show = false;
private Label label;
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded.
*/
#FXML
private void initialize() {
;I don't know what you have, but if you use a Combobox...
showOrHide.getItems().addAll(
"Show",
"Hide",);
}
/**
* Sets the stage of this dialog.
* #param dialogStage
*/
public void setDialogStage(Stage dialogStage) {
this.dialogStage = dialogStage;
}
/*The label that was passed from Main Scene Controller to Main Class to
* here is now used in the function to update the Combobox with the
* current status of the label */
public void setLabel(Label label) {
this.label = label;
if(label.isVisible){
showOrHide.setValue("Show");
show = true;
}
else{
showOrHide.setValue("Hide");
show = false;
}
}
/**
* Returns true if the user clicked OK, false otherwise.
* #return
*/
public boolean isShowOrHide() {
return show;
}
/**
* Called when the user clicks ok. Attach this in Scene Builder,to the OK,
* Enter or Apply or whatever you called it button of the Settings Scene
* It will reflect any change made to the combobox.
*/
#FXML
private void handleOk() {
if (showOrHide.getValue().toString() == "Show") {
show= true;
}
else{
show = false;
}
dialogStage.close();
}
/**
* Called when the user clicks cancel if you have a cancel button.
*/
#FXML
private void handleCancel() {
dialogStage.close();
}
}
}
I took most of this code from the tutorial and custom tailored it to your solution. It is kind of bouncing around to three classes, but if you think on it a little bit you can see how they are communicating between the controllers using the main class to facilitate it. I did not test this, but it should be pretty close to what you need.

how to share data between two stages in javafx

I have two fxml window login and main window.Their respective controllers are given below:
public class MainwindowController extends Stage implements Initializable {
#FXML private Button Send;
#FXML private TextField txtBcast;
#FXML private ListView listviewUsers;
#FXML Label lblDisplayName;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
ObservableList<String> chat =FXCollections.observableArrayList ("default");
listviewUsers.setItems(chat);
}
public void setLblName(String msg){
lblDisplayName.setText(msg);
}
#FXML public void ActionSend(ActionEvent e){
send();
txtBcast.setText("");
}
private void send() {
if (txtBcast.getText().isEmpty())
return;
// chatManager.sendPublicMsg(format,txtBcast.getText());
}
/**
*
* #param e
* #throws Exception
*/
#FXML public void ActionUserSelected( MouseEvent e) throws Exception{
// String lineRest = e.getActionCommand();
if(e.getClickCount()==2)
{
if(!listviewUsers.getSelectionModel().isEmpty())
{
String str=(String)listviewUsers.getSelectionModel().getSelectedItem();
Parent main= FXMLLoader.load(getClass().getResource("/letschat/fxwindows/Usertab.fxml"));
Scene scene = new Scene(main);
Stage stage = new Stage();
stage.setTitle(str);
stage.setScene(scene);
stage.show();
}
else { JOptionPane.showMessageDialog(null, "Oops! it seems you are trying to click the list view"); }
}
//Stage pstage = (Stage)listUsers.getScene().getWindow();
//pstage.close();
}
}
And
public class LoginwindowController extends Stage implements Initializable {
#FXML private LoginwindowController loginwindowController;
#FXML private MainwindowController mainwindowController;
#FXML private Button btnSignIn;
#FXML private TextField txtDisplayName;
#FXML private ToggleGroup Gender;
#FXML private ComboBox comboStatus;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
ObservableList<String> items =FXCollections.observableArrayList ("Online","Offline");
comboStatus.setItems(items);
writeToTextField();
}
public void writeToTextField() {
String username = System.getProperty("user.name");
txtDisplayName.setText(""+ username);
}
#FXML protected void ActionSignIn(ActionEvent event) throws Exception {
mainwindowController.setLblName(txtDisplayName.getText());
InetAddress addr = InetAddress.getLocalHost();
if(addr.isLoopbackAddress())
{
Dialogs.create().message("Oops! It seems you are not connected to any network..\n :(").showError();
}
else{
start(txtDisplayName.getText());// start chat manager
Parent root= FXMLLoader.load(getClass().getResource("/letschat/fxwindows/Mainwindow.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setTitle("LetsChat-Welcome "+ txtDisplayName.getText());
// Context.getInstance().setDisplayName(txtDisplayName.getText());
stage.setScene(scene);
stage.getIcons().add(new Image("/letschat/images/logo.png"));
Stage pstage = (Stage)btnSignIn.getScene().getWindow();
stage.show();
pstage.close();
}
}
private void start(String name) {
try {
ChatManager ic = new ChatManager(name);
ic.start();
} catch (Exception ex) {
Dialogs.create().message( "Could not start the chat session\nCheck that there no other instances running :(").showError();
}
}
}
I want the label lblDisplayName in main window updated with text from txtDisplay Name in login window when user clicks signin button.can someone help how to do so..soon plz
There are various ways to do this, in your case Login will create the other stage so an easy way is to create a new FXML loader (variable name: myLoader) and, if you want to pass the username of the user as constructor argument you can use myLoader.setControllerFactory and as return:
return clazz == MyController.class ? new MyController(userName) : null;
MyController is the name of the Controller where you want to read the username
If you want to use set methods, with getController you get the controller instance and call the set method (e.g, myController.setUsername());
To create a custom FXML
FXMLLoader myLoader = new FXMLLoader(<if you use relative paths, here you should pass the position);
remember to call the load() because the URI overload is static. (i.e, use getResourceAsStream).
If your application is large and complex, you could use EventBus (which I prefer everywhere..)
I'm not sure I completely understand the relationship between the two controllers, and which are the FXML files that correspond to the controllers, but it looks like the LoginWindowController loads MainWindow.fxml, and I'm guessing that MainWindowController is the controller for MainWindow.fxml.
In that case, you can just do
#FXML protected void ActionSignIn(ActionEvent event) throws Exception {
InetAddress addr = InetAddress.getLocalHost();
if(addr.isLoopbackAddress())
{
Dialogs.create().message("Oops! It seems you are not connected to any network..\n :(").showError();
}
else{
start(txtDisplayName.getText());// start chat manager
FXMLLoader loader = new FXMLLoader(getClass().getResource("/letschat/fxwindows/Mainwindow.fxml"));
Parent root= loader.load();
MainWindowController mainWindowController = loader.getController();
mainWindowController.setLblName(txtDisplayName.getText());
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setTitle("LetsChat-Welcome "+ txtDisplayName.getText());
// Context.getInstance().setDisplayName(txtDisplayName.getText());
stage.setScene(scene);
stage.getIcons().add(new Image("/letschat/images/logo.png"));
Stage pstage = (Stage)btnSignIn.getScene().getWindow();
stage.show();
pstage.close();
}
}

javafx fxml is null outside initialize()

In this code:
public class ESM extends Application {
private Stage primaryStage;
#FXML
private ToolBar mainToolBar;
#Override
public void start(final Stage stage) throws Exception {
try{
this.primaryStage = stage;
Parent root = FXMLLoader.load(getClass().getResource("/nz/co/great_ape/esm3/main_window.fxml"));
Scene scene = new Scene(root, 800, 700);
// Setup main stage to be full screen, no min or max buttons.
// TODO: How will this handle multiple screens? Apparently not well :-(
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
primaryStage.setX(bounds.getMinX());
primaryStage.setY(bounds.getMinY());
primaryStage.setWidth(bounds.getWidth());
primaryStage.setHeight(bounds.getHeight());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setTitle("ESM three");
primaryStage.setScene(scene);
primaryStage.show();
System.out.println("This will fail because mainToolBar is null. Why?");
assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";
} catch (Exception ex) {
Logger.getLogger(ESM.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Use initialize() to setup widgets from scenebuilder files, it is
* called by FXMLLoader.
*/
#FXML
public void initialize(){
System.out.println("initialize() But when here all is good and mainToolBar is a ToolBar.");
assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support.
*
* #param args The command line arguments.
*/
public static void main(String[] args) {
launch(args);
}
}
I cant see why it's got a value in the initialise() but in the start it's null. When debuging it's clear that initiialize() is called by FXMLLOader from inside start()
I was going to post the fxml but it does not seem to work as nothig shows in the preview. Any way, it's a real basic file, a BordePane and a ToolBar.
Any clues?
Always create a new class for your FXML Controller, don't try to reuse an Application class as a Controller class.
An Application instance is created by the JavaFX application launcher.
A Controller instance is created by the JavaFX FXML loader.
You don't supply the FXML that you use, but I am going to guess that it has it's Controller class erroneously set to be your application class.
So in your code, what happens is:
An instance of the application is created when you run the program (via the launch method).
In your application start method, you invoke the FXMLLoader, which instantiates a new Controller (in your case a new instance of the application class).
The FXMLLoader injects the #FXML tagged members into the new application object and invokes the initialize on the new object.
But your original application object doesn't know anything about the new application object and hence doesn't have a menu bar set in it.
In summary, to fix this:
Create a new controller class that the FXMLLoader can instantiate.
Change your fxml to reference the new controller class.
If your application really needs to reference the controller, then you can use the getController method on the FXML loader and in your controller class provide public methods to retrieve required elements (like your menu bar). See my answer to Passing Parameters JavaFX FXML for some more examples of this method.
import javafx.scene.control.ToolBar;
import javafx.fxml.FXML;
public class ESMController {
#FXML
private ToolBar mainToolBar;
public ToolBar getMainToolBar() { return mainToolBar; }
#FXML
public void initialize(){
assert mainToolBar != null : "fx:id=\"mainToolBar\" was null check your FXML ";
}
}

Resources