Java 具有自定义单元格单击处理的ListView

Java 具有自定义单元格单击处理的ListView,java,listview,javafx,event-handling,Java,Listview,Javafx,Event Handling,在我的JavaFX应用程序中,我使用带有自定义单元格的ListView。我希望处理列表项单击的方式不同于单击项目下方的空白区域。我在整个ListView上设置了一个事件侦听器,但我无法确定单击了哪些项(getSelectedItem()为null,可能是因为我的自定义单元格代码中存在错误)。如何正确处理以下情况 我的组件如下所示: ListView具有在组件构造函数中设置的自定义单元格工厂: 公共类DayComponent扩展了VBox{ @FXML 私有列表视图任命列表视图; pub

在我的JavaFX应用程序中,我使用带有自定义单元格的ListView。我希望处理列表项单击的方式不同于单击项目下方的空白区域。我在整个ListView上设置了一个事件侦听器,但我无法确定单击了哪些项(
getSelectedItem()
null
,可能是因为我的自定义单元格代码中存在错误)。如何正确处理以下情况

我的组件如下所示:


ListView具有在组件构造函数中设置的自定义单元格工厂:

公共类DayComponent扩展了VBox{
@FXML
私有列表视图任命列表视图;
public DayComponent()引发IOException{
// ...
setCellFactory(l->new AppointmentCell());
}
@FXML
公共无效HandLeapPoints单击(MouseeEvent事件){
System.out.println(appointmentsListView.getSelectionModel()
.getSelectedItem());//在任何情况下都为null
}
}
自定义单元格代码:

public class AppointmentCell extends ListCell<Appointment> {

    @Override
    protected void updateItem(Appointment item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
            setGraphic(new AppointmentLabel(item));
        } else {
            setGraphic(null);
        }
    }
}
public class AppointmentCell扩展了ListCell{
@凌驾
受保护的void updateItem(约会项,布尔值为空){
super.updateItem(项,空);
如果(!空){
setGraphic(新任命标签(项目));
}否则{
设置图形(空);
}
}
}

您可以尝试以下方法:

public class AppointmentCellMouseClickHandler implements EventHandler<MouseEvent> {

    private final Appointment appointment;

    public AppointmentCellMouseClickHandler(Appointment appointment) {
        this.appointment = appointment;
    }

    @Override
    public void handle(MouseEvent arg0) {
        //Do stuff with appointment
    }
}

public class EmptyAppointmentCellMouseClickHandler implements EventHandler<MouseEvent> {

    @Override
    public void handle(MouseEvent arg0) {
        //Do stuff without appointment
    }
}

public class AppointmentCell extends ListCell<Appointment> {

    @Override
    protected void updateItem(Appointment item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
            setGraphic(new AppointmentLabel(item));
            this.setOnMouseClicked(new AppointmentCellMouseClickHandler(item));
        } else {
            setGraphic(null);
            this.setOnMouseClicked(new EmptyAppointmentCellMouseClickHandler());
        }
    }
}
公共类任命CellMouseClickHandler实现EventHandler{
非公开最终任命;
公共任命CellMouseClickhandler(任命){
这个.任命=任命;
}
@凌驾
公共无效句柄(MouseEvent arg0){
//约见
}
}
公共类EmptyAppointmentCellMouseClickHandler实现EventHandler{
@凌驾
公共无效句柄(MouseEvent arg0){
//不约而同地做事
}
}
公共类任命单元扩展了ListCell{
@凌驾
受保护的void updateItem(约会项,布尔值为空){
super.updateItem(项,空);
如果(!空){
setGraphic(新任命标签(项目));
this.setonMouseClickHandler(新任命CellMouseClickHandler(项目));
}否则{
设置图形(空);
this.setOnMouseClicked(新的EmptyAppointmentCellMouseClickHandler());
}
}
}
编辑与评论相关的内容:

要处理ListView为空的情况,可以执行以下操作:

//To handle the initialisation where the listener won't be call
appointmentsListView.setOnMouseClicked(new EmptyAppointmentCellMouseClickHandler());
appointmentsListView.getItems().addListener(new ListChangeListener<Appointment>() {
            @Override
            public void onChanged(Change<? extends Appointment> change) {
                while(change.next()){
                    //Toogle the listener depending on the content of the list
                    listView.setOnMouseClicked(change.getList().isEmpty() ? new EmptyAppointmentCellMouseClickHandler() : null);
                }
            }
        });
