Reuse the same FXML declaration for menu bar and context menu - javafx

I have declared a menu bar in FXML with a bunch menu items (containing graphics, onClick method links etc...).
Now I'm creating a context menu for a table, and I'd like to put in there all the menu items for the "Edit" menu of the menu bar.
Is there a DRY way of doing so in FXML?
I don't like the idea of copying all the FXML declarations of the menu items, and having to maintain both sets of items.
I know I could reuse the items if I declared them in Java code, but I'd like to keep all my layout in FXML.
Here is the FXML for the edit menu, that I don't want to duplicate:
<Menu text="_Edit">
<MenuItem onAction="#copyRaw" text="Copy _raw log">
<accelerator>
<KeyCodeCombination alt="UP" code="C" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator>
<graphic>
<Glyph fontFamily="FontAwesome" icon="copy" />
</graphic>
</MenuItem>
<MenuItem onAction="#copyPretty" text="Copy with _columns">
<accelerator>
<KeyCodeCombination alt="UP" code="C" control="DOWN" meta="UP" shift="DOWN" shortcut="UP" />
</accelerator>
<graphic>
<Glyph fontFamily="FontAwesome" icon="copy" />
</graphic>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem onAction="#selectAll" text="Select _All">
<accelerator>
<KeyCodeCombination alt="UP" code="A" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator>
</MenuItem>
<MenuItem mnemonicParsing="false" onAction="#unselectAll" text="Unselect All" />
</Menu>

I'm not sure that my idea is best but u should to do it like this:
You can create a package in resources with most used elements as Buttons,Tables,Labels etc. for each assign an fx:id and include that in another fxmls.
Example:
PACKAGE: resource/package/name/utils/Label.fxml
<?import javafx.scene.control.Label?>
<?import javafx.geometry.Insets?>
<Label xmlns:fx="http://javafx.com/fxml"
fx:id="label"
style="-fx-background-color: red;
-fx-font: bold;
-fx-font-size: 30px;"
text="Hello world">
<padding>
<Insets top="5" left="5" right="5" bottom="5"/>
</padding>
</Label>
<!--Add all your nodes there-->
PACKAGE: resource/package/name/Main.fxml
<GridPane xmlns:fx="http://javafx.com/fxml" alignment="TOP_CENTER" hgap="10" vgap="10">
<fx:include source="Label.fxml"/> <!--There will be displayed all elements from Label.fxml-->
</GridPane>
In your case you just need to set fx:id for your Menu item and import in another fxml.
Good luck.

Related

Using FontAwesomeFX, how to have two icons for one button?

In my JavaFX program I am using FontAwesomeFX to add icons to buttons, labels, etc.
The way how I style this is through the .fxml file:
<Button fx:id="btnGoToWeb"
onAction="#btnGoToWeb">
<tooltip>
<Tooltip text="Go to Web"/>
</tooltip>
<graphic>
<FontAwesomeIconView glyphName="GLOBE" size="1.6em"/>
</graphic>
</Button>
Producing this button:
I would like to know how I can add 2 icons to one button. I would like to have something like shown below (please note the image is modified to illustrate the desired output):
Per #Slaw comment.
<Button mnemonicParsing="false" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
<graphic>
<HBox alignment="CENTER" spacing="5.0">
<children>
<FontAwesomeIconView />
<FontAwesomeIconView />
</children>
</HBox>
</graphic>
<tooltip>
<Tooltip text="Go to Web" />
</tooltip>
</Button>

What is the Function used for FXML comboBox in JavaFX

I have defined the combo Box in javaFX FXML file now i want to define it's function to get the value of Combo Box and use it in my code.
The FXML file is
<ComboBox fx:id="select_pc" promptText="Select PC">
<HBox.margin>
<Insets left="20.0" top="35.0" />
</HBox.margin>
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="ForkLift" />
<String fx:value="Gates" />
</FXCollections>
</items>
</ComboBox>
now can anybody tell me how to write a function to take the value of combo Box and use it in the String form

