当用户将某些内容拖到其边缘时,我希望向上或向下滚动ScrollPane
。 ScrollPane
内部会有一个VBox
,也会在VBox
内。
我认为我需要在setOnDragExited
中添加一些东西。但具体到底是什么?
这是一个例子的最小程序:
package application;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
VBox outerBox = new VBox();
outerBox.setMaxSize(700, 300);
root.setCenter(outerBox);
Label outerLabel = new Label("I am outside!");
ScrollPane sp = new ScrollPane();
outerBox.getChildren().addAll(outerLabel,sp);
VBox innerBox = new VBox();
//setting size bigger than ScrollPane's view.
innerBox.setPrefSize(600, 600);
sp.setContent(innerBox);
Label dragMe = new Label("Drag me to the edge of scroll pane! \n"+"or drop me in the scrollpane!");
root.setTop(dragMe);
dragMe.setOnDragDetected((MouseEvent event) ->{
Dragboard db = dragMe.startDragAndDrop(TransferMode.ANY);
db.setDragView(((Node) event.getSource()).snapshot(null, null));
ClipboardContent content = new ClipboardContent();
content.putString((dragMe.getText()));
db.setContent(content);
event.consume();
});
sp.setOnDragOver((DragEvent event) ->{
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
});
sp.setOnDragEntered((DragEvent event) -> {
});
sp.setOnDragExited((DragEvent event) -> {
System.out.println("-----Make the scrollpane scroll up or down depending on exiting on bottem or top------");
event.consume();
});
sp.setOnDragDropped((DragEvent event) ->{
Dragboard db = event.getDragboard();
System.out.println(((VBox) sp.getContent()).getChildren().add(new Label(db.getString())));
});
Scene scene = new Scene(root,1000,1000);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
答案 0 :(得分:2)
在这里找到了这个答案: Want to trigger scroll when dragging node outside the visible area in ScrollPane
没有完全回答并且没有使用ScrollPane
因此我认为我将我的工作/发现作为答案发布。
我发现你可以通过制作动画来实现这一目标:
private Timeline scrolltimeline = new Timeline();
....
scrolltimeline.setCycleCount(Timeline.INDEFINITE);
scrolltimeline.getKeyFrames()
.add(new KeyFrame(Duration.millis(20), (ActionEvent) -> { dragScroll();}));
<强>最小强>
package application;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private ScrollPane sp;
private Timeline scrolltimeline = new Timeline();
private double scrollVelocity = 0;
boolean dropped;
//Higher speed value = slower scroll.
int speed = 200;
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
sp = new ScrollPane();
sp.setPrefSize(300, 300);
VBox outer = new VBox(sp);
VBox innerBox = new VBox();
innerBox.setPrefSize(200,1000);
sp.setContent(innerBox);
root.setCenter(outer);
Label dragMe = new Label("drag me to edge!\n"+"or drop me in scrollpane!");
root.setTop(dragMe);
setupScrolling();
dragMe.setOnDragDetected((MouseEvent event) ->{
Dragboard db = dragMe.startDragAndDrop(TransferMode.ANY);
db.setDragView(((Node) event.getSource()).snapshot(null, null));
ClipboardContent content = new ClipboardContent();
content.putString((dragMe.getText()));
db.setContent(content);
event.consume();
});
Scene scene = new Scene(root, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
}
private void setupScrolling() {
scrolltimeline.setCycleCount(Timeline.INDEFINITE);
scrolltimeline.getKeyFrames().add(new KeyFrame(Duration.millis(20), (ActionEvent) -> { dragScroll();}));
sp.setOnDragExited((DragEvent event) -> {
if (event.getY() > 0) {
scrollVelocity = 1.0 / speed;
}
else {
scrollVelocity = -1.0 / speed;
}
if (!dropped){
scrolltimeline.play();
}
});
sp.setOnDragEntered(event -> {
scrolltimeline.stop();
dropped = false;
});
sp.setOnDragDone(event -> {
System.out.print("test");
scrolltimeline.stop();
});
sp.setOnDragDropped((DragEvent event) ->{
Dragboard db = event.getDragboard();
((VBox) sp.getContent()).getChildren().add(new Label(db.getString()));
scrolltimeline.stop();
event.setDropCompleted(true);
dropped = true;
});
sp.setOnDragOver((DragEvent event) ->{
event.acceptTransferModes(TransferMode.MOVE);
});
sp.setOnScroll((ScrollEvent event)-> {
scrolltimeline.stop();
});
sp.setOnMouseClicked((MouseEvent)->{
System.out.println(scrolltimeline.getStatus());
});
}
private void dragScroll() {
ScrollBar sb = getVerticalScrollbar();
if (sb != null) {
double newValue = sb.getValue() + scrollVelocity;
newValue = Math.min(newValue, 1.0);
newValue = Math.max(newValue, 0.0);
sb.setValue(newValue);
}
}
private ScrollBar getVerticalScrollbar() {
ScrollBar result = null;
for (Node n : sp.lookupAll(".scroll-bar")) {
if (n instanceof ScrollBar) {
ScrollBar bar = (ScrollBar) n;
if (bar.getOrientation().equals(Orientation.VERTICAL)) {
result = bar;
}
}
}
return result;
}
public static void main(String[] args) {
launch(args);
}
}
答案 1 :(得分:1)
JavaFX-8没有公共API将ScrollPane滚动到某个位置(https://bugs.openjdk.java.net/browse/JDK-8102126)并投票以获得此类API。
滚动到Java8中的某个位置(将在Java9中断!)的黑客攻击是获取ScrollPaneSkin类型的ScrollPane的外观并在那里调用onTraverse方法。