I'm created the following example containing a ListView
with a registered scroll event listener. Unfortunately the listener does only fire when scrolling via mouse wheel, but not when using the scrollbar on the side. Whats is wrong with the code?
Controller.java
package sample;
import java.net.URL;
import java.util.Arrays;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
public class Controller implements Initializable {
@FXML
private ListView lstPreview;
private ObservableList items = FXCollections.observableArrayList();
public Controller() {
}
@Override
public void initialize(URL location, ResourceBundle resources) {
items.addAll(Arrays.asList("Test 1", "Test 2", "Test 3", "Test 4", "Test 5", "Test 6", "Test 7", "Test 8", "Test 9", "Test 10"));
lstPreview.setItems(items);
lstPreview.addEventFilter(javafx.scene.input.ScrollEvent.ANY, event -> { System.out.println("ScrollEvent!"); });
lstPreview.addEventFilter(javafx.scene.control.ScrollToEvent.ANY, event -> { System.out.println("ScrollToEvent!"); });
}
}
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
sample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import java.net.URL?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<stylesheets>
<URL value="@style.css" />
</stylesheets>
<columnConstraints>
<ColumnConstraints />
<ColumnConstraints hgrow="ALWAYS" />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints vgrow="ALWAYS" />
</rowConstraints>
<children>
<ListView fx:id="lstPreview" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.vgrow="ALWAYS" />
</children>
</GridPane>
Solution
I ended up using @Uluk Biy solution, maybe one day the Java 8 JDK gets a function like this:
/**
* Looks up the first found scrollbar of a given control matching the desired orientation. If none found, null is returned
*
* @param control
* @param orientation
* @return
*/
public static javafx.scene.control.ScrollBar getScrollbarComponent(javafx.scene.control.Control control, javafx.geometry.Orientation orientation) {
javafx.scene.Node n = control.lookup(".scroll-bar");
if (n instanceof javafx.scene.control.ScrollBar) {
final javafx.scene.control.ScrollBar bar = (javafx.scene.control.ScrollBar) n;
if (bar.getOrientation().equals(orientation)) {
return bar;
}
}
return null;
}
Using it like this:
javafx.scene.control.ScrollBar timelineBar = de.elara.asgard.util.FxUtils.getScrollbarComponent(listTimeline, javafx.geometry.Orientation.HORIZONTAL);
if (timelineBar != null) {
timelineBar.addEventFilter(ScrollToEvent.ANY, event -> { doScrollingTimeline(); });
}
According to the Documentation:
Scroll event indicates that user performed scrolling by mouse wheel, track pad, touch screen or other similar device.
So it has nothing to do with the ScrollBar
s of the ListView
. As they are implementation detail it is not so easy to acces them, besides doing some reflection tricks.