How to add sub-headers to menu using fxml files?

How do I add sub-headers to my menu using JavaFX and the fxml files? I have looked at the CustomMenuItem option but I am unable to figure out what to put in the content part. Thanks for your help!
My fxml file:
<?import javafx.scene.input.*?>
<?import javafx.scene.control.*?>
<MenuBar>
<menus>
<Menu text="Menu 1">
<items>
<MenuItem text="Item 1" />
<MenuItem text="Item 2" />
<MenuItem text="Item 3" />
<SeparatorMenuItem />
<MenuItem text="Item A" />
<MenuItem text="Item B" />
<MenuItem text="Item C" />
</items>
</Menu>
</menus>
</MenuBar>
Below is an example of the result I am looking for. "Header 1" and "Header 2" shouldn't be clickable and should not highlight when the mouse moves over them.
Thanks for your input. Based on the link you provided, I found that it simply can be done adding the following in the fxml file:
<SeparatorMenuItem>
<content>
<Text text="Header Name" styleClass="textSeparator" />
</content>
</SeparatorMenuItem>
I think the answer you're looking for is here:
http://tiwulfx.panemu.com/2013/01/02/creating-custom-menu-separator-in-javafx/

JavaFX unable to find node declared in FXML at runtime using ID

Im unable to find a node "VBox" with id "#mainScrollPaneVbox" declared in FXML.
Here is my FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<BorderPane 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" fx:controller="com.conuretech.video_assembler.FXMLController">
<top>
<MenuBar prefHeight="16.0" prefWidth="600.0" BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#handleNewAction" text="New" />
<MenuItem mnemonicParsing="false" onAction="#handleOpenProjectAction" text="Open Project" />
<MenuItem mnemonicParsing="false" onAction="#handleSaveAsAction" text="Save As..." />
<MenuItem mnemonicParsing="false" onAction="#handleSaveAction" text="Save..." />
<MenuItem mnemonicParsing="false" onAction="#handleCovertImagesToVideoAction" text="Convert Project To video" />
<MenuItem mnemonicParsing="false" onAction="#handleImportLocalAction" text="Import Local Images" />
<MenuItem mnemonicParsing="false" onAction="#handleImportRemoteAction" text="Import Remote Images" />
<MenuItem mnemonicParsing="false" onAction="#handleExitAction" text="Exit" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Add New Frame From" />
<MenuItem mnemonicParsing="false" text="Delete Current Frame" />
<MenuItem mnemonicParsing="false" text="Edit Frame Properties" />
<MenuItem mnemonicParsing="false" text="Video Properties" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<left>
<ScrollPane id="#mainScrollPane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<content>
<VBox id="#mainScrollPaneVbox" prefHeight="200.0" prefWidth="200.0" />
</content></ScrollPane>
</left>
<center>
<GridPane BorderPane.alignment="CENTER">
<columnConstraints>
<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>
</GridPane>
</center>
</BorderPane>
Here is the Java code, that attempts to find the "Vbox" at runtime:
VBox vbox = (VBox) MainApp.scene.lookup("#mainScrollPaneVbox");
I also tried :
VBox vbox = (VBox) MainApp.scene.lookup("mainScrollPaneVbox");
But this still returns null.
Any ideas?
Thanks
Why your code doesn't work
The id attribute in the FXML should contain just the id of the node, not the CSS lookup for the id. In other words, you have
<VBox id="#mainScrollPaneVbox" ... >
when you need
<VBox id="mainScrollPaneVbox" ... >
The lookup should have the CSS lookup:
VBox vbox = (VBox) MainApp.scene.lookup("#mainScrollPaneVbox");
But I would not advise doing things this way anyway, especially since you already have a controller class.
Recommended Approach
CSS lookups are not very robust. They rely on String binding, and are not typesafe. Moreover, any errors will not be caught until the lookup is actually performed, which may be well after the application has been launched (e.g. when the user performs some action).
A better approach is to use #FXML injection. While these still rely on String binding and there is no compile-time type checking, errors will be caught when the FXML file is loaded, so any failures happen much earlier. This makes it much easier to detect and fix errors.
To use #FXML injection you would do
<VBox fx:id="mainScrollPaneVbox"
and then in your controller class:
public class FXMLController {
#FXML
private VBox mainScrollPaneVbox ; // same field name as the fx:id
// ...
public void initialize() {
// popuplate mainScrollPaneVbox ...
// can similarly be accessed in event handlers
// ...
}
// ...
}

