JavaFX TreeView还原滚动状态

时间:2016-06-29 13:28:15

标签: java javafx scrollbar javafx-8

我想保存TreeView组件的当前滚动状态并随时恢复该状态。

我尝试了很多东西来获得滚动位置并将其设置回来,但无法以任何方式完成。

这里的关键点是我们需要保存min,max,value,unitInc,blockInc值并在需要时恢复这些值。只有值或仅最小值和最大值不足以正确恢复。

更新

聆听垂直值更改并存储滚动状态

Set<Node> nodes = this.treeView.lookupAll(".scroll-bar");
for (Node node : nodes) {
    ScrollBar scrollBar = getScrollBar(node);
    if (scrollBar.getOrientation() == Orientation.VERTICAL) {
        scrollBar.valueProperty().addListener((observable, oldValue, newValue) -> {
            double value = newValue.doubleValue();
            if (value > 0) {
                scrollState.setMin(scrollBar.getMin());
                scrollState.setMax(scrollBar.getMax());
                scrollState.setUnitIncrement(scrollBar.getUnitIncrement());
                scrollState.setBlockIncrement(scrollBar.getBlockIncrement());
                scrollState.setVerticalValue(value);
            }
        });
    }
}

此处还存储滚动状态

private ScrollBar getScrollBar(Node node) {
    ScrollBar scrollBar = (ScrollBar) node;
    if (Objects.nonNull(scrollBar)) {
        scrollState.setMin(scrollBar.getMin());
        scrollState.setMax(scrollBar.getMax());
        scrollState.setUnitIncrement(scrollBar.getUnitIncrement());
        scrollState.setBlockIncrement(scrollBar.getBlockIncrement());
    }

    return scrollBar;
}

恢复存储的滚动状态

threadService.schedule(() -> { // run after some ms, it is important
    threadService.runActionLater(() -> { // run in ui thread

        Set<Node> nodes = this.treeView.lookupAll(".scroll-bar");
        for (Node node : nodes) {
            ScrollBar scrollBar = getScrollBar(node);
            if (scrollBar.getOrientation() == Orientation.VERTICAL) {
                double verticalValue = scrollState.getVerticalValue();
                if (verticalValue > 0) {
                    scrollBar.setMin(scrollState.getMin());
                    scrollBar.setMax(scrollState.getMax());
                    scrollBar.setUnitIncrement(scrollState.getUnitIncrement());
                    scrollBar.setBlockIncrement(scrollState.getBlockIncrement());
                    scrollBar.setValue(verticalValue);
                }
            }
        }
    }, true);
}, 50, TimeUnit.MILLISECONDS);

2 个答案:

答案 0 :(得分:2)

如果您只想在TreeView滚动到索引,那么您可以使用scrollTo方法(例如,您保存所选索引,然后您滚动到这个指数后来):

tree.scrollTo(5);

如果您确实希望存储然后恢复ScrollBar的位置,则可以使用Node类的lookupAll方法要查找.scroll-bar样式,然后将其设置为ScrollBar对象,该对象具有要存储的minPropertymaxPropertyvalueProperty

更新:

根据OP的发现,ScrollBar的{​​{3}}和unitIncrementProperty也应该存储和恢复,以便正确支持该操作。

示例

在示例中,我填充了TreeView一些虚拟数据。它包含一个Button,用于将水平位置和垂直ScrollBar保存到成员对象中,该成员对象可以存储位置的min,max,value,blockIncrement和unitIncrement值。它还有一个Button来恢复上次保存的滚动条位置。

public class TreeViewSample extends Application {

    // Members to store the horizontal and vertical positions
    private ScrollBarState hScrollBarState = null;
    private ScrollBarState vScrollBarState = null;

    TreeView<String> tree;

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Tree View Sample with scrollbars");

        TreeItem<String> rootItem = new TreeItem<String>("Items");
        rootItem.setExpanded(true);
        for (int i = 1; i < 30; i++) {
            TreeItem<String> item = new TreeItem<String>("Long long long long long long long Item" + i);
            rootItem.getChildren().add(item);
        }

        tree = new TreeView<String>(rootItem);
        VBox root = new VBox();


