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

buo*_*oto 1 java listview javafx event-handling

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

我的组件如下所示:

具有自定义单元格的组件

<fx:root type="javafx.scene.layout.VBox">
    <Label fx:id="dayname" text="${controller.day.name}" />
    <ListView fx:id="appointmentsListView" items="${controller.day.events}" 
        onMouseClicked="#handleAppointmentsClick" />
</fx:root>
Run Code Online (Sandbox Code Playgroud)

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

public class DayComponent extends VBox {
    @FXML
    private ListView<Appointment> appointmentsListView;

    public DayComponent() throws IOException {
        // ...
        appointmentsListView.setCellFactory(l -> new AppointmentCell());
    }

    @FXML
    public void handleAppointmentsClick(MouseEvent event) {
        System.out.println(appointmentsListView.getSelectionModel()
            .getSelectedItem()); // null in every case
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义单元格代码:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 6

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

这是一个简单的例子:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)