JavaFX-ListView在滚动条中单击向下或向上时逐个滚动元素

JavaFX-ListView在滚动条中单击向下或向上时逐个滚动元素,listview,javafx,Listview,Javafx,我有一个包含16项的列表视图。当我使用箭头或默认ListView滚动条的鼠标滚动它时,它会滚动半个项目 我需要的是在单击箭头或鼠标滚动时滚动一个项目,这样列表就不会显示一半的项目。有没有办法做到这一点? 这是我的密码: public void start(Stage primaryStage) throws IOException { ListView<String> lstRequestOpt = new ListView<>(); List<St

我有一个包含16项的列表视图。当我使用箭头或默认ListView滚动条的鼠标滚动它时,它会滚动半个项目

我需要的是在单击箭头或鼠标滚动时滚动一个项目,这样列表就不会显示一半的项目。有没有办法做到这一点? 这是我的密码:

public void start(Stage primaryStage) throws IOException {
    ListView<String> lstRequestOpt = new ListView<>();
    List<String> x = new ArrayList<>();
    for(int i = 0; i < 30; i++) {
        x.add("item " + i);
    }
    ObservableList<String> items = FXCollections.observableArrayList(x);
    lstRequestOpt.setItems(items);
    Scene scene = new Scene(lstRequestOpt);
    primaryStage.setScene(scene);
    primaryStage.show();
}
以下是输出图像:

我在这里试图实现的是,元素显示完整,与图片不同:

滚动时 用鼠标移动滚动条时 单击滚动条中的箭头时 有没有办法做到这一点

更新:

我可以设法创建一个方法,在使用滚动或箭头时打印一些东西,即使是最小的滚动。现在我需要找到一种方法来设置滚动中的移动值,并将其与ListView集成。我会继续努力的。代码如下:

for (Node node : lstRequestOpt.lookupAll(".scroll-bar")) {
        if (node instanceof ScrollBar) {
            final ScrollBar bar = (ScrollBar) node;
            bar.valueProperty().addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> value, Number oldValue, Number newValue) {
                    if ((double) oldValue < (double) newValue) {
                        System.out.println("UP");
                    } else {
                        System.out.println("DOWN");
                    }
                }
            });
        }
    }
感谢所有帮助我的人。

试试这个:

  ListView listView = new ListView();
    listView.setItems(listConetnt);

    EventHandler onePositionScrollEvent = (EventHandler<ScrollEvent>) event -> {
        int scrollIndex = 0;

        if (event.getDeltaY() > 0) {
            scrollIndex = listView.getSelectionModel().getSelectedIndex() - 1;
        } else {
            scrollIndex = listView.getSelectionModel().getSelectedIndex() + 1;
        }

        listView.getSelectionModel().select(scrollIndex);
    };

    listView.setOnScroll(onePositionScrollEvent);

我有一个非常讨厌的方法。不确定这是否适合你。但最终的意图是不要一个接一个地滚动px

其思想是监听垂直滚动条的value属性,并根据当前滚动条的值设置ListView滚动。下面的方法可以为您提供一些输入。一个缺点是我需要依赖VirtualFlow

import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.AccessibleAttribute;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

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

public class ListViewScrollDemo  extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        StackPane root = new StackPane();
        Scene sc = new Scene(root, 600, 200);
        stage.setScene(sc);
        stage.show();
        List<String> items = new ArrayList<>();
        for (int i = 1; i < 21; i++) {
            items.add("Item "+i);
        }
        ObservableList<String> itemList = FXCollections.observableArrayList();
        itemList.addAll(items);
        ScrollListView<String> list = new ScrollListView<>();
        list.setItems(itemList);
        root.getChildren().add(list);
    }

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

    class ScrollListView<T> extends ListView<T>{
        boolean firstRender = false;
        public ScrollListView() {
            needsLayoutProperty().addListener((obs,old,needsLayout)->{
                if(!firstRender && !needsLayout){
                    firstRender = true;
                    VirtualFlow<?> virtualFlow = (VirtualFlow<?>) lookup(".virtual-flow");

                    // Keeping vertical scrollBar node reference and tweaking the vertical scroll bar behavior to
                    // scroll by row and not by pixel.
                    ScrollBar vScrollBar = (ScrollBar) queryAccessibleAttribute(AccessibleAttribute.VERTICAL_SCROLLBAR);
                    vScrollBar.valueProperty().addListener((obs1, oldVal1, newVal) -> {
                        int visibleRowCount = virtualFlow.getLastVisibleCell().getIndex()-virtualFlow.getFirstVisibleCell().getIndex();
                        final double scrollVal = newVal.doubleValue();
                        final int size = getItems().size();
                        if (scrollVal < 1.0) {
                            final int virtualRowCount = size - visibleRowCount;
                            final double eachRowBuff = 1d / virtualRowCount;
                            for (int index = 0; index < virtualRowCount; index++) {
                                final double start = eachRowBuff * index;
                                final double end = start + eachRowBuff;
                                if (start <= scrollVal && scrollVal < end) {
                                    scrollTo(index);
                                    vScrollBar.setValue(start);
                                    break;
                                }
                            }
                        } else {
                            scrollTo(size - 1);
                        }
                    });
                }
            });
        }
    }
}

这真的很好。但是,当我滚动时,我需要在滚动时保留上一次选择,并且您的评论方式会在滚动时选择一个选项。如果滚动很小,滚动事件也不会触发,这在我的情况下很重要。无论如何,谢谢你。我不确定你是否理解。。。是否要按一个元素滚动列表而不更改选择?是。当滚动时,我唯一感兴趣的是看到元素完整,而不是被减半,但不改变选择。请提供一个例子来说明问题。也就是说:基本上,您可以查找滚动条并将其单位增量设置为nice try+1:-但不可靠至少在fx11:a中不可靠在这个确切的示例中,由于舞台的固定大小,有半行,而不是让场景在其pref.b处出现,其中包含更多项,例如100和pref initial,一切似乎都按预期进行。。。C只有一段时间:有虚假的人工制品f.i.当点击滚动条向上箭头向上滚动时,第一行看起来上面有一些空白-这可能是内部状态混乱和细胞重复使用不完整的结果,但问题太模糊了。@kleopatra,谢谢你的反馈。是的,我也意识到这种方法存在一些问题。因为我使用它的背景是一个完全不同的固定可见行数、固定桌子高度等,它完全适合我的目的。我认为,给出我的意见可能有助于提问者朝着这个方向思考,从而找到更好的解决方案。