title: JavaFX - how to synchronize scrollbars of two elements declared in FXML file
body: <p>I am developing IDE and I just stucked in the following problem:</p>
  
  <p>I want to create TabPane, load into some place in the program (to VBox), then add TAB on use some addFile hanler and BUILD TAB content by code_workspace.fxml file (That all is working for now). But I just want to synchronize two scrollbars of the elements that are stored in the same FXML file. Concretely that is scrollbar of ScrollPane (code_line_counter) and TextArea (code_text_area).</p>
  
  <p>I had one year of studying Java, so I welcome every advice you can give me. As you can see, my english isn't very good, so I suppose you will read a lot of information from a code:</p>
  
  <p><strong>FileManager.java</strong></p>
  
  <pre><code>package sample;
  
  import javafx.application.Platform;
  import javafx.fxml.FXML;
  import javafx.fxml.FXMLLoader;
  import javafx.fxml.Initializable;
  import javafx.scene.control.*;
  import javafx.scene.layout.StackPane;
  import javafx.scene.layout.VBox;
  
  import java.net.URL;
  import java.util.ResourceBundle;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  public class FileManager extends TabPane implements Initializable {
  
      @FXML private ScrollPane code_line_counter;
      @FXML private TextArea code_text_area;
      @FXML private Label code_line_counter_label;
  
      private int created_tabs;
  
      public FileManager()
      {
          super();
          super.setTabClosingPolicy(TabPane.TabClosingPolicy.ALL_TABS);
          this.created_tabs = 0;
      }
  
      @Override
      public void initialize(URL location, ResourceBundle resources)
      {
  
          code_text_area.textProperty().addListener((observable, oldValue, newValue) -&gt; {
  
              Matcher matcher_old_value = Pattern.compile("\n").matcher(oldValue);
              Matcher matcher_new_value = Pattern.compile("\n").matcher(newValue);
  
              int old_line_count = 0;
              int new_line_count = 0;
  
              while (matcher_old_value.find()) {
                  old_line_count++;
              }
  
              while (matcher_new_value.find()) {
                  new_line_count++;
              }
  
              if (new_line_count != old_line_count) {
  
                  code_line_counter_label.setText("1");
                  for (int i = 2; i &lt; new_line_count + 2; i++)
                      code_line_counter_label.setText(code_line_counter_label.getText() + "\n" + i);
  
              }
  
          });
  
          Platform.runLater(() -&gt; {
  
              ScrollBar s1 = (ScrollBar) code_line_counter.lookup(".scroll-bar:vertical");
              ScrollBar s2 = (ScrollBar) code_text_area.lookup(".scroll-bar:vertical");
              s2.valueProperty().bindBidirectional(s1.valueProperty());
  
          });
          }
  
      public boolean addFile (StackPane work_space, VBox welcome_screen, NotificationManager notification_manager)
      {    
          Tab new_tab = new Tab("Untitled " + (this.created_tabs + 1));
  
          try {
              FXMLLoader fxml_loader = new FXMLLoader(getClass().getResource("elements/code_workspace.fxml"));
              new_tab.setContent(fxml_loader.load());
          } catch (Exception e) {
              Notification fxml_load_error = new Notification("icons/notifications/default_warning.png");
              notification_manager.addNotification(fxml_load_error);
              return false;
          }
  
          new_tab.setOnClosed(event -&gt; {
              if (super.getTabs().isEmpty()) {
                  this.created_tabs = 0;
                  work_space.getChildren().clear();
                  work_space.getChildren().add(welcome_screen);
              }
          });
  
          super.getTabs().add(new_tab);
          super.getSelectionModel().select(new_tab);
          this.created_tabs++;
  
          return true;
      }
  
  }
  </code></pre>
  
  <p><strong>code_workspace.fxml</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  
  &lt;?import java.net.*?&gt;
  &lt;?import javafx.scene.control.*?&gt;
  &lt;?import javafx.scene.layout.*?&gt;
  
  &lt;VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.FileManager"&gt;
      &lt;children&gt;
          &lt;HBox minHeight="-Infinity" styleClass="search-bar" VBox.vgrow="NEVER" /&gt;
        &lt;HBox VBox.vgrow="ALWAYS"&gt;
           &lt;children&gt;
              &lt;ScrollPane id="code_line_counter" fx:id="code_line_counter" fitToWidth="true" focusTraversable="false" hbarPolicy="NEVER" minWidth="-Infinity" vbarPolicy="NEVER" HBox.hgrow="NEVER"&gt;
                 &lt;content&gt;
                    &lt;Label fx:id="code_line_counter_label" alignment="TOP_LEFT" focusTraversable="false" nodeOrientation="RIGHT_TO_LEFT" text="1" /&gt;
                 &lt;/content&gt;
              &lt;/ScrollPane&gt;
                &lt;TextArea fx:id="code_text_area" focusTraversable="false" promptText="Let's code!" HBox.hgrow="ALWAYS" /&gt;
           &lt;/children&gt;
        &lt;/HBox&gt;
      &lt;/children&gt;
     &lt;stylesheets&gt;
        &lt;URL value="@../styles/ezies_theme.css" /&gt;
        &lt;URL value="@../styles/sunis_styles.css" /&gt;
     &lt;/stylesheets&gt;
  &lt;/VBox&gt;
  </code></pre>
  
  <p>I tried a lot of moving with that code section:</p>
  
  <pre><code>ScrollBar s1 = (ScrollBar) code_line_counter.lookup(".scroll-bar:vertical");
              ScrollBar s2 = (ScrollBar) code_text_area.lookup(".scroll-bar:vertical");
              s2.valueProperty().bindBidirectional(s1.valueProperty());
  </code></pre>
  
  <p>But nothing help me. I tried also remove <code>Platform.runLater(() -&gt; {});</code>, but it also didn't help.</p>
  
  <p>Guys, what is the right solution of this problem, please?</p>
  
  <p><strong>*ADDITION:</strong>
  There is very interesting behavioral - when I add first tab, it runs normally, but when I am adding second or more tab into program collection, in about the 70% of cases took me the following exception:</p>
  
  <pre><code>Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
      at sample.FileManager.lambda$initialize$1(FileManager.java:75)
      at sample.FileManager$$Lambda$294/1491808102.run(Unknown Source)
      at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
      at com.sun.javafx.application.PlatformImpl$$Lambda$50/1472939626.run(Unknown Source)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
      at com.sun.javafx.application.PlatformImpl$$Lambda$49/1870453520.run(Unknown Source)
      at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
      at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
      at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
      at com.sun.glass.ui.win.WinApplication$$Lambda$38/123208387.run(Unknown Source)
      at java.lang.Thread.run(Thread.java:745)
  </code></pre>