'JavaFX: How to pan a ScrollPane that contains Button children?
In JavaFX, I have a ScrollPane
which contains a TilePane
which contains various Button
s.
This application will run on a touch screen, so the user will scroll by dragging the finger through the ScrollPane, but if the finger starts dragging over a child Button, then the ScrollPane doesn't scroll. Due to the way touch UIs work today, this is unexpected behavior for the user.
I want the buttons to respond to clicks, but I want the drag events to be sent to the underlying ScrollPane instead (if it pans using the drag events).
I've set the setPannable()
property of the ScrollPane
to true, and I've tried to set handlers on the Button
's various setOnDrag*()
methods to then fire the ScrollPane
's fireEvent()
method, but nothing happened.
Example:
button.setOnDragDone(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent event) {
scrollPane.fireEvent(event);
}
});
How should I go about doing this?
Solution 1:[1]
The problem for buttons is that the ButtonBehavior
registers a default mapping for MouseEvent.MOUSE_PRESSED
. This mapping consumes the event and the ScrollPane does not receive it anymore for panning calculation. In previous JFX versions it was possible to simply call ButtonSkin.consumeMouseEvents(false)
to fix that. With current versions this does not work anymore. I think this a bug and I might report it when I have time.
As a workaround I redirect the MouseEvent.MOUSE_PRESSED
to the viewPort
of the 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);
}
});
Edit: I reported the bug. Will post the link here when it is avaiable.
Solution 2:[2]
try this, consume
TouchEvent
on the ScrollPane
such as ...
ScrollPane.addEventHandler(TouchEvent.ANY, new EventHandler<TouchEvent>() {
@Override
public void handle(TouchEvent t) {
t.consume();
}
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Politic Revolutionnaire |