Add a GridPane to a ScrollPane using code javafx - javafx

Please how can I add a GridPane to a ScrollPane that I have in my fxml file with javafx code ?

If your ScrollPane has been defined in an FXML file, you need to add a reference to it within your Controller class. This is done along with any other instance fields you need to define (at the top of your controller class). Since the node is defined in an FXML document, you will annotate your Java code with the #FXML annotation:
#FXML
private ScrollPane myScrollPane;
This essentially tells JavaFX that the ScrollPane is created in the FXML document, and not within your Java class.
The ScrollPane has a Content property that holds the node you want.
So you would simply set your GridPane as the Content of the ScrollPane:
scrollPane.setContent(myGridPane);

Related

javafx load fxml into pane [duplicate]

I'm learning basic JavaFX right now, and I don't understand this statement from the book I'm reading: "No, a node such as a text field can be added to only one pane and once. Adding a node to a pane multiple times or to different panes will cause a runtime error." I can see from the UML diagram the book provides that it is a composition, but I don't understand why (library class code implementation) that is.
For instance, why does this result in a compile error? Isn't a new text field instantiated within the pane since it's a composition?
FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf);
Also, why does the following run but not show the text field placed in pane?
FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane2.getChildren().add(tf);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
This is basically a (deliberate) consequence of the way the API is designed. Each Node has a collection of properties, including a parent property (the - one and only one - parent of the node in the scene graph), along with properties such as layoutX and layoutY which are the coordinates of the node in relation to its parent. Consequently, a node can only belong to one parent, and can only be added to a parent once (as it can only have one location in the parent). Organizing things this way enables a very efficient layout process.
Another way to think of this: suppose your first code block did what you wanted; so the text field tf appeared twice in the flow pane. What result would you expect to get from tf.getBoundsInParent()? Since tf appears twice in the parent, the API would not be able to give a sensible value for this call.
There are a couple of inaccuracies in statements you make in your question:
For instance, why does this result in a compile error? Isn't a new
text field instantiated within the pane since it's a composition?
First, technically, this is aggregation, not composition; though I'm not sure understanding the difference will aid your understanding of what is happening at this point.
Second, there is no compile error here; you get an error at runtime (the pane detects that the same node has been added twice; the complier has no way to check this).
Third, parents do not instantiate copies of the nodes you add to them. If so, you wouldn't be able to change the properties of nodes that were displayed. For example, if the FlowPane in your example instantiated a new TextField when you called pane.getChildren().add(tf);, and then displayed that new text field, then if you subsequently called tf.setText("new text"), it would have no effect, as it would not be changing the text of the text field that pane was displaying.
When you call pane.getChildren().add(...) you pass a reference to the node you want to be added; it is that node that is then displayed as a child of the pane. Any other implementation would produce pretty counter-intuitive behavior.
In your second code block:
pane.getChildren().add(tf);
pane2.getChildren().add(tf);
the second call implicitly sets the parent property of tf to pane2; consequently tf is no longer a child of pane. So this code has the effect of removing tf from the first parent, pane. As far as I am aware, this side-effect is not documented, so you probably should avoid writing code like this.
Try this:
TextField tf = new TextField();
TextField tf2 = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf2);
The reason you cannot add the same node twice is that only one node with the same specifications and dimensions can be viewable in the gui. It would be like copying an identical blue circle onto an original blue circle. To the user it looks the same, but it takes up more memory.

JavaFX - How to load a specific AnchorPane's contents from an FXML file?

I'm trying to make an application which switches between scenes back and forth however I need to load a specific AnchorPane's contents into another AnchorPane when the scene switches back. For Example:
In my FXML1, I have a hierarchy that looks like this:
AnchorPane0
----SplitPane
--------AnchorPane1
--------AnchorPane2
In FXML2 the hierarchy is just this:
AnchorPane0
So I load FXML1, then I have a button that switches scenes loading FXML2.AnchorPane0 into FXML1.AnchorPane2. I have a back button in FXML2.AnchorPane0 that needs to load the original scene of FXML1.AnchorPane2 into FXML1.AnchorPane2. Right now my back button loads all 4 containers of FXML1 into FXML1.AnchorPane2. So my questions is, how do I load a specific container's contents preferably without making FXML1.AnchorPane2 its own FXML? Do I need to write a get method for the FXML1.AnchorPane2 to access its contents or is there a way to return an AnchorPane with all of its contents in place already?
I found the solution as shown below:
AnchorPane loader = FXMLLoader.load(getClass().getResource("myFXML.fxml"));
SplitPane spane = (SplitPane) loader.getChildren().get(0);
AnchorPane pane = (AnchorPane) spane.getItems().get(1);
foregroundAnchorPane.getChildren().setAll(pane);

