滚动显示上的JavaFX ListView

滚动显示上的JavaFX ListView,java,listview,javafx,scrollbar,Java,Listview,Javafx,Scrollbar,我在想,是否有一个属性,我可以附加一个侦听器,它表示“当列表视图开始显示滚动条时”的操作 问题是,我有一个到ListView的输出,在某个点上ListView的滚动条会触发。我想捕获该事件并滚动到底部,以便ListView对象的下一个添加项将自动滚动到底部 我知道我可能会使用侦听器来更改项目,但我希望在决定向上滚动时保留该行为,并且在添加项目后它不会立即回滚到最后一个位置。也许这可以帮助您: private boolean scroll = true; private ListView&

我在想,是否有一个属性,我可以附加一个侦听器,它表示“当列表视图开始显示滚动条时”的操作

问题是,我有一个到ListView的输出,在某个点上ListView的滚动条会触发。我想捕获该事件并滚动到底部,以便ListView对象的下一个添加项将自动滚动到底部


我知道我可能会使用侦听器来更改项目,但我希望在决定向上滚动时保留该行为,并且在添加项目后它不会立即回滚到最后一个位置。

也许这可以帮助您:

  private boolean scroll = true;
  private ListView<String> listView = new ListView<>();

  Constructor(){
    outputListView.addEventFilter(ScrollEvent.ANY, (e) ->{ //get every scroll event
      if(e.getTextDeltaY() > 0){ //set Scroll event to false when the user scrolls up
        scroll = false;
      }
    });
  }

  public void addToListView(String s){
    listView.getItems().add(s);
    if(scroll)
        listView.scrollTo(listView.getItems().size() -1 );
  }
private boolean scroll=true;
私有ListView ListView=新建ListView();
构造函数(){
outputListView.addEventFilter(ScrollEvent.ANY,(e)->{//获取每个滚动事件
如果(e.getTextDeltaY()>0){//当用户向上滚动时,将滚动事件设置为false
滚动=假;
}
});
}
public void addToListView(字符串s){
listView.getItems().add;
如果(滚动)
scrollTo(listView.getItems().size()-1);
}
在这种情况下,当滚动条显示时,listView向下滚动,但当用户向上滚动时,listView不再向下滚动,直到用户在listView底部滚动(这是一种标准listView行为)

尝试以下操作:

for (Node node : listView.lookupAll(".scroll-bar")) {
    if (node instanceof ScrollBar) {
        ScrollBar scrollBar = (ScrollBar) node;
        scrollBar.visibleProperty().addListener((observable, oldValue, newValue) -> {
            System.out.println(String.format("%s ScrollBar Visible Property Changed From: %s To: %s", scrollBar.getOrientation(), oldValue, newValue));
        });
    }
}
输出:

垂直滚动条可见属性已从:false更改为:true


注意:此代码应该在您在
列表视图中设置项目后添加
以避免
NullPointerException

就个人而言,我并不热衷于CSS查找方法,因为我觉得它太像黑客了(我不喜欢依赖硬编码的属性查找)

我喜欢做的是在物理布局树中搜索具有正确方向的滚动条:

    public static Optional<ScrollBar> getScrollbar(Node n, Orientation o) {
        LinkedList<Node> queue = new LinkedList<>();
        queue.add(n);
        
        while(! queue.isEmpty()) {
            n = queue.removeFirst();
            
            if (n instanceof ScrollBar) {
                ScrollBar sb = (ScrollBar)n;
                
                if (sb.getOrientation() == o) {
                    return Optional.of(sb);
                }
            }
            
            if (n instanceof Parent) {
                queue.addAll(((Parent) n).getChildrenUnmodifiable());
            }
        }
        
        return Optional.empty();
    }
public静态可选getScrollbar(节点n,方向o){
LinkedList队列=新建LinkedList();
添加(n);
而(!queue.isEmpty()){
n=queue.removeFirst();
如果(滚动条的n个实例){
滚动条sb=(滚动条)n;
如果(sb.getOrientation()==o){
(某人)的返回;
}
}
if(父级的n个实例){
queue.addAll(((父)n.getChildrenUnmodifiable());
}
}
返回可选的.empty();
}
例如,如果我将浮动按钮锚定到列表视图的右上角,当列表视图的布局边界属性更改时,我将执行以下操作:

    Optional<ScrollBar> sb = getScrollbar(listView, Orientation.VERTICAL);
        
    if (sb.isPresent() && sb.get().isVisible()) {
        StackPane.setMargin(hoverButton, new Insets(1, sb.get().getWidth(), 0, 0));
    }
    else {
        StackPane.setMargin(hoverButton, new Insets(1, 1, 0, 0));
    }
可选sb=getScrollbar(listView,Orientation.VERTICAL);
如果(sb.isPresent()&&sb.get().isVisible()){
setMargin(悬停按钮,新的插入(1,sb.get().getWidth(),0,0));
}
否则{
setMargin(悬停按钮,新的插入(1,1,0,0));
}

这将使我的按钮快速移动,使其不会悬停在滚动条上。

当滚动条显示您可能正在更改我假定的已存在对象的可见性时?在这种情况下,您可以监听滚动条的可见标志。但我从未尝试过此方法,因此我不能保证此方法有效,但它可能是一种值得尝试的方法。是的,但我在ListView中找不到侦听此标志的点。此标志更改没有现有事件,因此您需要创建自己的事件。您可以查看自定义活动的介绍。谢谢!对JavaFX还是新手,不知道你可以制作自己的事件。但是。。。即使触发自定义事件也需要触发器。“关注什么”的问题仍然存在。谢谢,但我只想在显示滚动条的活动中滚动到底,保留原来的滚动行为和挂钩。有趣。谢谢,我试试。谢谢。“lookupAll”看起来很有趣。我会试试的。是的,我成功了。由于我的列表是动态的,并且不是从一开始就加载的,所以为条目更改附加了一个侦听器,以便发现滚动条。非常感谢。