在我的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>
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
}
}
自定义单元代码:
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);
}
}
}
答案 0 :(得分:2)
一种相当干净的方法是使用列表视图中的单元格注册鼠标侦听器,以处理非空单元格的单击。如果单元格非空,则使用鼠标事件。在列表视图本身上注册第二个鼠标侦听器,以处理空单元格的单击(如果列表视图为空,则处理列表视图的占位符)。这需要两个处理程序,但至少以合理的方式分离“空”和“非空”功能。
这是一个简单的例子:
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);
}
}
答案 1 :(得分:0)
你可以尝试类似的东西:
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());
}
}
}
与评论相关的修改:
要处理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);
}
}
});