I worked on stage when I noticed that I did the same thing almost three times. Instead (since I hate it), I decided to take what I had 3 times and turn it into a custom component.
Now I know that I can add it to the code, but I can not predict the behavior of the layout (two of them will go directly to the tabs, and the third will be in the grid panel).
I tried to import the .jar that contained the control into Scene Builder. A dialog box popped up asking what I wanted to import into the JAR, but it was completely empty.
I have already seen that some people have added “user controls” (a term I use freely), only to find that basically it just dumps a bunch of components together to form a control. It might work for some people, but I'm not looking for it. To clarify
I want (I have to look into the FXML code):
<DGCSDefiner //other layout related XML code/>
what I do not want:
<GridPane //bla bla XML layout code> <columnConstraints> //bla bla column constraint stuff </columnConstraints> //etc, etc </GridPane>
Is it possible? I tear myself away from C # and VS2010 again, and I'm a little messed up when it comes to user controls, so if at all it's possible to do something like this, can someone tell me how?
Is it possible to import a compiled JAR file containing a JavaFX user control into Scene Builder, so removing it from the library will lead to what I described there?
EDIT 1 Okay, this is what I have in my FXML file. According to mlody991, I need 3 files to make this work: FXML file (built into SceneBuilder):
<?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.text.*?> <fx:root alignment="CENTER" hgap="5.0" styleClass="root" stylesheets="@DGCSDefiner.css" type="GridPane" vgap="5.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="DGCSDefiner.DGCSDefinerController"> <children> <ComboBox fx:id="cbxColorStyle" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="150.0" promptText="Select Background Color Style" /> <ColorPicker fx:id="cpSolidColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="32.0" prefWidth="283.0" visible="false" GridPane.rowIndex="1" /> <StackPane fx:id="spSettings" styleClass="Group" GridPane.rowIndex="2" GridPane.vgrow="NEVER"> <children> <GridPane fx:id="gpLinearSettings" hgap="5.0" styleClass="Group" vgap="20.0" visible="false"> <children> <Label text="Angle" GridPane.halignment="RIGHT" GridPane.valignment="CENTER"> <font> <Font name="Arial" size="12.0" /> </font> </Label> <ComboBox fx:id="cbxLinearAngle" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="150.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER" /> <Label text="1st Color" GridPane.halignment="RIGHT" GridPane.rowIndex="1" /> <ColorPicker fx:id="cpFirstLinearColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" /> <Label text="2nd Color" GridPane.halignment="RIGHT" GridPane.rowIndex="2" /> <ColorPicker fx:id="cpSecondLinearColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="2" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS" /> </children> <columnConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="NEVER" /> <RowConstraints minHeight="10.0" vgrow="NEVER" /> <RowConstraints minHeight="10.0" vgrow="NEVER" /> </rowConstraints> </GridPane> <TabPane fx:id="tabRadialSettings" styleClass="Group" tabClosingPolicy="UNAVAILABLE" visible="false"> <tabs> <Tab closable="false" text="Colors"> <content> <GridPane hgap="5.0" styleClass="Group" vgap="5.0"> <children> <Label maxHeight="1.7976931348623157E308" text="1st Color" GridPane.vgrow="NEVER" /> <ColorPicker fx:id="cpFirstRadialColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.vgrow="NEVER" /> <Label maxHeight="1.7976931348623157E308" text="2nd Color" GridPane.rowIndex="1" GridPane.vgrow="NEVER" /> <ColorPicker fx:id="cpSecondRadialColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.rowIndex="1" GridPane.vgrow="NEVER" /> </children> <columnConstraints> <ColumnConstraints hgrow="NEVER" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> </rowConstraints> </GridPane> </content> </Tab> <Tab closable="false" text="Size and Position"> <content> <GridPane hgap="5.0" styleClass="Group" vgap="5.0"> <children> <Label text="H Position" /> <Label text="V Position" GridPane.rowIndex="1" /> <Label text="Radius" GridPane.rowIndex="2" /> <Slider fx:id="sliderHPos" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="1.0" showTickMarks="true" GridPane.columnIndex="1" /> <Slider fx:id="sliderVPos" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="1.0" showTickMarks="true" value="1.0" GridPane.columnIndex="1" GridPane.rowIndex="1" /> <Slider fx:id="sliderRadius" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="1.0" showTickMarks="true" value="1.0" GridPane.columnIndex="1" GridPane.rowIndex="2" /> </children> <columnConstraints> <ColumnConstraints hgrow="NEVER" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> </rowConstraints> </GridPane> </content> </Tab> </tabs> </TabPane> </children> </StackPane> </children> <columnConstraints> <ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="ALWAYS" /> </rowConstraints> </fx:root>
Java class file (which will represent the actual object in the code):
package DGCSDefiner; import java.io.IOException; import static java.util.Arrays.asList; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.ColorPicker; import javafx.scene.control.ComboBox; import javafx.scene.control.Slider; import javafx.scene.control.TabPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; public class DGCSDefiner extends Pane { //DigiGames Color Settings Definer. // Values injected by FXMLLoader //<editor-fold defaultstate="collapsed" desc="FXML Variables"> //<editor-fold defaultstate="collapsed" desc="Containers"> @FXML private GridPane gpLinearSettings; // fx:id="gpLinearSettings" @FXML private StackPane spSettings; // fx:id="spSettings" @FXML private TabPane tabsRadialSettings; // fx:id="tabRadialSettings" //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Color Pickers"> @FXML private ColorPicker cpSolidColor, // fx:id="cpSolidColor" cpFirstLinearColor, // fx:id="cpFirstLinearColor" cpSecondLinearColor, // fx:id="cpSecondLinearColor" cpFirstRadialColor, // fx:id="cpFirstRadialColor" cpSecondRadialColor; // fx:id="cpSecondRadialColor" //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Combo Boxes"> @FXML private ComboBox<ColorStyles> cbxColorStyle; // fx:id="cbxColorStyle" @FXML private ComboBox<Integer> cbxLinearAngle; // fx:id="cbxLinearAngle" //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Sliders"> @FXMLprivate Slider sliderRadius, // fx:id="sliderRadius" sliderHPos, // fx:id="sliderHPos" sliderVPos; // fx:id="sliderVPos" //</editor-fold> //</editor-fold> private FXMLLoader Loader; @FXML // This method is called by the FXMLLoader when initialization is complete void initialize() { //<editor-fold defaultstate="collapsed" desc="Assertions"> //<editor-fold defaultstate="collapsed" desc="Container Assertions"> assert this.gpLinearSettings != null : "fx:id=\"gpLinearSettings\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.spSettings != null : "fx:id=\"spSettings\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.tabsRadialSettings != null : "fx:id=\"tabsRadialSettings\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; //</editor-fold> //<editor-fold defaultstate="collapsed" desc="ColorPicker Assertions"> assert this.cpSolidColor != null : "fx:id=\"cpSolidColor\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.cpFirstLinearColor != null : "fx:id=\"cpFirstLinearColor\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.cpSecondLinearColor != null : "fx:id=\"cpSecondLinearColor\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.cpFirstRadialColor != null : "fx:id=\"cpFirstRadialColor\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.cpSecondRadialColor != null : "fx:id=\"cpSecondRadialColor\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; //</editor-fold> //<editor-fold defaultstate="collapsed" desc="ComboBox Assertions"> assert this.cbxColorStyle != null : "fx:id=\"cbxColorStyle\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.cbxLinearAngle != null : "fx:id=\"cbxLinearAngle\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Slider Assertions"> assert this.sliderRadius != null : "fx:id=\"sliderRadius\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.sliderHPos != null : "fx:id=\"sliderHPos\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; assert this.sliderVPos != null : "fx:id=\"sliderVPos\" was not injected: check your FXML file 'JFXMLColorStyleDefiner.fxml'."; //</editor-fold> //</editor-fold> //<editor-fold defaultstate="collapsed" desc="Initializations"> //<editor-fold defaultstate="collapsed" desc="ComboBox Initializations"> this.cbxColorStyle.getItems().addAll( asList(ColorStyles.values()) ); for (int x = 0; x < 8; x++) this.cbxLinearAngle.getItems().add(x * 45); this.cbxColorStyle.setOnAction(event -> { ColorStyles CS = this.cbxColorStyle.getValue(); this.cpSolidColor.setVisible(CS == ColorStyles.SOLID); this.gpLinearSettings.setVisible(CS == ColorStyles.LINEAR); this.tabsRadialSettings.setVisible(CS == ColorStyles.RADIAL); }); //</editor-fold> this.Loader = new FXMLLoader( this.getClass().getResource("DGCSDefiner.fxml") ); this.Loader.setRoot(this); this.Loader.setController(this); //</editor-fold> } public DGCSDefiner(){ try{ this.Loader.load(); } catch(IOException e){ throw new RuntimeException(e); } } /** * Get the ColorSettings defined by the control. * @return Defined Color Settings. */ public ColorSettings getColorSettings(){ if (this.cbxColorStyle.getSelectionModel().getSelectedIndex() < 0) return null; switch(this.cbxColorStyle.getValue()){ case SOLID: return new ColorSettings(this.cpSolidColor.getValue()); case LINEAR: return new ColorSettings( this.cpFirstLinearColor.getValue(), this.cpSecondLinearColor.getValue(), this.cbxLinearAngle.getValue() ); case RADIAL: return new ColorSettings( this.cpFirstRadialColor.getValue(), this.cpSecondRadialColor.getValue(), (int)this.sliderRadius.getValue(), (int)this.sliderHPos.getValue(), (int)this.sliderVPos.getValue() ); } return null; //This should never happen. } /** * Load defined color settings. * @param cs Predefined color settings. */ public void setColorSettings(ColorSettings cs){ this.cbxColorStyle.setValue(cs.Style); switch(cs.Style){ case SOLID: this.cpSolidColor.setValue(cs.clrPrimary); break; case LINEAR: this.cbxLinearAngle.setValue(cs.intAngle); this.cpFirstLinearColor.setValue(cs.clrPrimary); this.cpSecondLinearColor.setValue(cs.clrSecondary); break; case RADIAL: this.sliderRadius.setValue(cs.intSize); this.sliderHPos.setValue(cs.intHPos); this.sliderVPos.setValue(cs.intVPos); this.cpFirstRadialColor.setValue(cs.clrPrimary); this.cpSecondRadialColor.setValue(cs.clrSecondary); } } }
And then this last file, the purpose of which eludes me:
package DGCSDefiner; import java.net.URL; import java.util.ResourceBundle; import javafx.fxml.Initializable; public class DGCSDefinerController implements Initializable { @Override public void initialize(URL location, ResourceBundle resources) { } }
Is it possible for someone to explain the purpose of this last file to me? What is this function? I can see from the sample code that I was presented with, it was installed as an FXML controller, but it still doesn't tell me anything. I have never even installed an FXML controller before, since I usually do this in code, so does it explicitly make this control importable in Scene Builder?
EDIT 2 Good. I had a hunch, and it turned out to be correct, but it did not help. I removed the link to the CSS control stylesheet, and this allowed me to add the control, no problem.
However, when I fell, this happened in the FXML file:
From this came out (just this link):
<Tab fx:id="tabBGStyle" closable="false" text="Background" />
:
<Tab fx:id="tabBGStyle" closable="false" text="Background"> <content> <GridPane alignment="CENTER" hgap="5.0" styleClass="root" vgap="5.0"> <children> <ComboBox fx:id="cbxColorStyle" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="150.0" promptText="Select Background Color Style" /> <ColorPicker fx:id="cpSolidColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="32.0" prefWidth="283.0" visible="false" GridPane.rowIndex="1" /> <StackPane fx:id="spSettings" styleClass="Group" GridPane.rowIndex="2" GridPane.vgrow="NEVER"> <children> <GridPane fx:id="gpLinearSettings" hgap="5.0" styleClass="Group" vgap="20.0" visible="false"> <children> <Label text="Angle" GridPane.halignment="RIGHT" GridPane.valignment="CENTER"> <font> <Font name="Arial" size="12.0" /> </font> </Label> <ComboBox fx:id="cbxLinearAngle" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="150.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER" /> <Label text="1st Color" GridPane.halignment="RIGHT" GridPane.rowIndex="1" /> <ColorPicker fx:id="cpFirstLinearColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="CENTER" /> <Label text="2nd Color" GridPane.halignment="RIGHT" GridPane.rowIndex="2" /> <ColorPicker fx:id="cpSecondLinearColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="2" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS" /> </children> <columnConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="NEVER" /> <RowConstraints minHeight="10.0" vgrow="NEVER" /> <RowConstraints minHeight="10.0" vgrow="NEVER" /> </rowConstraints> </GridPane> <TabPane fx:id="tabRadialSettings" styleClass="Group" tabClosingPolicy="UNAVAILABLE" visible="false"> <tabs> <Tab closable="false" text="Colors"> <content> <GridPane hgap="5.0" styleClass="Group" vgap="5.0"> <children> <Label maxHeight="1.7976931348623157E308" text="1st Color" GridPane.vgrow="NEVER" /> <ColorPicker fx:id="cpFirstRadialColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.vgrow="NEVER" /> <Label maxHeight="1.7976931348623157E308" text="2nd Color" GridPane.rowIndex="1" GridPane.vgrow="NEVER" /> <ColorPicker fx:id="cpSecondRadialColor" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.columnIndex="1" GridPane.rowIndex="1" GridPane.vgrow="NEVER" /> </children> <columnConstraints> <ColumnConstraints hgrow="NEVER" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"/> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> </rowConstraints> </GridPane> </content> </Tab> <Tab closable="false" text="Size and Position"> <content> <GridPane hgap="5.0" styleClass="Group" vgap="5.0"> <children> <Label text="H Position" /> <Label text="V Position" GridPane.rowIndex="1" /> <Label text="Radius" GridPane.rowIndex="2" /> <Slider fx:id="sliderHPos" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="1.0" showTickMarks="true" GridPane.columnIndex="1" /> <Slider fx:id="sliderVPos" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="1.0" showTickMarks="true" value="1.0" GridPane.columnIndex="1" GridPane.rowIndex="1" /> <Slider fx:id="sliderRadius" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" min="1.0" showTickMarks="true" value="1.0" GridPane.columnIndex="1" GridPane.rowIndex="2" /> </children> <columnConstraints> <ColumnConstraints hgrow="NEVER" minWidth="10.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> </rowConstraints> </GridPane> </content> </Tab> </tabs> </TabPane> </children> </StackPane> </children> <columnConstraints> <ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" /> </columnConstraints> <rowConstraints> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" vgrow="ALWAYS" /> </rowConstraints> </GridPane> </content> </Tab>
which is exactly what I DO NOT WANT.
What I would like to see is something like this:
<Tab fx:id="tabBGStyle" closable="false" text="Background"> <content> <DGCSDefiner/> </content> </Tab>
in FXML code after I dragged the user control into the constructor. Is it possible? Do I need to compile it into a jar?
Edit 3 To make this clearer, this is exactly what I want to see. It looks good, but the problem is that there is no information on how to import a custom control into Scene Builder, so that when I drag it onto the canvas I only get somewhere near one line of code, one and a half books that he writes ( it’s just stupid. If I wanted so that I could (and could) do it myself).