Accessing node generated by FXML - java

I've created a simple JavaFX program, using CSS and FXML for style and layout, respectively. How can I, from the main Java application, edit the nodes declared in the FXML? Specifically, how could I change the text from the Text object shown below:
CSS
.stage {
-fx-background-color: lightskyblue ;
-fx-effect: innershadow(three-pass-box , rgba(0,0,0,0.6), 25, 0.0, 0, 1 );
}
.time {
-fx-fill: white;
-fx-font-size: 95;
-fx-font-family: 'sans-serif';
-fx-effect: dropshadow(three-pass-box , rgba(0,0,0,0.6), 2, 0.0, 0, 1 );
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<BorderPane fx:id="mainStage" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" styleClass="stage" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<center>
<Text fx:id="time" styleClass="time" text="Text" />
</center>
<stylesheets>
<URL value="#application.css" />
</stylesheets>
</BorderPane>
Java Program
public class Main extends Application {
#Override
public void start(Stage stage) {
Parent root;
try {
root = FXMLLoader.load(getClass().getResource("layout.fxml"));
Scene scene = new Scene(root, 300, 275);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}

Add a controller class for the FXML, with the proper annotations:
public class MyCtrl {
#FXML private Text time; // name must be the same as fx:id
}
Declare the controller in the FXML (there are other ways too, this is probably the simplest):
<BorderPane fx:id="mainStage" ... fx:controller="mypackage.MyCtrl">
And then you can access it from within the controller, e.g. from the initialize() method:
public void initialize() {
text.setText("xyz");
}
(You probably want to setup a timer in MyCtrl.initialize() to call setText() with the current time periodically.)

Related

How to fix Object cannot be converted to javafx.scene.Node

I'm trying to load my fxml file, which is fine and loaded (I have tried it with my main class). But, when I tried to set the content in the Controller, an error occurred saying:
incompatible types: java.lang.Object cannot be converted to javafx.scene.Node
at addNewCategorie.getDialogPane().setContent(fxmlLoader.load());
My Controller Class:
#FXML
private BorderPane mainBorder;
#FXML
public void handle_the_addition_of_newCategorie(){
Dialog<ButtonType> addNewCategorie = new Dialog<>();
addNewCategorie.setTitle("Add Categorie");
addNewCategorie.initOwner(mainBorder.getScene().getWindow());
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("/AddNewCategorie.fxml"));
try{
addNewCategorie.getDialogPane().setContent(fxmlLoader.load());
}catch (IOException E){
System.out.println("IOEXception : "+E.getMessage());
}
addNewCategorie.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
addNewCategorie.show();
}
My fxml file:
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<BorderPane fx:id="mainBorder" fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" style="-fx-background-color:#485460">
<center>
<HBox spacing="20" alignment="CENTER">
<Button text="Add new Categorie" style="-fx-background-color:#2ecc71; -fx-text-fill:white" onMouseClicked="#handle_the_addition_of_newCategorie"/>
</HBox>
</center>
</BorderPane>
had to change this:
addNewCategorie.getDialogPane().setContent(fxmlLoader.load());
to:
addNewCategorie.getDialogPane().setContent((Node)fxmlLoader.load());
and:
fxmlLoader.setLocation(getClass().getResource("/AddNewCategorie.fxml"));
To:
fxmlLoader.setLocation(getClass().getClassLoader().getResource("/AddNewCategorie.fxml"));

How to make AnchorPane rounded inside another AnchorPane

As the title says I have created a root AnchorPane in which two AnchorPanes are placed the upper AnchorPane somehow gets rounded but in case of lower one, the upper side is rounded whereas the lower side remains edged.
Java Code:
package application;
import javafx.application.*;
import javafx.event.*;
import javafx.fxml.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.layout.*;
public class Main extends Application {
private double xOffset = 0;
private double yOffset = 0;
public void start(Stage primaryStage)
{
try
{
primaryStage.initStyle(StageStyle.TRANSPARENT);
AnchorPane root = FXMLLoader.load(getClass().getResource("load.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
scene.setFill(javafx.scene.paint.Color.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.show();
root.setOnMousePressed(new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{
xOffset = e.getSceneX();
yOffset = e.getSceneY();
}
});
root.setOnMouseDragged(new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{
primaryStage.setX(e.getScreenX() - xOffset);
primaryStage.setY(e.getScreenY() - yOffset);
}
});
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Most of the Designing part is done using Scene Builder in fxml file
FXML Code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="root" prefHeight="452.0" prefWidth="362.0" style="-fx-background-color: transparent; -fx-background-radius: 30; -fx-border-radius: 30;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<AnchorPane prefHeight="70.0" prefWidth="362.0" style="-fx-background-color: #3D4956; -fx-background-radius: 30; -fx-border-radius: 30;" />
<AnchorPane fx:id="pg1" layoutY="80.0" prefHeight="373.0" prefWidth="362.0" style="-fx-background-color: #3D4956; -fx-background-radius: 30;" />
</children>
</AnchorPane>
Works fine for me (until I resize the window to make the scene smaller than the preferred size of the root). Note that you haven't produced a responsive layout there.
If you want to wrap everything in an AnchorPane, replace layoutY="80.0" with AnchorPane.topAnchor="80" AnchorPane.bottomAnchor="0" and the bottom AnchorPane will shrink/grow when resizing the window vertically.
Note though that there is a simpler way to produce this kind of layout (the responsive version) that using AnchorPane: Just use a VBox:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="root" spacing="10" prefHeight="452.0" prefWidth="362.0" style="-fx-background-color: transparent; -fx-background-radius: 30; -fx-border-radius: 30;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<AnchorPane prefHeight="70.0" style="-fx-background-color: #3D4956; -fx-background-radius: 30; -fx-border-radius: 30;" />
<AnchorPane fx:id="pg1" VBox.vgrow="ALWAYS" style="-fx-background-color: #3D4956; -fx-background-radius: 30;" />
</children>
</VBox>
VBox.vgrow="ALWAYS" results in the second AnchorPane being grown to the space remaining in the VBox.

field that is supposed to be assigned by fxml is throwing NullPointerException when accesed from inner class - javaFX

I have a controller for an fxml file. The controller has a field public BorderPane mainBorderPane; which is supposed to be filled with the Border pane of the same fx:id found in the fxml file. When I try to access it from an inner class it gives a NullPointerExcetion
The clearBorderPaneCenter(); and the clearBorderPaneRight work just fine but when I run the cashSceneController.show() it crashes on the line mainBorderPane.setRight(rightLayout);
fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="mainBorderPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Program.gui.MainSceneController">
<top>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</top>
<left>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</left>
<center>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
<right>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</right>
<bottom>
<Pane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</bottom>
</BorderPane>
Simplified version of controller:
public class MainSceneController {
MainSceneController.CashSceneController cashSceneController = new MainSceneController.CashSceneController();
public BorderPane mainBorderPane;
public void switchLayout(byte ID){
//todo Make this work switchScene()
clearBorderPaneCenter();
clearBorderPaneRight();
cashSceneController.show();
}
public void clearBorderPaneRight(){
try {
mainBorderPane.setRight(null);
OutputHelper.log("cleared right of mainBorderPane");
} catch (Exception e){
OutputHelper.log("clearing right of mainBorderPane not required - already cleared");
}
}
public void clearBorderPaneCenter(){
try {
mainBorderPane.setCenter(null);
OutputHelper.log("cleared centre of mainBorderPane");
} catch (Exception e){
OutputHelper.log("clearing centre of mainBorderPane not required - already cleared");
}
}
public class CashSceneController{
VBox rightLayout;
public void show() {
setVBox();
mainBorderPane.setRight(rightLayout);
}
public void setVBox(){
rightLayout = new VBox();
//......
}
}
}
This is how the fxml file is loaded
SceneController = new MainSceneController(new Scene(FXMLLoader.load(getClass().getResource("gui/MainScreen.fxml"))));
I hope that I explained my problem well enough. I'm new to stack overflow and have no idea of what is a good question
Edit: it appears that the problem is caused by the mainBorderPane not being assigned at all. The clearBorderPaneCenter and clearBorderPaneRight seem to not crash cause they are caught by the try catch. Any ideas why the mainBorderPane might not be getting assigned correctly?
You are missing the fxml annotation. It is required for the FXMLLoader to inject the BorderPane into the code
#FXML
public BorderPane mainBorderPane;

Null pointer exception in #FXML Injection

I'm trying to work with JavaFX and FXML files, but something goes wrong when I inject the MenuBar in the controller, compiler gives me a NullPointerException. I tried with buttons and textfields and it works.
This is mycode:
FXML file:`
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox fx:controller="it.fedgiac.projectmanager.controller.ControllerMain" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<MenuBar fx:id="menubar_mainmenu" />
</children>
</VBox>`
And this is my Controller
public class ControllerMain {
#FXML
public MenuBar menubar_mainmenu;
public void generateView(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("main_layout.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Projects Manager");
menubar_mainmenu.getMenus().add(new Menu("File"));
stage.setScene(scene);
stage.show();
}
}
After debugging I saw that the variable menubar_mainmenu is null
This is the error:
Thank you in advance for your help.
Make your FXML Controller implement Initializable. You will then be prompted to implement the method initialize(URL url, ResourceBundle resourceBundle). In this method, you can be sure that the menubar_mainmenuis initialized. You can move your existing code into that method.
public void initialize(URL url, ResourceBundle resourceBundle){
menubar_mainmenu.getMenus().add(new Menu("File"));
}

SubScene in JavaFX does not show elements loaded from an FXML file

I have a program created with an FXML file (made in SceneBuilder) that has four SubScenes in it:
#FXML
public SubScene p1sub;
#FXML
public SubScene p2sub;
#FXML
public SubScene p3sub;
#FXML
public SubScene p4sub;
Each of these subscenes is nearly identical to the rest.
I can get the root node (which contains these) to show up just fine, but when I try to add the SubScenes, they don't show up.
//This is the code I use to initialize one of the four.
Parent root2a = null;
try {
FXMLLoader loader2 = new FXMLLoader(getClass().getResource(
"PlayerConfigurationSubScreen.fxml"));
root2a = (Parent) loader2.load();
} catch (Exception e) {
/*code*/
}
/*code*/
if (root2a != null) {
System.out.println("root2 isn't null");
p1sub = new SubScene(root2a, 149, 260);
}
/*code*/
stage.show();
Any idea how to make them show up? I'm new at JavaFX.
Set the subscene dimensions in fxml and instead of "new" just add the parent to the subscene.
....
p1sub.setRoot(root2a);
....
I think you are approaching the problem the wrong way. From what I understand from your code, you want to load a subscene and then assign it to one of your predefined "slots".
This however will not work, as the pre-defined slots has nothing to do with what is actually rendered. Everything that is drawn in a window has to be assigned as child of a container of some kind.
I've made an example here that reproduces the problem you are facing:
public class ReplaceTest extends Application {
#FXML Button button;
#FXML Label oldLabel;
#Override
public void start(Stage primaryStage) throws IOException{
Parent root = FXMLLoader.load( getClass().getResource("ReplaceTest.fxml") );
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private static int i = 0;
#FXML protected void simpleClick(ActionEvent e){
Label newLabel = new Label("Hello! " + i++);
oldLabel = newLabel;
System.out.println("Nothing happens...");
}
}
And the FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="200.0" spacing="10.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="replaceTest.ReplaceTest">
<children>
<Label fx:id="oldLabel" text="TEXT TO BE REPLACED" />
<Button fx:id="button" onAction="#simpleClick" text="Replace label" />
</children>
<padding>
<Insets top="10.0" />
</padding>
</VBox>
If you try this example, you will see that overwriting oldLabel does not affect the rendering window. Instead, you can try to create areas to which you add your new subscenes as children. This will update the rendering window and will (hopefully) produce the behavior you desire. Again, I've made an example you can consult:
public class ReplaceTest extends Application {
#FXML Button button;
#FXML VBox wrappingBox;
#Override
public void start(Stage primaryStage) throws IOException{
Parent root = FXMLLoader.load( getClass().getResource("ReplaceTest.fxml") );
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private static int i = 0;
#FXML protected void simpleClick(ActionEvent e){
Label newLabel = new Label("Hello! " + i++);
wrappingBox.getChildren().clear();
wrappingBox.getChildren().add(newLabel);
System.out.println("Someting happens!");
}
}
And the FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="100.0" prefWidth="200.0" spacing="10.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="replaceTest.ReplaceTest">
<children>
<VBox fx:id="wrappingBox" alignment="TOP_CENTER">
<children>
<Label text="TEXT TO BE REPLACED" />
</children>
</VBox>
<Button fx:id="button" onAction="#simpleClick" text="Replace label" />
</children>
<padding>
<Insets top="10.0" />
</padding>
</VBox>

Categories

Resources