我创建了以下示例,其中包含带有已注册滚动事件侦听器的ListView
。不幸的是,听众只在通过鼠标滚轮滚动时才会触发,但在侧面使用滚动条时则不会触发。代码有什么问题?
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>
解决方案
我最终使用了@Uluk Biy解决方案,也许有一天Java 8 JDK获得了这样的功能:
/**
* 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;
}
像这样使用它:
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(); });
}
答案 0 :(得分:1)
滚动事件表示用户通过鼠标滚轮滚动, 触控板,触摸屏或其他类似设备。
因此它与ScrollBar
的{{1}}无关。因为它们是实现细节,所以除了做一些反射技巧之外,访问它们并不容易。
答案 1 :(得分:0)
这是一种简单的方法,可以不做任何反射技巧:
首先,您应该实现自己的ListViewSkin扩展,比如CustomListViewSkin
。稍后将使用.setSkin方法在列表视图上设置外观。 (您可以扩展ListView并覆盖createDefaultSkin方法,以使您的自定义外观也可以运行)。
现在,您应该扩展VirtualFlow(比如CustomVirtualFlow
)并让CustomListViewSkin在运行时通过覆盖CustomVirtualFlow类的createVirtualFlow来创建CustomVirtualFlow的实例。
然后,您应该将此方法添加到CustomVirtualFlow以完成作业。
import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.EventHandler;
import javafx.scene.control.ListCell;
import javafx.scene.input.MouseEvent;
public class CustomVirtualFlow<T> extends VirtualFlow<ListCell<T>>
{
public VirtualScrollBar getVertialBar()
{
return getVbar();
}
public VirtualScrollBar getVertialBar()
{
return getVbar();
}
}
最后,将此方法添加到CustomListViewSkin实现中:
public CustomVirtualFlow<ListCell<T>> getFlow()
{
return (CustomVirtualFlow<ListCell<T>>) flow;
}
而且,现在:
ListView lv = new ListView();
CustomListViewSkin skin = new CustomListViewSkin(lv);
lv.setSkin(skin);
//add the list view to some scene
CustomVirtualFlow flow = skin.getFlow();
ScrollBar vb = flow.getVerticalBar();
//do whatever you like with the vb instance now