//在不调用侦听器的情况下处理初始化
AppointsListView.setOnMouseClicked(新的EmptyAppointCellMouseClickHandler());
appointmentsListView.getItems().addListener(新ListChangeListener()){
@凌驾

public void onchange(Change您可以尝试以下方法:

public class AppointmentCellMouseClickHandler implements EventHandler<MouseEvent> {

    private final Appointment appointment;

    public AppointmentCellMouseClickHandler(Appointment appointment) {
        this.appointment = appointment;
    }

    @Override
    public void handle(MouseEvent arg0) {
        //Do stuff with appointment
    }
}

public class EmptyAppointmentCellMouseClickHandler implements EventHandler<MouseEvent> {

    @Override
    public void handle(MouseEvent arg0) {
        //Do stuff without appointment
    }
}

public class AppointmentCell extends ListCell<Appointment> {

    @Override
    protected void updateItem(Appointment item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
            setGraphic(new AppointmentLabel(item));
            this.setOnMouseClicked(new AppointmentCellMouseClickHandler(item));
        } else {
            setGraphic(null);
            this.setOnMouseClicked(new EmptyAppointmentCellMouseClickHandler());
        }
    }
}
公共类任命CellMouseClickHandler实现EventHandler{
非公开最终任命;
公共任命CellMouseClickhandler(任命){
这个.任命=任命;
}
@凌驾
公共无效句柄(MouseEvent arg0){
//约见
}
}
公共类EmptyAppointmentCellMouseClickHandler实现EventHandler{
@凌驾
公共无效句柄(MouseEvent arg0){
//不约而同地做事
}
}
公共类任命单元扩展了ListCell{
@凌驾
受保护的void updateItem(约会项,布尔值为空){
super.updateItem(项,空);
如果(!空){
setGraphic(新任命标签(项目));
this.setonMouseClickHandler(新任命CellMouseClickHandler(项目));
}否则{
设置图形(空);
this.setOnMouseClicked(新的EmptyAppointmentCellMouseClickHandler());
}
}
}
编辑与评论相关的内容:

要处理ListView为空的情况,可以执行以下操作:

//To handle the initialisation where the listener won't be call
appointmentsListView.setOnMouseClicked(new EmptyAppointmentCellMouseClickHandler());
appointmentsListView.getItems().addListener(new ListChangeListener<Appointment>() {
            @Override
            public void onChanged(Change<? extends Appointment> change) {
                while(change.next()){
                    //Toogle the listener depending on the content of the list
                    listView.setOnMouseClicked(change.getList().isEmpty() ? new EmptyAppointmentCellMouseClickHandler() : null);
                }
            }
        });
//在不调用侦听器的情况下处理初始化
AppointsListView.setOnMouseClicked(新的EmptyAppointCellMouseClickHandler());
appointmentsListView.getItems().addListener(新ListChangeListener()){
@凌驾

public void onChanged(Change一种合理干净的方法是向列表视图中的单元格注册鼠标侦听器,以处理对非空单元格的单击。如果单元格非空,则使用鼠标事件。在列表视图本身注册第二个鼠标侦听器,以处理对空单元格的单击(如果列表视图为空,则在列表视图的占位符上)。这需要两个处理程序,但至少以合理的方式分隔“空”和“非空”功能

下面是一个简单的例子:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ListViewMouseHandlerExample extends Application {

    private int count = 0 ;

    @Override
    public void start(Stage primaryStage) {
        ListView<String> listView = new ListView<>();

        Button addButton = new Button("Add");
        addButton.setOnAction(e -> listView.getItems().add("Item " + (++count)));

        Button deleteButton = new Button("Delete");
        deleteButton.setOnAction(e -> listView.getItems().remove(listView.getSelectionModel().getSelectedIndex()));
        deleteButton.disableProperty().bind(listView.getSelectionModel().selectedItemProperty().isNull());

        listView.setCellFactory(lv -> {
            ListCell<String> cell = new ListCell<String>() {
                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    setText(item);
                }
            };
            cell.setOnMouseClicked(e -> {
                if (!cell.isEmpty()) {
                    System.out.println("You clicked on " + cell.getItem());
                    e.consume();
                }
            });
            return cell;
        });

        listView.setOnMouseClicked(e -> {
            System.out.println("You clicked on an empty cell");
        });

        BorderPane root = new BorderPane(listView);
        ButtonBar buttons = new ButtonBar();
        buttons.getButtons().addAll(addButton, deleteButton);
        root.setBottom(buttons);


        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
导入javafx.application.application;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.ButtonBar;
导入javafx.scene.control.ListCell;
导入javafx.scene.control.ListView;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
公共类ListViewMouseHandlerExample扩展了应用程序{
私有整数计数=0;
@凌驾
公共无效开始(阶段primaryStage){
ListView ListView=新建ListView();
按钮添加按钮=新按钮(“添加”);
addButton.setOnAction(e->listView.getItems().add(“Item”+(+++count)));
按钮删除按钮=新按钮(“删除”);
deleteButton.setOnAction(e->listView.getItems().remove(listView.getSelectionModel().getSelectedIndex());
deleteButton.disableProperty().bind(listView.getSelectionModel().SelectEditeProperty().isNull());
listView.setCellFactory(lv->{
ListCell=新ListCell(){
@凌驾
受保护的void updateItem(字符串项,布尔值为空){
super.updateItem(项,空);
setText(项目);
}
};
cell.setOnMouseClicked(e->{
如果(!cell.isEmpty()){