title: SceneBuilder Custom Control Classpath
body: <p>I am at wit's end with SceneBuilder and Java FX's way of handling custom controls.</p>
  
  <ol>
  <li><p>Do I use fx:root, or do I NOT use it? I opted to use it. So within
  the Controller+Root class of the control, I set itself as the root
  and controller, just as required. But it still says "Root hasn't
  been set. Use method setRoot() before load."</p></li>
  <li><p>Within the parent FXML that will house the custom control, what am I
  supposed to import?</p></li>
  <li><p>What is the correct classpath so that I can display my custom
  control in SceneBuilder 2.0? I don't quite understand the
  "/.../.../.../bin" thing at all.</p></li>
  <li><p>With the new <code>&lt;fx:include&gt;</code> tag, is it necessary to use
  <code>&lt;MyCustomControl /&gt;</code> within the markup anymore?</p></li>
  </ol>
  
  <p>So far, my custom control is nothing but a progress indicator, to avoid complications.</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  
  &lt;?import java.lang.*?&gt;
  &lt;?import javafx.scene.control.*?&gt;
  &lt;?import javafx.scene.layout.*?&gt;
  &lt;?import javafx.scene.layout.HBox?&gt;
  
  
  &lt;fx:root type="HBox" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"&gt;
     &lt;children&gt;
        &lt;ProgressBar fx:id="progressBar" prefWidth="200.0" progress="0.0" /&gt;
     &lt;/children&gt;
  &lt;/fx:root&gt;
  
  package application.ctrl;
  
  import java.io.IOException;
  
  import javafx.fxml.FXML;
  import javafx.fxml.FXMLLoader;
  import javafx.scene.control.ProgressIndicator;
  import javafx.scene.layout.HBox;
  import application.Main;
  </code></pre>
  
  <p>Its controller:</p>
  
  <pre><code>public class ProgressSelector extends HBox {
  
      @FXML
      private ProgressIndicator progressBar;
  
  
  
      public ProgressSelector() {
          FXMLLoader loader = new FXMLLoader(getClass().getResource(
                  Main.PROGRESS_SELECTOR));
          loader.setRoot(this);
          loader.setController(this);
          loader.setClassLoader(this.getClass().getClassLoader());
          try {
              loader.load();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  }
  </code></pre>
  
  <p>The parent FXML:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  
  &lt;?import javafx.scene.text.*?&gt;
  &lt;?import javafx.geometry.*?&gt;
  &lt;?import java.lang.*?&gt;
  &lt;?import javafx.scene.control.*?&gt;
  &lt;?import javafx.scene.layout.*?&gt;
  &lt;?import javafx.scene.layout.VBox?&gt;
  &lt;?import application.ctrl.ProgressSelector?&gt;
  
  &lt;VBox fx:id="vbox" spacing="5.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.ctrl.ObjectiveEditorCtrl"&gt;
     &lt;children&gt;
        &lt;HBox&gt;
           &lt;children&gt;
              &lt;Button mnemonicParsing="false" onAction="#back" text="&amp;lt;" /&gt;
              &lt;Label text="Editing Objective:" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
        &lt;TextField fx:id="objectiveName" /&gt;
        &lt;ProgressSelector /&gt;
        &lt;HBox&gt;
           &lt;children&gt;
              &lt;Label text="Planned Start:" /&gt;
              &lt;Region HBox.hgrow="ALWAYS" /&gt;
              &lt;DatePicker fx:id="plannedStart" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
        &lt;HBox&gt;
           &lt;children&gt;
              &lt;Label text="Actual Start:" /&gt;
              &lt;Region HBox.hgrow="ALWAYS" /&gt;
              &lt;DatePicker fx:id="actualStart" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
        &lt;HBox&gt;
           &lt;children&gt;
              &lt;Label text="Planned Finish:" /&gt;
              &lt;Region HBox.hgrow="ALWAYS" /&gt;
              &lt;DatePicker fx:id="plannedFinish" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
        &lt;HBox&gt;
           &lt;children&gt;
              &lt;Label text="Actual Finish:" /&gt;
              &lt;Region HBox.hgrow="ALWAYS" /&gt;
              &lt;DatePicker fx:id="actualFinish" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
        &lt;HBox alignment="CENTER_RIGHT"&gt;
           &lt;children&gt;
              &lt;Button mnemonicParsing="false" onAction="#save" text="Save" /&gt;
              &lt;Button mnemonicParsing="false" onAction="#back" text="Cancel" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
     &lt;/children&gt;
     &lt;padding&gt;
        &lt;Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /&gt;
     &lt;/padding&gt;
  &lt;/VBox&gt;
  </code></pre>
  
  <p>Its controller:</p>
  
  <pre><code>package application.ctrl;
  
  import interfaces.ControlledScreenInterface;
  
  import java.net.URL;
  import java.util.ResourceBundle;
  
  import javafx.fxml.FXML;
  import javafx.fxml.Initializable;
  import javafx.scene.control.DatePicker;
  import javafx.scene.control.TextField;
  import javafx.scene.layout.VBox;
  import application.ScreenController;
  import application.objects.Objective;
  
  public class ObjectiveEditorCtrl implements Initializable,
          ControlledScreenInterface {
  
      @FXML
      private TextField objectiveName;
      @FXML
      private ProgressSelector completion;
      @FXML
      private DatePicker plannedStart;
      @FXML
      private DatePicker plannedFinish;
      @FXML
      private DatePicker actualStart;
      @FXML
      private DatePicker actualFinish;
      @FXML
      private VBox vbox;
  
      private ScreenController parent;
      private Objective current;
  
  
  
      @Override
      public void initialize(URL location, ResourceBundle resources) {
          // TODO Auto-generated method stub
  
      }
  
  
  
      public void init(Objective current) {
          this.current = current;
          objectiveName.setText(current.getName());
          // completion.setProgress(current.getCompletion());
          plannedStart.setValue(current.getPlannedStart());
          actualStart.setValue(current.getActualStart());
          plannedFinish.setValue(current.getPlannedFinish());
          actualFinish.setValue(current.getActualFinish());
      }
  
  
  
      public void save() {
          // current.setName(objectiveName.getText());
          // // current.setCompletion(completion.getProgress());
          // current.setPlannedStart(plannedStart.getValue());
          // current.setPlannedFinish(plannedFinish.getValue());
          // current.setActualStart(actualStart.getValue());
          // current.setActualFinish(actualFinish.getValue());
          // back();
      }
  
  
  
      public void back() {
          parent.back();
      }
  
  
  
      @Override
      public void setParentScreen(ScreenController parent) {
          this.parent = parent;
      }
  }
  </code></pre>