JavaFX:如何平移包含 Button 子项的 ScrollPane?

问题描述 投票:0回答:3

在 JavaFX 中,我有一个

ScrollPane
,其中包含一个
TilePane
,其中包含各种
Button

此应用程序将在触摸屏上运行,因此用户将通过在 ScrollPane 中拖动手指来滚动,但如果手指开始在子 Button 上拖动,则 ScrollPane 不会滚动。由于当今触摸 UI 的工作方式,这对用户来说是意想不到的行为。

我希望按钮响应单击,但我希望将拖动事件发送到底层 ScrollPane(如果它使用拖动事件进行平移)。

我已将

setPannable()
ScrollPane
属性设置为 true,并且我尝试在
Button
的各种
setOnDrag*()
方法上设置处理程序,然后触发
ScrollPane
fireEvent()
方法,但什么也没发生。

示例:

    button.setOnDragDone(new EventHandler<DragEvent>() {
        @Override
        public void handle(DragEvent event) {
            scrollPane.fireEvent(event);
        }
    });

我该怎么做?

javafx touch mouseevent javafx-8
3个回答
0
投票

按钮的问题是

ButtonBehavior
MouseEvent.MOUSE_PRESSED
注册了默认映射。此映射会消耗该事件,并且 ScrollPane 不再接收该事件以进行平移计算。在以前的 JFX 版本中,可以简单地调用
ButtonSkin.consumeMouseEvents(false)
来解决这个问题。对于当前版本,这不再起作用。我认为这是一个错误,当我有时间时我可能会报告它。

作为解决方法,我将

MouseEvent.MOUSE_PRESSED
重定向到
viewPort
ScrollPane

   ScrollPane pane = new ScrollPane(bar)
    {
      @Override
      protected Skin<?> createDefaultSkin()
      {
        Skin<?> skin = super.createDefaultSkin();
        for (Node ch : getChildren())
        {
          if (ch.getStyleClass().contains("viewport"))
            viewPort = ch;
        }
        return skin;
      }
    };
    pane.addEventFilter(MouseEvent.MOUSE_PRESSED, e ->
    {
      if (lastFiredEvent != e)
      {
        lastFiredEvent = e.copyFor(e.getSource(), viewPort);
        viewPort.fireEvent(lastFiredEvent);
      }
    });

编辑:我报告了该错误。当链接可用时,将在此处发布链接。

https://bugs.openjdk.java.net/browse/JDK-8284878


0
投票

我也遇到过这种情况。我通过从 Label 扩展并实现 Toggle 接口编写了一个 PannableToggle 类,也许有一个可选择的伪状态接口?然而..

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleGroup;
import javafx.scene.input.MouseEvent;

public class PannableToggle extends Label implements javafx.scene.control.Toggle {
    private final ObjectProperty<ToggleGroup> toggleGroup = new SimpleObjectProperty<>();
    private final BooleanProperty             selected    = new SimpleBooleanProperty(false);


    public PannableToggle() { this(null); }


    public PannableToggle(String text) {
        super(text);
        updateStyle();
        setOnMouseClicked(this::handleMouseClicked);
    }


    private void handleMouseClicked(MouseEvent event) {
        if (!isSelected() && getToggleGroup() != null) {
            getToggleGroup().selectToggle(this);
        }
    }


    @Override
    public void setSelected(boolean selected) {
        if (this.selected.get() != selected) {
            this.selected.set(selected);
            updateStyle();
        }
    }


    @Override
    public boolean isSelected() { return selected.get(); }


    @Override
    public ToggleGroup getToggleGroup() { return toggleGroup.get(); }


    @Override
    public void setToggleGroup(ToggleGroup group) {
        this.toggleGroup.set(group);
        if (group != null) {
            group.getToggles().add(this);
        }
    }


    @Override
    public ObjectProperty<ToggleGroup> toggleGroupProperty() { return toggleGroup; }


    @Override
    public BooleanProperty selectedProperty() { return selected; }


    private void updateStyle() {
        String style = isSelected() ? " -fx-underline: true;"
            : null;
        
        setStyle(style);
    }


    // Fluent API for setting text
    public PannableToggle withText(String text) {
        setText(text);
        return this;
    }


    // Fluent API for setting toggle group
    public PannableToggle withToggleGroup(ToggleGroup group) {
        setToggleGroup(group);
        return this;
    }
}

-1
投票

试试这个,

consume
TouchEvent
ScrollPane
例如...

ScrollPane.addEventHandler(TouchEvent.ANY, new EventHandler<TouchEvent>() {
        @Override
        public void handle(TouchEvent t) { 
            t.consume();
        }
    });     
© www.soinside.com 2019 - 2024. All rights reserved.