How to call a function inside a nested controller when catching an event in the parent [duplicate] - javafx

This question already has answers here:
JavaFX8 fxml naming of nested controllers
(1 answer)
JavaFX Nested Controllers (FXML <include>)
(2 answers)
Closed 22 days ago.
I'm currently writing a JavaFX application with nested Views and Controllers and I need to execute a function in the nested controllers when a specific event occurs in the parent one.
The FXML for the main window is as is
<TabPane fx:id="viewsTabpane" side="RIGHT">
<Tab fx:id="graphicViewTab" closable="false">
<graphic>
<ImageView>
<Image url="#../Images/Graphic_Icon.png" requestedHeight="40" requestedWidth="40"/>
</ImageView>
</graphic>
<fx:include source="GraphicView.fxml"/>
</Tab>
<Tab fx:id="xmlViewTab" closable="false">
<graphic>
<ImageView>
<Image url="#../Images/XML_Icon.png" requestedHeight="40" requestedWidth="40"/>
</ImageView>
</graphic>
<fx:include source="XMLView.fxml"/>
</Tab>
</TabPane>
When switching from the xmlViewTab to the graphicViewTab I need to execute a updateModel() function from the XMLViewController.java file.
Any idea on how to do it ?
Thanks

Related

TreeView in FXML

How can I create a TreeView in FXML including all the branches and components in it? I can't find documentation about it. There is just code about how to populate it but I want to do it in FXML so y can have the design apart of the logic.
There's no specific documentation for FXML (beyond the Introduction to FXML document): but there is no need for any. An element beginning with an uppercase character is an instruction to instantiate the class of that name, so
<TreeView></TreeView>
will instantiate a TreeView. Attributes correspond to properties, so if you needed you could do
<TreeView editable="true"></TreeView>
Nested elements beginning with lower case also correspond to properties, and will be set to the enclosed FXML structure. So you can create a tree view with code like
<TreeView fx:id = "treeView">
<root>
<TreeItem fx:id="rootItem" value="Root" expanded="true">
<children>
<TreeItem fx:id="child1" value="Child 1" expanded="true">
<children>
<TreeItem fx:id="child11" value="Child 1.1"></TreeItem>
<TreeItem fx:id="child12" value="Child 1.2"></TreeItem>
</children>
</TreeItem>
<TreeItem fx:id="child2" value="Child 2">
<children>
<TreeItem fx:id="child21" value="Child 2.1"></TreeItem>
<TreeItem fx:id="child22" value="Child 2.2"></TreeItem>
</children>
</TreeItem>
</children>
</TreeItem>
</root>
</TreeView>
You can, of course, see all the properties in the API documentation.

Padding in FXML the content of a TabPane, but not the tab bar

I am looking for an elegant way of setting a padding to a TabPane, but without padding the tab bar:
<TabPane>
<padding>
<Insets top="10" bottom="10" right="10" left="10" />
</padding>
<Tab text="red">
<Rectangle fill="RED" width="200" height="200" />
</Tab>
<Tab text="blue">
<Rectangle fill="BLUE" width="200" height="200" />
</Tab>
</TabPane>
gives:
however,
<TabPane>
<Tab text="red">
<VBox>
<padding>
<Insets top="10" bottom="10" right="10" left="10" />
</padding>
<Rectangle fill="RED" width="200" height="200" />
</VBox>
</Tab>
<Tab text="blue">
<VBox>
<padding>
<Insets top="10" bottom="10" right="10" left="10" />
</padding>
<Rectangle fill="BLUE" width="200" height="200" />
</VBox>
</Tab>
</TabPane>
gives:
which is exactly what i want, however I want to simplify the FXML structure, mainly by refactoring the <padding> element so it's declared in one place (shorter and non-repeating code) and not in every tab of the pane.
So is there any way to achieve this? Or am I stuck with my repeated <padding> elements? I'd prefer an FXML solution, but if no way exists a Java one is OK.
In a word: no.
Each Tab of the TabPane accepts a Node for it's contentProperty. The content itself is not a Region and therefore cannot have Insets or padding applied to it. The TabPane itself does not contain a method that allows you to style the content of all the child Tabs at once.
You must first add a container of some sort to the Tab in order to apply padding. So the second method in your question is the simplest way to accomplish what you are trying to do.
A Workaround
While this cannot be done with FXML, you could use a Java loop to add the same padding to all of your Tab objects after loading the scene:
Insets insets = new Insets(10);
for (Tab tab : tabPane.getTabs()) {
((VBox) tab.getContent()).setPadding(insets);
}
This assumes, of course, that you use a VBox for the content of all your tabs.
EDIT: I updated the answer to use the CSS selectors from fabian's comment down below.
You can set padding for most JavaFX scene graph objects in a separate css file. You will need to link the css file to your FXML file which I will show below. The css file and the FXML file will need to be in the same directory, otherwise you will have to edit the value="..." tag.
style.css
.tab-pane > .tab-content-area > * {
-fx-padding: 10 10 10 10;
}
This sets padding to all the VBoxes that happen to be under a Tab somewhere (no matter how deep in the hierarchy)
main.fxml
<TabPane>
<Tab text="red">
<VBox>
<Rectangle fill="RED" width="200" height="200" />
</VBox>
</Tab>
<Tab text="blue">
<VBox>
<Rectangle fill="BLUE" width="200" height="200" />
</VBox>
</Tab>
<stylesheets>
<URL value="#style.css" />
</stylesheets>
</TabPane>

