Getting size of FXML generated nodes - javafx

I want to get the size of a node, after it has been sized properly, which I understand is done after the stage is shown. however, i cannot do it in start() method, because the node is not initialized yet, because its loaded it from an FXML file.
If I implement Initializable Interface and try to get the size in initialize() method, it returns 0.0
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<GridPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="musicPlayer.Test">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<TableView fx:id="testNode">
<columns>
<TableColumn prefWidth="75.0" text="C1" />
<TableColumn prefWidth="75.0" text="C2" />
</columns>
</TableView>
</children>
</GridPane>
just an arbitrary node in a grid pane generated with scene builder
public class Test extends Application implements Initializable {
#FXML
private TableView testNode;
public void initialize(URL location, ResourceBundle resources) {
//System.out.println(testNode.getWidth()); is always 0.0
}
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
//System.out.println(testNode.getWidth()); throws Nullpointer Exception
}
public static void main(String[] args) {
launch(args);
}
}
I've also tried adding a listener to the stage, but i still get a nullpointer exception.
Is there a way of getting the size, without using a sleeping thread?

Related

Passing a Button in FXML using JavaFX

Hello I Have this portion of my code, I actually need disable the button when the user is logging, I am trying to pass the button to the FXML, but nothing happens: this is the code in the Main Controller, when the user is logged and data match with the password and username the button with the variable btn1 must disabled, I post my entire code for any help.
public Button getBtn1() {
return btn1;
}
public void conexion () {
String usus="";
String Passu ="";
String Bd="jdbc:sqlserver: // THUMANO2:1433;databaseName=QUORA";
String Usuario="sa";
String Pass="milkas87";
String SqlQuery= "select NOMBREUSUARIO, CONVERT (VARCHAR(50), (DecryptByPassPhrase('*xc/6789oÑ---+y',PASS))) as PASS from usuarios where CONVERT (VARCHAR(50), (DecryptByPassPhrase('*xc/6789oÑ---+y',PASS)))='"+fcontrasena.getText().toString().trim()+"'";
Connection Conexion = null;
try {
Conexion=DriverManager.getConnection(Bd, Usuario, Pass);
PreparedStatement ps =Conexion.prepareStatement(SqlQuery);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
usus = rs.getString("NOMBREUSUARIO");
Passu = rs.getString("PASS");
}
if(fcontrasena.getText().toString().trim().equals(Passu) && fusuario.getText().toString().equals(usus)) {
Stage administrador=new Stage();
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Admin.fxml"));
Stage login=(Stage)fusuario.getScene().getWindow();
Parent root = loader.load();
AdminScreenController controlador = loader.<AdminScreenController>getController();
controlador.setBtn1(btn1);
Scene scene=new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
administrador.setScene(scene);
administrador.setTitle("AdminScreen");
login.hide();
administrador.show();
} catch(Exception e) {}
}
} catch(SQLException e) {
JOptionPane.showMessageDialog(null,"error","ERROR",0);
}
}
this is the code for AdminScreenController:
public void setBtn1(Button btn1) {
btn1.setDisable(true);
}
this is the FXML Document:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="576.0" prefWidth="791.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.AdminScreenController">
<children>
<BorderPane fx:id="bpane" prefHeight="621.0" prefWidth="791.0">
<left>
<VBox fx:id="vboxr" prefHeight="576.0" prefWidth="205.0" BorderPane.alignment="CENTER">
<children>
<BorderPane prefHeight="106.0" prefWidth="205.0">
<center>
<Button fx:id="btn1" mnemonicParsing="false" prefHeight="51.0" prefWidth="127.0" text="Planilla Sistemas" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
<BorderPane prefHeight="106.0" prefWidth="205.0">
<center>
<Button fx:id="btn2" mnemonicParsing="false" prefHeight="51.0" prefWidth="127.0" text="AMP" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
<BorderPane prefHeight="116.0" prefWidth="205.0">
<center>
<Button fx:id="btn3" mnemonicParsing="false" prefHeight="51.0" prefWidth="127.0" text="Tareas Funcionarios" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
<BorderPane prefHeight="106.0" prefWidth="205.0">
<center>
<Button fx:id="btn4" mnemonicParsing="false" prefHeight="51.0" prefWidth="127.0" text="Indicadores" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
<BorderPane prefHeight="106.0" prefWidth="205.0" />
</children>
</VBox>
</left>
<top>
<BorderPane prefHeight="145.0" prefWidth="791.0" BorderPane.alignment="CENTER">
<left>
<Pane fx:id="imgview" prefHeight="145.0" prefWidth="205.0" BorderPane.alignment="CENTER" />
</left>
</BorderPane>
</top>
</BorderPane>
</children>
</StackPane>
its something wrong? i need some orientation here. thanks.
Here is an example that shows the MVC relationship in JavaFX. The button is defined in FXML and injected into the controller where it can be accessed.
TestAppView.fxml
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox alignment="CENTER" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.app.TestAppController">
<Button fx:id="myButton" text="Hello World" />
</VBox>
TestAppController.java
public class TestAppController implements Initializable {
#FXML
private Button myButton;
#Override
public void initialize(URL url, ResourceBundle resources) {
// Prints Hello World & disables the button when clicked
myButton.setOnAction((e) -> {
System.out.println("Hello World");
myButton.setDisable(true);
});
}
}
TestAppMain.java
public class TestAppMain extends Application {
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(TestAppController.class.getResource("TestAppView.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root, 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX blur underneath area from pane

Is there any way to add a blur effect only to a part of an image defined by the area of a Pane? If you blur the pane over the image only the pane get blurred, but is there a way to blur the picture part underneath?
Here's an example of what I mean: It's simply just an image overlayed with a pane which has backgrouud and opacity set. Now I want to blur the part the pane lays on.
Main.java:
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
GridPane root = (GridPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
Scene scene = new Scene(root,500,500);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ImageView fitHeight="495.0" fitWidth="535.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER">
<image>
<Image url="#../../../../Downloads/ZGEX2eX.jpg" />
</image>
</ImageView>
<Pane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #012E56; -fx-opacity: 0.666;" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" />
</children>
</GridPane>
You can use the Clip of an ImageView to apply an effect only to a specific area of your image:
public class BlurredImageTest extends Application {
private DoubleProperty effectHeight = new SimpleDoubleProperty(80);
#Override
public void start(Stage primaryStage) {
Image image = new Image("yourImage.jpg");
ImageView img = new ImageView(image);
Rectangle clip = new Rectangle();
clip.widthProperty().bind(image.widthProperty());
clip.heightProperty().bind(image.heightProperty().subtract(effectHeight));
img.setClip(clip);
ImageView imgEffect = new ImageView(image);
Rectangle clipEffect = new Rectangle();
clipEffect.widthProperty().bind(image.widthProperty());
clipEffect.heightProperty().bind(effectHeight);
clipEffect.translateYProperty().bind(image.heightProperty().subtract(effectHeight));
imgEffect.setClip(clipEffect);
imgEffect.setEffect(new GaussianBlur());
StackPane root = new StackPane(img, imgEffect);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public final void setEffectHeight(double value) {
effectHeight.set(value);
}
public static void main(String[] args) {
launch(args);
}
}

Binding listener isn't working properly in JavaFX 8

Currently I am learning how to use Bindings and Binding-Events properly. I already read a chapter of a book about it and in general I have no problem in using Bindings.
For testing my knowledge, I wrote a little JavaFX8 Application. I got 2 TextFields, but at the moment I am focusing on one TextField, called "firstName". I am using a BooleanBinding. Whenever the TextField is getting filled, the BooleanBinding is set to "true". If there's no Input in the Field, the BooleanBinding is set to "false". My goal is to update Label called "statusLabel", whenever the BooleanBinding got changed.
This is how the binding looks:
BooleanBinding nameEntered = firstName.textProperty().isNotEmpty();
This is my ChangeListener:
nameEntered.addListener((o, oldValue, newValue) -> {
statusLabel.setText(newValue.toString());
});
For a short amount of time, the Listener is working properly. When the BooleanBinding got changed, the Label is getting updated. But after some input changes (deleting the input, filling again etc...) the Label isn't getting updated anymore. Any ideas how to fix this?
Here is the full code:
FXMLController:
package gui;
/*
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.binding.When;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
*/
public class LayoutController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
private TextField firstName;
#FXML
private TextField secondName;
#FXML
private CheckBox checkBox1;
#FXML
private CheckBox checkBox2;
#FXML
private CheckBox checkBox3;
#FXML
private Label statusLabel;
#Override
public void initialize(URL url, ResourceBundle rb) {
BooleanBinding nameEntered = firstName.textProperty().isNotEmpty();
nameEntered.addListener((o, oldValue, newValue) -> {
statusLabel.setText(newValue.toString());
});
}
}
MainView.java:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author xyz
*/
public class MainView extends Application{
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Layout.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Benutzerauswahl");
primaryStage.show();
}
public static void main(String args[]){
launch(args);
}
}
FXMLLayout:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="310.0" prefWidth="343.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.LayoutController">
<center>
<AnchorPane prefHeight="371.0" prefWidth="380.0" BorderPane.alignment="CENTER">
<children>
<GridPane layoutX="50.0" layoutY="103.0" prefHeight="234.0" prefWidth="281.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="49.0" AnchorPane.topAnchor="50.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="155.0" minWidth="10.0" prefWidth="110.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="197.0" minWidth="10.0" prefWidth="171.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="40.0" minHeight="10.0" prefHeight="40.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="40.0" minHeight="10.0" prefHeight="40.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="400.0" minHeight="10.0" prefHeight="88.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label prefHeight="17.0" prefWidth="56.0" text="Vorname:" GridPane.halignment="CENTER" />
<Label prefHeight="17.0" prefWidth="69.0" text="Nachname:" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
<TextField fx:id="firstName" prefHeight="25.0" prefWidth="144.0" GridPane.columnIndex="1" />
<TextField fx:id="secondName" prefHeight="25.0" prefWidth="144.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<AnchorPane prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2">
<children>
<CheckBox fx:id="checkBox1" layoutX="14.0" layoutY="42.0" mnemonicParsing="false" text="Kurs 1" />
<CheckBox fx:id="checkBox2" layoutX="14.0" layoutY="69.0" mnemonicParsing="false" text="Kurs 2" />
<CheckBox fx:id="checkBox3" layoutX="14.0" layoutY="96.0" mnemonicParsing="false" text="Kurs 3" />
<Label fx:id="statusLabel" layoutX="43.0" layoutY="132.0" prefHeight="17.0" prefWidth="84.0" text="Status" />
</children>
</AnchorPane>
</children>
</GridPane>
</children>
</AnchorPane>
</center>
</BorderPane>
This is really a duplicate of JavaFX Beans Binding suddenly stops working: the problem is that the binding is getting "prematurely garbage collected" because there are no live references to it that are retained. Forcing the reference to be retained in a controller seems to be a little tricky.
First note that if you actually bind a property of a UI element (which is necessarily in scope as long as it is displayed), then the UI element indirectly keeps a reference to the binding. Consequently in your code this will fix the problem:
statusLabel.textProperty().bind(nameEntered.asString());
(instead of the listener you currently have). If you can't actually use a binding, then it seems that first you need to get the controller to retain a reference to the binding:
public class LayoutController implements Initializable {
// existing code...
private BooleanBinding nameEntered ;
public void initialize(URL url, ResourceBundle rb) {
nameEntered = firstName.textProperty().isNotEmpty();
nameEntered.addListener((o, oldValue, newValue) -> {
statusLabel.setText(newValue.toString());
});
}
}
and then additionally you need to force an reference to the controller itself to stay in scope:
public class MainView extends Application{
private LayoutController controller ;
#Override
public void start(Stage primaryStage) throws Exception {
FMXLLoader loader = new FXMLLoader(getClass().getResource("Layout.fxml"));
Parent root = loader.load();
controller = loader.getController();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Benutzerauswahl");
primaryStage.show();
}
public static void main(String args[]){
launch(args);
}
}
There may be a more obvious way to do this, but I can't find one that works.

FXML Set ButtonType onAction

I'm building a DialogPane in FXML and I'm trying to figure out how to respond to button presses on the dialog since onAction is not a valid parameter for ButtonType. I've attached my FXML and Controller Class. There is very little documentation about DialogPane and even less about doing it in FXML so I'm not sure how to proceed.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ButtonType?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<DialogPane fx:id="loginPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="LoginController">
<content>
<GridPane hgap="5.0" vgap="5.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="300.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Driver Name" />
<TextField fx:id="driverTxt" GridPane.columnIndex="1" />
<Label text="URL" GridPane.rowIndex="1" />
<TextField fx:id="urlTxt" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Username" GridPane.rowIndex="2" />
<TextField fx:id="userTxt" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="Password" GridPane.rowIndex="3" />
<TextField fx:id="passTxt" GridPane.columnIndex="1" GridPane.rowIndex="3" />
</children>
</GridPane>
</content>
<buttonTypes>
<ButtonType fx:id="loginButton" text="Login" />
<ButtonType fx:id="cancelBtn" text="Cancel" />
</buttonTypes>
</DialogPane>
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.ButtonType;
import javafx.scene.control.DialogPane;
import javafx.scene.control.TextField;
public class LoginController {
#FXML
DialogPane loginPane;
#FXML
TextField driverTxt;
#FXML
TextField urlTxt;
#FXML
TextField userTxt;
#FXML
TextField passTxt;
#FXML
ButtonType loginButton;
#FXML
private void loginButtonAction(){
// How do I do something here
}
public void initialize() {
driverTxt.setText("org.postgresql.Driver");
urlTxt.setText("jdbc:postgresql://localhost/postgres");
userTxt.setText("postgres");
passTxt.setText("postgres");
}
}
Typically you wouldn't need to do this. You would usually show a DialogPane in a Dialog<ButtonType> calling its showAndWait() method, which returns an Optional<ButtonType> representing the button pressed (if any). So normal usage would be something like
public class LoginController {
public static final ButtonType LOGIN = new ButtonType("Login");
#FXML
DialogPane loginPane;
#FXML
TextField driverTxt;
#FXML
TextField urlTxt;
#FXML
TextField userTxt;
#FXML
TextField passTxt;
public void initialize() {
driverTxt.setText("org.postgresql.Driver");
urlTxt.setText("jdbc:postgresql://localhost/postgres");
userTxt.setText("postgres");
passTxt.setText("postgres");
}
public String getDriver() {
return driverTxt.getText();
}
public String getUrl() {
return urlTxt.getText();
}
public String getUser() {
return userTxt.getText();
}
public String getPass() {
return pass.getText();
}
}
and make the following changes to your FXML file:
<buttonTypes>
<LoginController fx:constant="LOGIN" />
<ButtonType fx:constant="CANCEL" />
</buttonTypes>
Then you would use this with:
Dialog<ButtonType> dialog = new Dialog<>();
FXMLLoader dialogLoader = new FXMLLoader(getClass().getResource("Login.fxml"));
dialog.setDialogPane(dialogLoader.load());
LoginController controller = dialogLoader.getController();
dialog.showAndWait().filter(LoginController.LOGIN::equals)
.ifPresent(button -> {
String driver = controller.getDriver();
// etc etc
// process login...
});
As an alternative to exposing the text from the text fields, you could define a processLogin() method in the controller itself that read the text fields and did whatever you need to do:
public class LoginController {
public static final ButtonType LOGIN = new ButtonType("Login");
#FXML
DialogPane loginPane;
#FXML
TextField driverTxt;
#FXML
TextField urlTxt;
#FXML
TextField userTxt;
#FXML
TextField passTxt;
public void initialize() {
driverTxt.setText("org.postgresql.Driver");
urlTxt.setText("jdbc:postgresql://localhost/postgres");
userTxt.setText("postgres");
passTxt.setText("postgres");
}
public void processLogin() {
String driver = driverTxt.getText();
// etc...
// process login...
}
}
then just do
// ...
dialog.showAndWait().filter(LoginController.LOGIN::equals)
.ifPresent(button -> controller.processLogin());
If you really need to register an onAction handler with the login button, do it in the initialize() method in the controller:
public void initialize() {
driverTxt.setText("org.postgresql.Driver");
urlTxt.setText("jdbc:postgresql://localhost/postgres");
userTxt.setText("postgres");
passTxt.setText("postgres");
Button login = (Button) loginPane.lookupButton(loginButton);
login.setOnAction(e -> { /* ... */ });
}
but this is really against the intended use of the dialog pane API.
One final alternative would be to override the createButton method in DialogPane. To do this, you'd need a subclass of DialogPane, which would mean using the FXML custom component pattern.
So this would look something like:
public class LoginPane extends DialogPane {
public static final ButtonType LOGIN = new ButtonType("Login");
#FXML
TextField driverTxt;
#FXML
TextField urlTxt;
#FXML
TextField userTxt;
#FXML
TextField passTxt;
public LoginPane() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginPane.fxml"));
loader.setRoot(this);
loader.setController(this);
loader.load();
} catch (IOException exc) {
// bad if you get here...
throw new UncheckedIOException(exc);
}
}
#Override
public Node createButton(ButtonType buttonType) {
Node button = super.createButton(buttonType);
if (buttonType == LOGIN) {
((Button) button).setOnAction(e -> processLogin());
}
return button ;
}
public void initialize() {
driverTxt.setText("org.postgresql.Driver");
urlTxt.setText("jdbc:postgresql://localhost/postgres");
userTxt.setText("postgres");
passTxt.setText("postgres");
}
public void processLogin() {
String driver = driverTxt.getText();
// etc...
// process login...
}
}
and the FXML would then look like
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ButtonType?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<fx:root type="DialogPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
<content>
<GridPane hgap="5.0" vgap="5.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="300.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Driver Name" />
<TextField fx:id="driverTxt" GridPane.columnIndex="1" />
<Label text="URL" GridPane.rowIndex="1" />
<TextField fx:id="urlTxt" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Username" GridPane.rowIndex="2" />
<TextField fx:id="userTxt" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="Password" GridPane.rowIndex="3" />
<TextField fx:id="passTxt" GridPane.columnIndex="1" GridPane.rowIndex="3" />
</children>
</GridPane>
</content>
<buttonTypes>
<LoginPane fx:constant="LOGIN" />
<ButtonType fx:constant="CANCEL" />
</buttonTypes>
</fx:root>
You would use this version with
Dialog dialog = new Dialog();
dialog.setDialogPane(new LoginPane());
dialog.showAndWait();
so if you are looking to encapsulate as much as possible into the login pane and fxml, this is probably the cleanest option.
Note that the usage of DialogPane is fairly completely documented in the API docs for Dialog and DialogPane.

Add node or a scene created with Javafx to fxml

I try to add a TreeTableView which i have created by coding to right side of my splitpane. The SplitPane has fix Id: splitId and right side of it has the Id splitidRight. I have created splitpane and added it to anchorepane by scenebuiler. Then I have crated BorderPane with menubar. Then i add splitpane to the center of BorderPane. Now I want to add the treetable to the rightside of splitpane. The Error is javafx.scene.layout.AnchorPane cannot be cast to javafx.scene.control.SplitPane but beside this error i am not sure if i am doing the insertion at the right place.
public class Main extends Application {
private DataConstructor dc = new DataConstructor();
private BorderPane rootLayout;
private Stage primaryStage;
TreeItem<String> root = new TreeItem<>("Functions");
public static void main(String[] args) {
Application.launch(Main.class, args);
}
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
primaryStage.setTitle("IT-Saturation");
initRootLayout();
showOverViw();
makeTreeTable();
}
private void makeTreeTable() {
Scene scene = new Scene(new Pane(), 1200, 1800);
Pane sceneRoot = (Pane) scene.getRoot();
root.setExpanded(true);
//........make treetable.....//
treeTableView.setPrefWidth(1200);
treeTableView.setShowRoot(false);
treeTableView.setTableMenuButtonVisible(true);
sceneRoot.getChildren().add(treeTableView);
SplitPane sp = null;
try {
sp = FXMLLoader.load(getClass().getResource("/view/OverView.fxml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
StackPane container = new StackPane();
container.getChildren().add(treeTableView);
sp.getItems().add(container);
sp.setDividerPositions(0.3f, 0.6f, 0.9f); // you can tweak it any how
// primaryStage.setScene(scene);
// primaryStage.show();
}
/**
* Initializes the root layout.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Shows the overview inside the root layout.
*/
public void showOverViw() {
try {
// Load overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/view/OverView.fxml"));
AnchorPane overView = (AnchorPane) loader.load();
// Set overview into the center of root layout.
rootLayout.setCenter(overView);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
*
* #return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
This is the rootLayout.fxml (BorderPane)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
and this is OverView.fxml with splitpane in it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="700.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<SplitPane fx:id="splitId" dividerPositions="0.14691151919866444" layoutX="58.0" layoutY="42.0" prefHeight="700.0" prefWidth="1200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" SplitPane.resizableWithParent="false">
<children>
<Label layoutX="23.0" layoutY="173.0" text="Function count" />
<TextField editable="false" layoutX="1.0" layoutY="225.0" promptText="FuncCount" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" />
<Label layoutX="20.0" layoutY="315.0" text="Organization count" />
<TextField editable="false" layoutX="1.0" layoutY="366.0" promptText="OrgCount" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" />
<ToggleButton layoutX="30.0" layoutY="487.0" mnemonicParsing="false" text="Draw/Reset" />
</children>
</AnchorPane>
<AnchorPane fx:id="splitIdRight" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
As the error says you're trying to cast the AnchorPane which is the top root node of your OverView.fxml to SplitPane.
Change your line
SplitPane = null;
to
AnchorPane =null;
that should solve your error.

Resources