2017-06-06 31 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上,此時鍵盤將顯示出來。