2017-06-06 57 views
1

我在Scrollpane中有很多VBox中的Textfields。当滚动和触摸文本框时,它只是抓住焦点。所以平滑滚动是不可能的。我怎么能很好地滚动,没有任何文本域的不必要的焦点。我是否需要在滚动时消耗文本字段上的事件?在VBox上滚动很多Textfields

回答

0

这里是我使用为目的的一类你描述:

public class MouseClickedFilter{ 

    private final Node      observableNode; 

    private BooleanProperty     scrolling   = new ReadOnlyBooleanWrapper(false); 

    private EventHandler<? super MouseEvent> dragDetectedFilter = e -> scrolling.set(true); 
    private EventHandler<? super MouseEvent> mouseExitedHandler = e -> scrolling.set(false); 

    private EventHandler<? super MouseEvent> mouseClickedFilter = evt -> 
                    { 
                     if (scrolling.get()) { 
                      evt.consume(); 
                      scrolling.set(false); 
                     } 
                    }; 

    private boolean       listenersEnabled; 

    public MouseClickedFilter(Node observableNode) { 
     this.observableNode = observableNode; 
    } 

    public void activate() { 
     if (!listenersEnabled) { 
      observableNode.addEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter); 
      observableNode.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); 
      observableNode.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter); 
     } 
    } 

    public void deactivate() { 
     if (listenersEnabled) { 
      observableNode.removeEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter); 
      observableNode.removeEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler); 
      observableNode.removeEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter); 
     } 
    } 

    public final ReadOnlyBooleanProperty scrollingProperty() { 
     return scrolling; 
    } 

    public final boolean isScrolling() { 
     return scrolling.get(); 
    } 

} 

ObservableNode是包含文本框

+0

感谢您的代码,但它没有帮助。滚动仍然卡住并显示TextFields。 – tonimaroni

+0

是滚动是斯图尔特。这似乎是Android上的ScrollPane与javafxport结合使用的一个基本问题,无论ScrollPane中使用的节点如何。 – jns

0

这是情况下,你要在滚动一个可能的解决方案您ScrollPane长长的文本框列表,不让它们占据焦点,直到完全停止滚动,并且显然希望选择其中一个文本框。

它基于一个自定义的“按住”事件,受此启发question

想法是将HBOX中的TextField控件捆绑在一起,并禁用使用容器的鼠标透明属性访问控件。

然后,无论何时点击容器,如果按足够长的时间,容器就可以访问控制器,键盘将显示出来。否则,您将继续滚动,但不显示键盘。

我将仅在iOS上使用此question中提及的KeyboardService

public class BasicView extends View { 

    public BasicView(String name) { 
     super(name); 

     setTop(new Button("Button")); 

     VBox controls = new VBox(15.0); 

     controls.setAlignment(Pos.CENTER); 

     ScrollPane pane = new ScrollPane(controls); 
     controls.prefWidthProperty().bind(pane.widthProperty().subtract(20)); 

     for (int i = 0; i < 100; i++) { 
      final Label label = new Label("TextField " + (i + 1)); 
      final TextField textField1 = new TextField(); 
      HBox.setHgrow(textField1, Priority.ALWAYS); 
      HBox box = new HBox(10, label, textField1); 
      box.setMouseTransparent(true); 

      box.setAlignment(Pos.CENTER_LEFT); 
      box.setPadding(new Insets(5)); 
      controls.getChildren().add(box); 
     } 

     addPressAndHoldHandler(controls, Duration.millis(300), eStart -> { 
       for (Node box : controls.getChildren()) { 
        box.setMouseTransparent(true); 
       } 
      }, eEnd -> { 
       for (Node box : controls.getChildren()) { 
        if (box.localToScene(box.getBoundsInLocal()).contains(eEnd.getSceneX(), eEnd.getSceneY())) { 
         box.setMouseTransparent(false); 
         ((HBox) box).getChildren().get(1).requestFocus(); 
         break; 
        } 
       } 
      }); 
     setCenter(pane); 

     // iOS only 
     Services.get(KeyboardService.class).ifPresent(keyboard -> { 
      keyboard.visibleHeightProperty().addListener((obs, ov, nv) -> { 
       if (nv.doubleValue() > 0) { 
        for (Node box : controls.getChildren()) { 
         Node n1 = ((HBox) box).getChildren().get(1); 
         if (n1.isFocused()) { 
          double h = getScene().getHeight() - n1.localToScene(n1.getBoundsInLocal()).getMaxY(); 
          setTranslateY(-nv.doubleValue() + h); 
          break; 
         } 
        } 
       } else { 
        setTranslateY(0); 
       } 
      }); 
     }); 
    } 

    @Override 
    protected void updateAppBar(AppBar appBar) { 
     appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu"))); 
     appBar.setTitleText("Scrolling over TextFields"); 
    } 

    private void addPressAndHoldHandler(Node node, Duration holdTime, 
      EventHandler<MouseEvent> handlerStart, EventHandler<MouseEvent> handlerEnd) { 
     class Wrapper<T> { 
      T content; 
     } 

     Wrapper<MouseEvent> eventWrapper = new Wrapper<>(); 

     PauseTransition holdTimer = new PauseTransition(holdTime); 
     holdTimer.setOnFinished(event -> handlerEnd.handle(eventWrapper.content)); 

     node.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> { 
      handlerStart.handle(event); 
      eventWrapper.content = event; 
      holdTimer.playFromStart(); 
     }); 
     node.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> holdTimer.stop()); 
     node.addEventHandler(MouseEvent.DRAG_DETECTED, event -> holdTimer.stop()); 
    } 
} 

请注意,当您显示视图时,我已在顶部添加了一个按钮以使焦点位于第一位。

每当您点击/点击controls VBox时,它会将所有框设置为透明:box.setMouseTransparent(true);,并启动PauseTransition

如果在300毫秒之前有鼠标释放或鼠标拖动(这可以在您方便时更改),则转换将停止。否则,在300 ms后,它会将框设置为box.setMouseTransparent(false);,并将焦点设置在TextField上,此时键盘将显示出来。