JavaFX BorderPane vs Pane hiding Labels

I have a working map using Pane and Path and Label objects. I place several Path and Label objects onto the Pane. The Path objects represent countries and the Label objects their capitals. So it shows a country and in the middle a Label with a String object bound to the Label.
count.textProperty().bind(system.getNations().get(nameNoSpace).getTroopCount().asString());
When using BorderPane instead of Pane the Label objects suddenly stop showing up?
Any idea what is the reason ?
Is the BorderPane hiding the Labels ?
Thanks
You cannot add children to a BorderPane using the root.getChildren().add(node) method.
to add object to a BorderPane you need to use other methods such as
setCenter(node);
setTop(node);
setBottom(node);
setLeft(node);
setRight(node);
See the BorderPane documentation for more informations.
If you need to use thegetChildren().add() method you can insert a Pane at the center of the BorderPane and add the nations in the Pane.

How to create an inner popup in JavaFX styled with FXML

I have an FXML file that I'm using to allow user input when requested. Right now I just put it in a new stage and do Stage.show(). I would like to not have it appear in a new window and behave more like a ContextMenu.
Looking at ContextMenu class it doesn't appear that I can set the content based off an FXML file. Is there a way to do this either with ContextMenu or Popup or some other class I am unaware of?
Although that library is quite nice, I wanted something simple that didn't require 3rd party downloads. I came up with this:
Popup popup = new Popup();
CustomController controller = new CustomController();
FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlfile));
loader.setController(controller);
popup.getContent().add((Parent)loader.load());
The problem was I didn't realize that a Parent could be considered a Node for the method Popup#getContent#add
ControlsFX has a PopOver control you might like. That PopOver can use any Node for its content, so you can simply create a popover, load a node from FXML and set the content of the popover to that node.

What is the justification for JavaFX FXML schema not supporting context menu inside the panes?

It is possible to add a context menu to a scroll pane, but not to other types of panes. Why?
How FXML Works
FXML works by introspecting on the Java API using reflection (or by using specialized builder classes). More information on FXML works can be found in the Introduction to FXML documentation.
Why ContextMenus can't be defined on Panes in JavaFX using FXML Markup
Control has a contextMenu property. A ScrollPane is a Control. Other pane types such as StackPane are not controls. As there is no corresponding property in these other pane types which could be set to contain a reference to a contextMenu, you can't define a contextMenu on these pane types using FXML.
For similar reasons, you can't define a Tooltip on a Pane either.
How to define a ContextMenu for a Panes in an FXML Controller
You can still set a context menu on panes (and any other arbitrary nodes which are not controls) via code, using the contextMenu show API, for example by placing the following code in your FXML controller.
#FXML StackPane stack;
// . . .
public void initialize() {
final ContextMenu contextMenu = new ContextMenu(new MenuItem("xyzzy"));
stack.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
contextMenu.show(
stack,
mouseEvent.getScreenX(),
mouseEvent.getScreenY()
);
}
});
}
Why not add a ContextMenu property
Node could have a contextMenu property, which would allow ContextMenus to be defined on Panes via FXML Markup.
The reason why Node does not have a contextMenu property but Control does is because ContextMenu is itself a Control. Adding a ContextMenu property to node would mean that the core scene graph model code for the JavaFX implementation would have a dependency on the controls module (which would have a dependency on the scene graph module), hence a circular dependency. This would prevent the shipping of a very light Java runtime system which included the core JavaFX scene graph and rendering engine but did not include controls (not that anybody ships such a system today).
How to File Feature Requests
If you think the system should be changed to allow definition of context menus on arbitrary panes using SceneBuilder, then you can file a feature request against the JavaFX issue tracker (if you do so, include a link back to this question in the feature request).
Described method to open popup leads to multiple popups open if every node in the scene graph want to open context menu. Consuming of event is definitely needed.
See also discussion at Using FXML to Create ContextMenu within a Pane It provides working answer to this problem.
BTW, Node.onContextMenuRequested(...) should be used instead, yes?

Resources