        Button buttonSave = new Button("Save ScrollBars!");
        buttonSave.setOnAction((event) -> {
            // On save get the scrollbars and update the members (if the scrollbar is present)
            ScrollBar bar = getScrollBar(tree, Orientation.HORIZONTAL);
            if (bar != null)
                hScrollBarState = new ScrollBarState(bar.getMin(), bar.getMax(), bar.getValue(), bar.getBlockIncrement(), bar.getUnitIncrement());

            bar = getScrollBar(tree, Orientation.VERTICAL);

            if (bar != null)
                vScrollBarState = new ScrollBarState(bar.getMin(), bar.getMax(), bar.getValue(), bar.getBlockIncrement(), bar.getUnitIncrement());

        });

        Button buttonRestore = new Button("Restore ScrollBars!");
        buttonRestore.setOnAction((event) -> {

            restoreScrollBarPositions(getScrollBar(tree, Orientation.HORIZONTAL), hScrollBarState);
            restoreScrollBarPositions(getScrollBar(tree, Orientation.VERTICAL), vScrollBarState);
        });

        root.getChildren().addAll(tree, buttonSave, buttonRestore);

        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    private ScrollBar getScrollBar(TreeView<?> tree, Orientation orientation) {
        // Get the ScrollBar with the given Orientation using lookupAll
        for (Node n : tree.lookupAll(".scroll-bar")) {
            if (n instanceof ScrollBar) {
                ScrollBar bar = (ScrollBar) n;

                if (bar.getOrientation().equals(orientation))
                    return bar;
            }
        }
        return null;
    }

    private void restoreScrollBarPositions(ScrollBar bar, ScrollBarState state) {
        // Set back the position values if they present
        if (bar != null && state != null) {
            bar.setMin(state.min);
            bar.setMax(state.max);
            bar.setValue(state.value);
            bar.setUnitIncrement(state.unitIncrement);
            bar.setBlockIncrement(state.blockIncrement);
        }
    }

    // Simple class to store the position values
    class ScrollBarState {
        double min;
        double max;
        double value;
        double blockIncrement;
        double unitIncrement;

        ScrollBarState(double min, double max, double value, double blockInc, double unitInc) {
            this.min = min;
            this.max = max;
            this.value = value;
            this.blockIncrement = blockInc;
            this.unitIncrement = unitInc;
        }
    }
}

答案 1 :(得分:0)

这可能对某人有用。我基于DVarga的解决方案创建了一个友好的状态对象。这是使用TextArea。

public class ScrollBarState
{
  private final TextArea textArea;
  private final Orientation orientation;
  private ScrollBar scrollBar;

  private double min;
  private double max;
  private double value;
  private double blockIncrement;
  private double unitIncrement;

  // ---------------------------------------------------------------------------------//
  // constructor
  // ---------------------------------------------------------------------------------//

  public ScrollBarState (TextArea textArea, Orientation orientation)
  {
    this.textArea = textArea;
    this.orientation = orientation;
  }

  // ---------------------------------------------------------------------------------//
  // reset
  // ---------------------------------------------------------------------------------//

  public void reset ()
  {
    scrollBar = null;
  }

  // ---------------------------------------------------------------------------------//
  // save
  // ---------------------------------------------------------------------------------//

  public void save ()
  {
    if (scrollBar == null && !setScrollBar ())
      return;

    this.min = scrollBar.getMin ();
    this.max = scrollBar.getMax ();
    this.value = scrollBar.getValue ();
    this.blockIncrement = scrollBar.getBlockIncrement ();
    this.unitIncrement = scrollBar.getUnitIncrement ();
  }

  // ---------------------------------------------------------------------------------//
  // restore
  // ---------------------------------------------------------------------------------//

  public void restore ()
  {
    if (scrollBar == null)
      return;

    scrollBar.setMin (min);
    scrollBar.setMax (max);
    scrollBar.setValue (value);
    scrollBar.setUnitIncrement (unitIncrement);
    scrollBar.setBlockIncrement (blockIncrement);
  }

  // ---------------------------------------------------------------------------------//
  // setScrollBar
  // ---------------------------------------------------------------------------------//

  private boolean setScrollBar ()
  {
    for (Node node : textArea.lookupAll (".scroll-bar"))
      if (node instanceof ScrollBar
          && ((ScrollBar) node).getOrientation ().equals (orientation))
      {
        scrollBar = (ScrollBar) node;
        return true;
      }
    return false;
  }
}