JavaFX tableview resize to fit window

I am just trying out JavaFX and am forcing my way into it because it is suppose to be the future. I am trying to create a table with 4 columns. The columns AND THE TABLE should resize to fill the parent pane. I cannot for the life of me get this to work. I have been trying for over 4 hours now and the tableview does not resize.
Here is my FXML file.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.collections.*?>
<?import t.cubed.fxml.*?>
<BorderPane styleClass="root" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="t.cubed.fxml.FXMLDocumentController">
<top>
<MenuBar fx:id="menuBar" styleClass="menu-bar">
<menus>
<Menu text="File">
<items>
<MenuItem onAction="#handleOpenAction" text="Open" />
<MenuItem onAction="#handleExitAction" text="Exit" />
</items>
</Menu>
<Menu text="Edit">
<items>
<MenuItem onAction="#handleWeightAction" text="Edit Weights" />
<MenuItem onAction="#handleFilterAction" text="Edit Filters" />
<MenuItem onAction="#handleOptionsAction" text="Options" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<GridPane>
<!--
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
-->
<TableView fx:id="testTable" GridPane.columnIndex="0" GridPane.rowIndex="0" GridPane.columnSpan="1">
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
<columns>
<TableColumn text="TEST NUMBER">
<cellValueFactory>
<PropertyValueFactory property="testNumber" />
</cellValueFactory>
</TableColumn>
<TableColumn text="TEST NAME">
<cellValueFactory>
<PropertyValueFactory property="testName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="TEST TIME(ms)">
<cellValueFactory>
<PropertyValueFactory property="testTime" />
</cellValueFactory>
</TableColumn>
<TableColumn text="BEST MATCH">
<cellValueFactory>
<PropertyValueFactory property="bestMatch" />
</cellValueFactory>
</TableColumn>
</columns>
<items>
<!--
<FXCollections fx:factory="observableArrayList">
<TestTableModel testNumber="100" testName="Test1234" testTime="0.34" bestMatch="99"/>
</FXCollections>
-->
</items>
</TableView>
</GridPane>
</center>
<stylesheets>
<URL value="#t-cubed.css" />
</stylesheets>
</BorderPane>
How Resizable Layout Works
The size of resizable items in JavaFX is managed by the layout managers in which the items are placed.
What you need to do
For your particular issue, you need to set the GridPane sizing constraints to manage the TableView that you placed in the grid.
See the GridPane.hgrow and GridPane.vgrow constraints I added on the TableView:
<TableView fx:id="testTable"
GridPane.columnIndex="0"
GridPane.columnSpan="1"
GridPane.hgrow="ALWAYS"
GridPane.vgrow="ALWAYS"
GridPane.rowIndex="0">
FXML just reflects the Java API, so you could also do the same in Java source as well; i.e. GridPane.setHGrow(node, priority). Though, if you are using FXML for your layout, defining the layout constraints in FXML is recommended.
Refactored Sample
I loaded your FXML up in Scene Builder 2 and set the appropriate constraints and it appears to resize automatically fine when I use the preview functionality of Scene Builder.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.collections.*?>
<?import t.cubed.fxml.*?>
<BorderPane styleClass="root" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="t.cubed.fxml.FXMLDocumentController">
<top>
<MenuBar fx:id="menuBar" styleClass="menu-bar">
<menus>
<Menu text="File">
<items>
<MenuItem onAction="#handleOpenAction" text="Open" />
<MenuItem onAction="#handleExitAction" text="Exit" />
</items>
</Menu>
<Menu text="Edit">
<items>
<MenuItem onAction="#handleWeightAction" text="Edit Weights" />
<MenuItem onAction="#handleFilterAction" text="Edit Filters" />
<MenuItem onAction="#handleOptionsAction" text="Options" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<GridPane>
<children>
<!--
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
-->
<TableView fx:id="testTable" GridPane.columnIndex="0" GridPane.columnSpan="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="0" GridPane.vgrow="ALWAYS">
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
<columns>
<TableColumn text="TEST NUMBER">
<cellValueFactory>
<PropertyValueFactory property="testNumber" />
</cellValueFactory>
</TableColumn>
<TableColumn text="TEST NAME">
<cellValueFactory>
<PropertyValueFactory property="testName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="TEST TIME(ms)">
<cellValueFactory>
<PropertyValueFactory property="testTime" />
</cellValueFactory>
</TableColumn>
<TableColumn text="BEST MATCH">
<cellValueFactory>
<PropertyValueFactory property="bestMatch" />
</cellValueFactory>
</TableColumn>
</columns>
<items>
<!--
<FXCollections fx:factory="observableArrayList">
<TestTableModel testNumber="100" testName="Test1234" testTime="0.34" bestMatch="99"/>
</FXCollections>
-->
</items>
</TableView>
</children>
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
</GridPane>
</center>
<stylesheets>
<URL value="#t-cubed.css" />
</stylesheets>
</BorderPane>
Some Advice
You are placing the TableView inside a GridPane. Using a GridPane in your case is a little strange as the GridPane you only place one node in the GridPane. Just placing the TableView directly in the center of your BorderPane or using a simpler layout parent such as a StackPane would have worked just fine. But perhaps this is just some cut down version of a more complex UI, so perhaps that is why you have used a GridPane.
Further Reading
If you have time, read up on layout in JavaFX in the Node, Pane, Group and GridPane javadoc and try this little layout bounds demo too.
Additional Questions for Comments
mention a StackPane would work, but StackPanes don't seem to have Hgrow and Vgrow?
StackPanes don't need a Hgrow or Vgrow constraints. Those constraints set Priorities, which are defined as:
Enumeration used to determine the grow (or shrink) priority of a given
node's layout area when its region has more (or less) space available
and multiple nodes are competing for that space.
With a StackPane, all children are layered on top of each other, they don't compete for space, so such growth priority settings for child nodes are not applicable.
After some homework, we came up with some qualifying information on FXML containers. Pretty much for the same reason given above by #user3403469. In the Scene Builder, there's a long list of 'containers'. Imho, only these 9 elements and Pane qualify as layout container, as they inherit from
<Pane> ... parent for all Pane classes. While both, Pane and Control inherit from Region only the Pane child-classes have layout properties.
* <AnchorPane>
* <BorderPane>
* <FlowPane>
* <GridPane>
* <StackPane>
* <TextFlow>
* <TilePane>
* <HBox>
* <VBox>
You can consider that Control child-classes more or less inherit Events and actions. Layout like things need to come from the encapsulating region, and the only thing with layout elements available to wrap a 'Control' is-a 'Pane'.
javafx.scene.layout.Pane
These FXML elements would be the bespoke 'layout managers' described in the #jewelsea's answer and elsewhere.
I guess 'Control' containers are still containers in FXML. It seems that they need to be 'inside' a panel to do good ;-)
Corrections and comment welcome.
related:
Percent width for TableColumn in JavaFX 2.x TableView
There seems to be a lot of code. My idea of dynamic resizing is a Zero-tolerance for code to do scaling and resize. Gee we left that behind in Windows 1.3 didn't we?
where is the: FXML Specification?
Reference and Guidelines for Dynamic Layout using JavaFX

Resources