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

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 ...

Related

Javafx MVC how to signal new threaded result from one controller to another

I have a Javafx MVC Structure where Controller 1, 2, 3... are in charge of updating the UI elementes, and Super Controller executes whatever job is passed to it from them, and returns the result.
I have a Button Btn1 in Controller1 which when pressed will be disabled and show a processing symbol while the main job is done in other thread whose function is present in Super Controller. Once that thread completes its job, it'll notify the calling function that job is done, so that Btn1 will be enabled again, and processing symbol removed.
CONTROLLER1
#FXML
Button Btn1;
private ProgressIndicator loading;
private SUPERCONTROLLER con;
#Override
public void initialize(URL url, ResourceBundle rb){
loading=new javafx.scene.control.ProgressIndicator();
loading.setProgress(javafx.scene.control.ProgressIndicator.INDETERMINATE_PROGRESS);
}
#FXML
private void press(MouseEvent evt){
Btn1.setDisable(true);
Btn1.setGraphic(loading);
Task<Integer>t=this.con.Action();
new Thread(t).start();
t.setOnSuceeded(e->{
if(t.getValue()==0){
System.out.println("Success");
}else{
System.out.println("falure");
}
Btn1.setDisable(false);
Btn1.setGraphic(null);
});
}
private void inject(SUPERCONTROLLER c){
this.con=c;
}
SUPERCONTROLLER
#FXML
private VBox sidePane;
#Override
public void initialize(URL url,ResourceBundle rb){
var fxml=new FXMLLoader(getClass().getResource("CONTROLLER1.fxml");
Pane childPanel=fxml.load();
sidePane.getChildren().add(childPanel);
CONTROLLER1 childPanel.getController();
CONTROLLER1.inject(this);
}
protected Task<Integer> Action(){
Task<Integer>task=new Task<>(){
#Override protected Integer call(){
Thread.currentThread.wait(3000); //Imitate long task
return 0;
}
}
return task;
}
However, I want the thread concept to stay in Super Controller itself. i.e., Instead of setting suceeded operation in Controller1, I want to move it to Super Controller and Controller1 should just re-enable the button when Super Controller tells it.

Null exception when I try to access a controller that I passed using JavaFX

I have a root layout with multiples Tabs. From my main App I open the root layout. There I included multiple FXMLs with their own controllers.
I am trying to pass the main controller to one of the Tabes controller.
The issue I am having, everything works as expected, but I get a null exception when I try to click on an action button from the new tab.
RootLayout FXML
<fx:indlue fx:id="myNewTabAnchorPane" source="NewTabFXML.fxml"/>
RootLayout Controller
#FXML NewTabController newTabController;
mainTabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){
#override
public void change(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue){
if(newValue == myTab){
newTabController.setMyRootController(this);
}
NewTabController
public void setMyRootController(RootController rootController){
this.rootController = rootController;
System.out.println(rootController.getID); // this prints fine
}
However, if I trigger this action I get blank from the same controller
#FXML
public void createAction(ActionEvent event) throws IOException{
System.out.println(rootController.getID); // with this I get null value.
}
What am I missing?
Here is the problem:
#FXML NewTabController newTabController;
It should be myNewTabAnchorPaneController which is not a partially lowercased class name, but fx:id + Controller concatenation.

How to close a dialog box programmatically

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).

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.

JavaFX load FXML inside parent controller

I have a borderpane where I'm loading an fxml (alias FirstPanel) with relative controller inside of it and positioned in the center. The fxml contains a TableView and a button which should load another fxml (alias SecondPanel) and relative controller instead the first panel. Basically, the SecondPanel needs to show some details about the data selected in the table.
Is it possible to do it? How can I get the parent of my FirstPanel and use it for the SecondPanel instead of the first?
UPDATE
I've tried many solutions but without reach my goal. The application load the UsersMainPageController which contains only an AnchorPane like parent control, so this is the relative code:
[UsersMainPageController]
public class UsersMainPageController implements Initializable {
private PostOffice application;
#FXML
private AnchorPane ParentControl;
public void setApp(PostOffice application){
this.application = application;
}
public void loadPage(String pageName) {
try {
URL url = getClass().getResource(pageName);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(url);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
AnchorPane page = (AnchorPane) fxmlLoader.load(url.openStream());
ParentControl.getChildren().clear();///name of pane where you want to put the fxml.
ParentControl.getChildren().add(page);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void loadManageUsers () {
loadPage("UsersManage.fxml");
}
public void loadListUsers () {
loadPage("UsersList.fxml");
}
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
loadListUsers();
}
}
loadListUsers calls UsersList.fxml with the relative controller UsersListController that contains a TableView with some records and some buttons. When I click a specific button, it should call loadManageUsers with relative controller UsersManageController which contains some fields for editing data and inserting new users. When users are edited or inserted, it should be able to return to the previous page with the TableView and clear the current page (in this case UsersManageController).
[UsersListController]
public class UsersListController implements Initializable {
private UsersMainPageController mainController;
#FXML
private void handleButtonEditAction(ActionEvent event) throws IOException {
mainController.loadManageUsers();
}
}
[UsersManageController]
public class UsersManageController implements Initializable {
private UsersMainPageController mainController;
#FXML
private void handleButtonBackAction(ActionEvent event) throws IOException {
mainController.loadListUsers();
}
}
When I click from the UsersListController the ButtonEdit to load the UsersManageController, I get this error:
Caused by: java.lang.NullPointerException
at postoffice.multiuser.UsersListController.handleButtonAggiornaAction(UsersListController.java:210)
... 50 more
you can add your child fxml into parent controller..
1.first just take a anchor pane and set its bounds where you want to put your FXML code.
now try this...
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
openNewWindow("Example.fxml");
}
});
you can pass fxml name into function...
public void openNewWindow(String FXMLFile)
{
//ChildNode child;
try {
URL url = getClass().getResource(FXMLFile);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(url);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
AnchorPane page = (AnchorPane) fxmlLoader.load(url.openStream());
anchor.getChildren().clear();///name of pane where you want to put the fxml.
anchor.getChildren().add(page);
}
catch (IOException e) {
e.printStackTrace();
}
}

Resources