2015-04-17 83 views
0

我创建了以下包含带注册滚动事件侦听器的ListView的示例。不幸的是,当通过鼠标滚轮滚动时,侦听器只会触发,而在侧面使用滚动条时不会触发。代码有什么问题?JavaFX ScrollListener 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 JDK 8得到这样的功能:

/** 
* 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

您可以访问滚动条和事件处理程序添加到它。请参阅[此链接](http://stackoverflow.com/a/25886988)。 –

+0

谢谢,我解决了你的建议! – alex

回答

1

根据Documentation

滚动事件表示用户通过鼠标滚轮, 触控板,触摸屏或其他类似设备执行滚动。

因此,无关与ScrollBar S中ListView的。因为它们是实现细节,所以访问它们并不容易,除了做一些反射技巧。

+0

谢谢,我很害怕.... – alex

+0

尽管可以使用反射,但它不是唯一的方法。我在下面提供了另一个简单的答案。 – Amin

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 
+0

或者你看看这个[我的答案](http://stackoverflow.com/questions/26537548/javafx-listview-with-touch-events-for-scrolling-up-and-down/39304755#39304755) – Amin