Given I have an FXML which represents a form to create a data record. If I use this FXML only for a CreateRecordController I could bind the controller directly in the FXML and use the fx:ids to bind the controls to this controller.
But what would I do if I want to reuse this FXML for an EditRecordController as well? I cannot bind two controllers in the FXML. Is there a way to do this binding in the FXML loader??
You can pass the controller instance to FXMLLoader before loading the fxml. This requires the fx:controller attribute to be absent from the fxml file:
Object controller = ... // create an instance of the desired controller class here
FXMLLoader loader = new FXMLLoader(getClass().getResource("/some/path/myfxml.fxml"));
loader.setController(controller);
Node root = loader.load();
Note: Binding is the wrong term here, since you do not assign the controller to any javafx property.
Related
I have a problem in JavaFX with FXML , i created an ImageView in FXML and gave it an id . how can i simply use the ImageView that i have created in FXML in the java class code ?
When defining the ImageView in your controller, you need to add the #FXML annotation before it.
An example in Java would be like so:
#FXML
private Canvas canvas;
And in the FXML file:
<center>
<Canvas fx:id="canvas" height="600" width="600" />
</center>
Just keep in mind that the name in Java must be the same as the id in the FXML file
There is an possibility to get Controller instance from Node ?? for example AnchorPane on Tab ?
I have some AnchorPanes where I load different Controllers and I would like to verify which controller is already loaded
Nodes do not contain any information about a controller used with the fxml file used to create it by default, since fxml is just one way of creating a scene. However you could attach information like this to the userData/properties in the fxml:
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="AnchorPane" prefHeight="400.0" prefWidth="600.0" onMouseClicked="#click" fx:controller="fxml.FXMLController">
<!-- store controller as userData property -->
<userData>
<fx:reference source="controller" />
</userData>
<properties>
<!-- store controller at key "foo" in properties map -->
<foo><fx:reference source="controller" /></foo>
</properties>
</AnchorPane>
If you do this, you can lookup the controller at closest ancestor of a node where you added this kind of information using
public static Object getController(Node node) {
Object controller = null;
do {
controller = node.getProperties().get("foo");
node = node.getParent();
} while (controller == null && node != null);
return controller;
}
to retrieve the info from the properties map or using
public static Object getController(Node node) {
Object controller = null;
do {
controller = node.getUserData();
node = node.getParent();
} while (controller == null && node != null);
return controller;
}
to retrieve the info from the userData property.
You should probably use just one way of adding the info though, not both. Also it would be better to replace foo as key...
It's an old question, but if you have a main window, where you include other fxml files like this:
<AnchorPane prefHeight="900.0" prefWidth="1600.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="MainController">
<!-- <HBox></HBox>, some elements here, your normal usual FXML-->
<fx:include fx:id="someAnchorPane" source="SomeAnchorPane.fxml"/>
</AnchorPane>
and your SomeAnchorPane.fxml has fx:controller property set to SomeOtherController, then you can add a controller field in your MainController like this:
#FXML private SomeOtherController someAnchorPaneController;
And it will inject appropriate controller in this field automatically.
The key thing here is that your field has to be named "fx:id+Controller" for it to work.
In my program i have a tabPane with each tab having in own FXML file and controller .I have loaded the FXML file for tab 2 (Schedular).I`m trying to call a function in my child controller (Scheduler) from my parent controller(FXML Document) . When i load the controller using FXML Loader it returns a null. How can i solve this .
Here is my main code:
Main FXMLDocument :
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="AnchorPane" prefHeight="600" prefWidth="800" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="showprojavafxml.FXMLDocumentController">
<children>
The FXMLLoader only instantiates the controller when it loads the fxml file (this has to be the case, since the controller class is specified in the fxml file...). Since you never call load() on the loader, the controller is never created.
It looks like you are referencing the FXML file twice through two different mechanisms: once in FXMLDocumentController.initialize(), where you create a FXMLLoader whose location is set to the fxml file, and once in the main FXML document itself, via a <fx:include>. The <fx:include> is causing the UI defined in Scheduler.fxml to be displayed; the FXMLLoader you create in the initialize() method is not (because you never call load() and display the result).
To reference a controller for an included fxml, use the "Nested controller" technique.
First, add an fx:id to your fx:include:
<Tab fx:id="tab2" text="Scheduler" >
<fx:include fx:id="scheduler" source="Scheduler.fxml" />
</Tab>
Now you can inject the controller into a field whose name is the fx:id with the text "Controller" appended:
public class FXMLDocumentController {
#FXML
private SchedulerController schedulerController ;
#Override
public void initialize(URL url, ResourceBundle rb) {
schedulerController.refreshList();
}
}
<AnchorPane>
<TreeView fx:id="locationTreeView" focusTraversable="true" prefHeight="449.0" prefWidth="725.0" style="#tree
{
-fx-border-style:solid;
-fx-border-width:1px;
-fx-border-color:#ffffff;
}"/>
In the above fxml code I want to add one more <TreeView> but through the controller. How can I do this?
You will have to:
Give a fx:id to the AnchorPane:
<AnchorPane fx:id="theAnchorPane">
Add the corresponding field in the controller:
#FXML private AnchorPane theAnchorPane;
From the code that performs the addition you have to:
Create the new TreeView however you like:
TreeView newTreeView = ...;
Add it to the childen of the AnchorPane, possibly with some constraints:
theAnchorPane.getChildren().add(newTreeView);
AnchorPane.setTopAnchor(newTreeView, ...); // etc
I have an mxml page that has this tag:
<fx:Declarations>
<mx:StringValidator id = "validator"
source = "{myTextInput}"
property = "text"
required = "true"
maxLength = "128"/>
<fx:Declarations>
I want to do the same in another page but build and add the validator dynamically using action script. I have this code for building the validator:
var lengthTextValidator:StringValidator = new StringValidator();
lengthTextValidator.source = fieldTextInput;
lengthTextValidator.property = "text";
lengthTextValidator.required = true;
How can I finish the work and add the validator to the page? Thanks!
To add a UIComponent as a child of another UIComponent you can use addChild():
myComponent.addChild(myOtherUIComponent);
However, a validator is not a UIComponent or DisplayObject. It does not get added as a child to a page. If you are just replacing the fx:Declaration piece of an MXML file with an ActionScript piece that does the same thing, then you don't have to do much more.
I would make the lengthTextValidator a public, or protected, instance variable on the component:
public var lengthTextValidator:StringValidator = new StringValidator();
That means the variable will be use within the component. Your original syntax without the public or private will either make a method specific variable that won't be accessible when the method is done executing or will put the variable in the internal namespace.
The rest of your code must go in a method. For an ActionScript class; you can put it in a constructor. Or for a MXML class you can put it in an initialize or creationComplete event handler.
lengthTextValidator.source = fieldTextInput;
lengthTextValidator.property = "text";
lengthTextValidator.required = true;
If you are putting the validator code in a separate class; then you'll have to import the class and create an instance of it:
import myPackage.MyClass;
public var myClass :MyClass = new MyClass();
Then you can access the validator by accessing the public variable on the component:
myClass.lengthTextValidator;
Finally; if you just want to move that snippet into an ActionScript file that is not a class; you can use the include directoive inside a fx:Script block:
<fx:Script><[[
include "myASFile.as"
]]></fx:Script>
The last approach is unorthodox and not usually recommended.