gpt4 book ai didi

listview - 如何通过鼠标拖动在 JavaFX ListView 中选择多行

转载 作者:行者123 更新时间:2023-12-04 12:50:24 25 4
gpt4 key购买 nike

我是 JavaFX 的新手,我似乎无法找到如何做到这一点。

我在 Vbox 中有一个 ListView,我用字符串的 ObservableList 填充。我已将 ListView 的 SelectionMode 设置为 MULTIPLE,这允许我在按住 Ctrl 或 Shift 键的同时选择多个项目。

我希望能够单击一行并向下拖动鼠标并选择多行,但我不知道该怎么做。我尝试了几次搜索,似乎只找到拖放,这不是我需要的。

@FXML private ListView availableColumnList;

private ObservableList<String> availableColumns = FXCollections.<String>observableArrayList("One","Two","Three","Four");

availableColumnList.getItems().addAll(availableColumns);

availableColumnList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

最佳答案

如果您使用的是 JavaFX 10+,那么您可以扩展 ListViewSkin并在那里添加功能。您需要 JavaFX 10 或更高版本的原因是因为那时 VirtualContainerBase类,ListViewSkin扩展,有 getVirtualFlow() 添加的方法。然后您可以使用动画 API,例如 AnimationTimer , 滚动 ListView通过 VirtualFlow#scrollPixels(double) 方法。

下面是一个概念验证。它所做的只是自动滚动ListView当鼠标靠近 ListView 的顶部(或左侧)或底部(或右侧)时.当鼠标进入一个单元格时,该项目被选中(粗略地)。如果您想在开始向相反方向拖动鼠标时取消选择项目,那么您需要自己实现。您可能想要实现的另一件事是停止 AnimationTimer如果 ListView被隐藏或从场景中移除。

注:下面使用“完全按下-拖动-释放”手势。换句话说,有 MouseEvent 的混合体。处理程序和 MouseDragEvent处理程序。使用原因MouseDragEvent s 是因为它们可以传递到其他节点,而不仅仅是原始节点(与“简单的按下-拖动-释放”手势不同)。查看 this documentation了解更多信息。

Main.java

import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.stage.Stage;

public final class Main extends Application {

@Override
public void start(Stage primaryStage) {
var listView = IntStream.range(0, 1000)
.mapToObj(Integer::toString)
.collect(Collectors.collectingAndThen(
Collectors.toCollection(FXCollections::observableArrayList),
ListView::new
));
// Sets the custom skin. Can also be set via CSS.
listView.setSkin(new CustomListViewSkin<>(listView));
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
primaryStage.setScene(new Scene(listView, 600, 400));
primaryStage.show();
}

}

CustomListViewSkin.java
import javafx.animation.AnimationTimer;
import javafx.geometry.Rectangle2D;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.skin.ListViewSkin;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;

public class CustomListViewSkin<T> extends ListViewSkin<T> {

private static final double DISTANCE = 10;
private static final double PERCENTAGE = 0.05;

private AnimationTimer scrollAnimation = new AnimationTimer() {

@Override
public void handle(long now) {
if (direction == -1) {
getVirtualFlow().scrollPixels(-DISTANCE);
} else if (direction == 1) {
getVirtualFlow().scrollPixels(DISTANCE);
}
}

};

private Rectangle2D leftUpArea;
private Rectangle2D rightDownArea;

private int direction = 0;
private int anchorIndex = -1;

public CustomListViewSkin(final ListView<T> control) {
super(control);
final var flow = getVirtualFlow();
final var factory = flow.getCellFactory();

// decorate the actual cell factory
flow.setCellFactory(vf -> {
final var cell = factory.call(flow);

// handle drag start
cell.addEventHandler(MouseEvent.DRAG_DETECTED, event -> {
if (control.getSelectionModel().getSelectionMode() == SelectionMode.MULTIPLE) {
event.consume();
cell.startFullDrag();
anchorIndex = cell.getIndex();
}
});

// handle selecting items when the mouse-drag enters the cell
cell.addEventHandler(MouseDragEvent.MOUSE_DRAG_ENTERED, event -> {
event.consume();
if (event.getGestureSource() != cell) {
final var model = control.getSelectionModel();
if (anchorIndex < cell.getIndex()) {
model.selectRange(anchorIndex, cell.getIndex() + 1);
} else {
model.selectRange(cell.getIndex(), anchorIndex + 1);
}
}
});

return cell;
});

// handle the auto-scroll functionality
flow.addEventHandler(MouseDragEvent.MOUSE_DRAG_OVER, event -> {
event.consume();
if (leftUpArea.contains(event.getX(), event.getY())) {
direction = -1;
scrollAnimation.start();
} else if (rightDownArea.contains(event.getX(), event.getY())) {
direction = 1;
scrollAnimation.start();
} else {
direction = 0;
scrollAnimation.stop();
}
});

// stop the animation when the mouse exits the flow/list (desired?)
flow.addEventHandler(MouseDragEvent.MOUSE_DRAG_EXITED, event -> {
event.consume();
scrollAnimation.stop();
});

// handle stopping the animation and reset the state when the mouse
// is released. Added to VirtualFlow because it doesn't matter
// which cell receives the event.
flow.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> {
if (anchorIndex != -1) {
event.consume();
anchorIndex = -1;
scrollAnimation.stop();
}
});

updateAutoScrollAreas();
registerChangeListener(control.orientationProperty(), obs -> updateAutoScrollAreas());
registerChangeListener(flow.widthProperty(), obs -> updateAutoScrollAreas());
registerChangeListener(flow.heightProperty(), obs -> updateAutoScrollAreas());
}

// computes the regions where the mouse needs to be
// in order to start auto-scrolling. The regions depend
// on the orientation of the ListView.
private void updateAutoScrollAreas() {
final var flow = getVirtualFlow();
switch (getSkinnable().getOrientation()) {
case HORIZONTAL:
final double width = flow.getWidth() * PERCENTAGE;
leftUpArea = new Rectangle2D(0, 0, width, flow.getHeight());
rightDownArea = new Rectangle2D(flow.getWidth() - width, 0, width, flow.getHeight());
break;
case VERTICAL:
final double height = flow.getHeight() * PERCENTAGE;
leftUpArea = new Rectangle2D(0, 0, flow.getWidth(), height);
rightDownArea = new Rectangle2D(0, flow.getHeight() - height, flow.getWidth(), height);
break;
default:
throw new AssertionError();
}
}

@Override
public void dispose() {
unregisterChangeListeners(getSkinnable().orientationProperty());
unregisterChangeListeners(getVirtualFlow().widthProperty());
unregisterChangeListeners(getVirtualFlow().heightProperty());
super.dispose();

scrollAnimation.stop();
scrollAnimation = null;
}
}

注:mentioned by kleopatra ,至少其中一些功能更适合行为类。然而,为了简单起见,我决定只使用现有的公共(public)皮肤类(通过扩展它)。同样,以上只是概念验证。

关于listview - 如何通过鼠标拖动在 JavaFX ListView 中选择多行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57366020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com