2017-01-20 24 views
0

Я хотел бы иметь прокрутку вверх или вниз, когда пользователь перетаскивает что-то к краю. У ScrollPane будет VBox внутри него и будет внутри VBox.Scroll ScrollPane вниз или вверх при перетаскивании в него элемента.

Предполагаю, что мне нужно что-то положить в 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

этот ответ здесь: 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();})); 

Minimal:

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); 
    } 

} 
0

JavaFX-8 не имеет публичного API для прокрутки ScrollPane в определенном положении (https://bugs.openjdk.java.net/browse/JDK-8102126) и проголосуйте, чтобы получить такой API в

Ручка для прокрутки до определенной позиции в Java8 (кто сломается в Java9!) - это получить Кожа ScrollPane, который имеет тип ScrollPaneSkin и вызвать метод onTraverse.

+0

не уверен, если я нашел другой путь, но я не думаю, что я называю onTraverse –