Synchronize Editor scrollbar with WebView scrollbar

Thangalin thangalin at gmail.com
Tue Jun 16 15:20:48 UTC 2020


Aloha List!

How would you synchronize the scrollbars for a StyleClassedTextArea
with a WebView instance, without using JavaScript?

Here's a code snippet that shows the overall objective:

public class ScrollSync extends Application {
  private final StyleClassedTextArea mEditor =
      new StyleClassedTextArea( false );
  private final VirtualizedScrollPane<StyleClassedTextArea> mEditorScrollPane =
      new VirtualizedScrollPane<>( mEditor );

  private final WebView mWebView = new WebView();
  private final String mHtml =
      "<!DOCTYPE html><html><body>%CONTENT%</body></html>";

  public static void main( final String[] args ) {
    launch( args );
  }

  @Override
  public void start( final Stage stage ) {
    mEditorScrollPane.setVbarPolicy( ScrollPane.ScrollBarPolicy.ALWAYS );

    mEditor.textProperty().addListener(
        ( observable, oldValue, newValue ) -> {
          mWebView.getEngine().loadContent(
              mHtml.replace( "%CONTENT%", newValue )
          );
        }
    );

    final SplitPane splitPane = new SplitPane(
        mEditorScrollPane,
        mWebView
    );

    stage.setScene( new Scene( splitPane, 800, 400 ) );
    stage.show();
  }
}

Using FlyingSaucer, JScrollPane, and a SwingNode:

private final Consumer<Double> mScrollEventObserver = o -> {
  final var eScrollPane = getActiveEditor().getScrollPane();
  final int eScrollY = eScrollPane
      .estimatedScrollYProperty().getValue().intValue();
  final int eHeight = (int) (eScrollPane
      .totalHeightEstimateProperty().getValue().intValue()
      - eScrollPane.getHeight());
  final double eRatio = eHeight > 0
      ? Math.min( Math.max( eScrollY / (float) eHeight, 0 ), 1 ) : 0;

  final var pPreviewPane = getPreviewPane();
  final var pScrollBar = pPreviewPane.getVerticalScrollBar();
  final var pHeight = pScrollBar.getMaximum() - pScrollBar.getHeight();
  final var pScrollY = (int) (pHeight * eRatio);
  final var pScrollPane = pPreviewPane.getScrollPane();

  final int oldScrollY = mScrollRatio.getAndSet( pScrollY );
  final int delta = Math.abs( oldScrollY - pScrollY );

  if( delta > 33 ) {
    // Prevent concurrent modification exceptions when attempting to
    // set the vertical scroll bar position.
    synchronized( mMutex ) {
      Platform.runLater( () -> {
        pScrollBar.setValue( pScrollY );
        pScrollPane.repaint();
      } );
    }
  }
};

The "delta > 33" is required because it appears the values for
estimatedScrollYProperty() and totalHeightEstimateProperty() are
unstable. (That is, they fluctuate when typing along the same row
within the text area.)

How would you get a reference to the WebView's vertical scroll bar?
I've tried using lookup( ".scroll-bar:vertical" ), but the object
wasn't responsive to changing the scroll bar position.

Thank you!


More information about the openjfx-discuss mailing list