Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Issues synchronizing 2 TreeViews via their scrollbar.valueProperty().bindBidirectional()

User_Q7KIIDec 12 2022

Hi All,
Wondering if anyone has experienced the following issue and looking for any possible workarounds for it.
The problem seems to have been introduced in version 17 (version 16 seems to be working fine) and it happens with 2 TreeViews (that share the same content/root) are synchronized via their corresponding scrollbars valueProperty().bindBidirectional.
Things work fine if the scrollbar is at the very top (value = 0), as soon as you scroll down and expand or collapse any items, the content of the 2 TreeViews gets out of sync (same content will be displayed in different lines).
The issue corrects itself when scroll again up/down, selecting a different row or the application loses focus.
See small code sample below that shows the issue.
Any help would be appreciated.
Thanks,
Pablo.

package javafx.test;

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TreeViewSyncScrollingSample extends Application {
	
	private static final int CHILDREN_PER_LEVEL = 5;
	private static final int NUMBER_OF_LEVELS = 3;
	
	public static void main(String[] args) {
		Application.launch(args);
	}

	@Override
	public void start(Stage stage) {

		final String version = String.format("Java: %s, JavaFX: %s",
				System.getProperty("java.runtime.version"), System.getProperty("javafx.version"));
		stage.setTitle(version);
		final Scene scene = new Scene(new Group(), 500, 400);
		Group sceneRoot = (Group) scene.getRoot();

		final TreeItem<String> root = createRootNode();
		final TreeView<String> treeView1 = new TreeView<>(root);

		// treetable 2
		final TreeView<String> treeView2 = new TreeView<>(root);
		
		// create the layout and start
		final HBox hbox = new HBox(treeView1, treeView2);
		sceneRoot.getChildren().add(hbox);
		stage.setScene(scene);
		stage.show();

		final ScrollBar scrollBar1 = findVerticalScrollBar(treeView1);
		final ScrollBar scrollBar2 = findVerticalScrollBar(treeView2);
		scrollBar1.valueProperty().bindBidirectional(scrollBar2.valueProperty());
	}
	
  private ScrollBar findVerticalScrollBar(Parent table) {
    return (ScrollBar)table.lookup(".scroll-bar:vertical");
  }
   
  private List<TreeItem<String>> createChildren(int level, String idPrefix) {
  	if (level == NUMBER_OF_LEVELS) {
  		return null;
  	}
		final List<TreeItem<String>> thisLevelChildren = new ArrayList<>();
		for (int i = 0; i < CHILDREN_PER_LEVEL; i++) {
			final String id = String.format("%s%s", idPrefix, i);
			final TreeItem<String> child = new TreeItem<>(String.format("Child %s", id));
			final List<TreeItem<String>> nextLevelChildren = createChildren(level+1, id);
			if (nextLevelChildren != null) {
				child.setExpanded(true);
				child.getChildren().setAll(nextLevelChildren);
			}
			thisLevelChildren.add(child);
		}
		return thisLevelChildren;
  }
   
  private TreeItem<String> createRootNode() {

  	final TreeItem<String> root = new TreeItem<>("Root");
  	final List<TreeItem<String>> childNodes = createChildren(0, "");
		root.setExpanded(true);
		root.getChildren().setAll(childNodes);
		return root;
  }
}
Comments
Post Details
Added on Dec 12 2022
1 comment
171 views