Set size of image in `ImageView` in button where image is set using css

I used fitWidth and preserveRatio to size the ImageView in the FXML, but the image does not scale to it but instead shows its full size (too big in my case). How do I set the size of the image using FXML or css?
FXML
<Button
fx:id="buttonUp"
GridPane.columnIndex="0"
GridPane.rowIndex="0"
onAction="#buttonUp">
<graphic>
<ImageView fitWidth="10.0" pickOnBounds="true" preserveRatio="true">
</ImageView>
</graphic>
</Button>
CSS
#buttonUp {
-fx-graphic: url('up.png');
}
#buttonUp:pressed {
-fx-graphic: url("up_pressed.png");
}
I don't want a JavaFX code solution because I want to keep my styling in the fxml and css.
If this really isn't possible in FXML or css then I'd concede in doing it with java, in that case just leave a comment.
Image in FXML
When I try
<ImageView id="buttonDownImage" fitHeight="40.0" fitWidth="40.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="resources/down.png" />
</image>
</ImageView>
Then there follows an java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found while I'm sure the file is there (the css could find it) and the IntellJ autocomplete even suggested to start with resources in the url.
Not tested, but try using the CSS on the ImageView itself:
<Button
fx:id="buttonUp"
GridPane.columnIndex="0"
GridPane.rowIndex="0"
onAction="#buttonUp">
<graphic>
<ImageView id="buttonUpGraphic" fitWidth="10.0" pickOnBounds="true" preserveRatio="true">
</ImageView>
</graphic>
</Button>
and then in CSS:
#buttonUp #buttonUpGraphic {
-fx-image: url('up.png');
}
#buttonUp:pressed #buttonUpGraphic {
-fx-image: url('up_pressed.png');
}
If the pictures are too big, well, then resize them! Bad solution, but better than nothing.

Gluon SceneBuilder 8.1.1 Problems using Include or Import FXML

I cannot include a simple fxml file into a BorderPane or TabPane.
Details including some sample code are already reported here:
https://bitbucket.org/gluon-oss/scenebuilder/issues/68/various-problems-trying-to-inlcude-an-fxml
I still have a few questions according this topic:
Is there a limitation of containers where you may fx:include into ? (e.g. are TabPanes not allowed??)
Is there some specific thing I had to do inside the included FXML file which I am missing?
Any other hint?
If you experience the same problems - maybe you could vote for the bug, so we increase the chances to get a fix.
By default, when you include one FXML file into another using Scene Builder menu File -> Include -> FXML..., the included file is added under the root, according the following code:
final FXOMObject rootObject = targetDocument.getFxomRoot();
if (rootObject != null) {
final Selection selection = getEditorController().getSelection();
if (selection.isEmpty() || selection.isSelected(rootObject)) {
targetObject = rootObject;
} else {
targetObject = selection.getAncestor();
}
...
}
In the case of your AnchorWithTabPane.fxml file, if you don't select anything, it will be included under the root:
<AnchorPane ...>
<children>
<TabPane .../>
<fx:include source="UserControl.fxml" />
</children>
</AnchorPane>
Now, if you select TabPane, going through the else condition, it will go again under the root, giving that the tabPane's ancestor is the root itself.
If you select Tab, the ancestor is TabPane, but there you can't include a FXML node.
If you select the AnchorPane of a tab, the ancestor is the tab, and you can't include there a FXML node either.
So the solution or workaround in this case is adding some inner container or node to that anchor pane, and then selecting it: since its ancestor will be the AnchorPane, it will add the FXML node there.
And finally you can delete that temporary container/node.
As a result, you will have:
<TabPane ...>
<tabs>
<Tab text="Untitled Tab 1">
<content>
<AnchorPane ...>
<children>
<fx:include source="UserControl.fxml" />
</children>
</AnchorPane>
</content>
</Tab>
<Tab text="Untitled Tab 2">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
</content>
</Tab>
</tabs>
Regarding your question about what containers can hold an fx:include, all the panes under javafx.scene.layout.* can hold them.
As hint, if you use NetBeans, edit an fxml file, and within the container tags click Ctrl+space, it will show you if the fx:include node is allowed:

Graphic and text position in a button (JavaFX) [duplicate]

I was wondering How one can achieve following button style where text resides underneath of image in JavaFx?
I tried a lot but all in vain. Any help would be appreciated.
The key is the contentDisplay property, set it to "TOP".
With fxml:
<Button contentDisplay="TOP" layoutX="101.0" layoutY="51.0" mnemonicParsing="false" text="Button">
<graphic>
<ImageView mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#image.png" preserveRatio="false" smooth="false" />
</image>
</ImageView>
</graphic>
</Button>
Or CSS:
.your-selector {
-fx-content-display: top;
}
Check the CSS reference here.
You can simply achieve that just by doing
Button b = new Button("text", graphics);
b.setContentDisplay(ContentDisplay.TOP);
And for cool icons, take a look at http://fxexperience.com/controlsfx/features/ it include icone from FontAwesome and IcoMoon

Resources