gpt4 book ai didi

JavaFX - 使自定义对象的 ListView 可编辑?

转载 作者:行者123 更新时间:2023-11-30 06:20:46 25 4
gpt4 key购买 nike

所以我使用 JavaFX 制作了一个简单的待办事项列表。我希望通过简单地双击待办事项列表中的每个项目并能够为该项目输入新值来使其可编辑。我一直在阅读 JavaDocs 以更好地理解如何做到这一点。我在网上找到了一个关于如何使用 String 类型的 ListView 来执行此操作的示例,但是当您有自定义对象的 ListView 时,它似乎会更复杂(就像我的情况一样,其中 ListView 的类型为 ToDoItem,a本文稍后将显示该类)。这是我到目前为止所尝试过的。

  public void initialize()
{
listContextMenu = new ContextMenu();
MenuItem deleteMenuItem = new MenuItem("Delete");
deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
TodoItem item = todoListView.getSelectionModel().getSelectedItem();
deleteItem(item);
}
});

listContextMenu.getItems().addAll(deleteMenuItem);
todoListView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TodoItem>() {
@Override
public void changed(ObservableValue<? extends TodoItem> observable, TodoItem oldValue, TodoItem newValue) {
if(newValue != null)
{
TodoItem item = todoListView.getSelectionModel().getSelectedItem();
itemDetailsTextArea.setText(item.getDetails());
DateTimeFormatter df = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
deadlineLabel.setText(item.getDeadline().format(df));
}
}
});

wantAllItems = new Predicate<TodoItem>() {
@Override
public boolean test(TodoItem todoItem) {
return true;
}
};

wantTodaysItems = new Predicate<TodoItem>() {
@Override
public boolean test(TodoItem todoItem) {
return todoItem.getDeadline().equals(LocalDate.now());
}
};
filteredList = new FilteredList<TodoItem>(TodoData.getInstance().getTodoitems(), wantAllItems);
SortedList<TodoItem> sortedList = new SortedList<TodoItem>(filteredList,
new Comparator<TodoItem>() {
@Override
public int compare(TodoItem o1, TodoItem o2) {
return o1.getDeadline().compareTo(o2.getDeadline());
}
});

//todoListView.setItems(TodoData.getInstance().getTodoitems());
todoListView.setItems(sortedList);
todoListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
todoListView.getSelectionModel().selectFirst();

todoListView.setEditable(true);

todoListView.setCellFactory(new Callback<ListView<TodoItem>, ListCell<TodoItem>>() {
@Override
public ListCell<TodoItem> call(ListView<TodoItem> lv) {
TextFieldListCell<TodoItem> cell = new TextFieldListCell<TodoItem>(){
@Override
public void updateItem(TodoItem item, boolean empty) {
super.updateItem(item, empty);

if(empty) setText(null);
else
{
setText(item.getShortDescription());
if(item.getDeadline().isBefore(LocalDate.now().plusDays(1)))
setTextFill(Color.RED);
else if(item.getDeadline().equals(LocalDate.now().plusDays(1)))
setTextFill(Color.BROWN);
}
}

@Override
public void commitEdit(TodoItem newValue) {
super.commitEdit(newValue);
}

};

cell.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
if(event.getCode() == KeyCode.ENTER)
cell.commitEdit(lv.getSelectionModel().getSelectedItem());
}
});

cell.emptyProperty().addListener(
(obs, wasEmpty, isNowEmpty) ->
{
if(isNowEmpty)
cell.setContextMenu(null);
else
cell.setContextMenu(listContextMenu);
}
);

cell.setConverter(new StringConverter<TodoItem>() {
@Override
public String toString(TodoItem object) {
return object.toString();
}

@Override
public TodoItem fromString(String string) {
cell.getItem().setShortDescription(string);
return cell.getItem();
}
});
return cell;
}
});

// this is the method where the source of the exception is being reported
todoListView.setOnEditCommit(new EventHandler<ListView.EditEvent<TodoItem>>() {
@Override
public void handle(ListView.EditEvent<TodoItem> e) {
todoListView.getItems().set(e.getIndex(), e.getNewValue());
}
});

}

我的ListView是ToDoItem类型。 ToDoItem 类如下所示:

public class TodoItem {

private SimpleStringProperty shortDescription;
private SimpleStringProperty details;
private LocalDate deadline;

public TodoItem(String shortDescription, String details, LocalDate deadline) {
this.shortDescription = new SimpleStringProperty(shortDescription);
this.details = new SimpleStringProperty(details);
this.deadline = deadline;
}

public String getShortDescription() {
return shortDescription.get();
}
public void setShortDescription(String shortDescription) {
this.shortDescription.set(shortDescription);
}

public String getDetails() {
return details.get();
}
public void setDetails(String details) { this.details.set(details); }

public LocalDate getDeadline() {
return deadline;
}
public void setDeadline(LocalDate deadline) {
this.deadline = deadline;
}

@Override
public String toString() {
return shortDescription.get();
}
}

待办事项列表 UI 本身可以毫无问题地运行并显示在屏幕上,并且所有其他功能都可以运行(添加项目、删除项目等)。我唯一遇到的问题是使其可编辑。

这是我按 ENTER 后得到的堆栈跟踪(第 162 行指的是 setOnEditCommit 方法的开头,第 165 行指的是 handle 方法中的单行代码):

Exception in thread "JavaFX Application Thread" java.lang.UnsupportedOperationException
at java.util.AbstractList.set(AbstractList.java:132)
at com.arslansana.todolist.Controller$7.handle(Controller.java:165)
at com.arslansana.todolist.Controller$7.handle(Controller.java:162)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8411)
at javafx.scene.control.ListCell.commitEdit(ListCell.java:378)
at com.arslansana.todolist.Controller$6$1.commitEdit(Controller.java:122)
at com.arslansana.todolist.Controller$6$1.commitEdit(Controller.java:104)
at javafx.scene.control.cell.CellUtils.lambda$createTextField$615(CellUtils.java:248)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8411)
at com.sun.javafx.scene.control.behavior.TextFieldBehavior.fire(TextFieldBehavior.java:179)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callAction(TextInputControlBehavior.java:178)
at com.sun.javafx.scene.control.behavior.BehaviorBase.callActionForEvent(BehaviorBase.java:218)
at com.sun.javafx.scene.control.behavior.TextInputControlBehavior.callActionForEvent(TextInputControlBehavior.java:127)
at com.sun.javafx.scene.control.behavior.BehaviorBase.lambda$new$74(BehaviorBase.java:135)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$KeyHandler.process(Scene.java:3964)
at javafx.scene.Scene$KeyHandler.access$1800(Scene.java:3910)
at javafx.scene.Scene.impl_processKeyEvent(Scene.java:2040)
at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2501)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:216)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:148)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$353(GlassViewEventHandler.java:247)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:246)
at com.sun.glass.ui.View.handleKeyEvent(View.java:546)
at com.sun.glass.ui.View.notifyKey(View.java:966)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)

最佳答案

您将 ListView 上的单元格工厂设置为提供支持编辑的单元格的单元格工厂:

    todoListView.setCellFactory(new Callback<ListView<TodoItem>, ListCell<TodoItem>>() {
@Override
public ListCell<TodoItem> call(ListView<TodoItem> lv) {
TextFieldListCell<TodoItem> cell = new TextFieldListCell<TodoItem>();
// ...

return cell ;
}
});

但是您几乎立即将其替换为提供不可编辑单元的单元工厂:

    todoListView.setCellFactory(new Callback<ListView<TodoItem>, ListCell<TodoItem>>() {
@Override
public ListCell<TodoItem> call(ListView<TodoItem> param) {
ListCell<TodoItem> cell = new ListCell<TodoItem>(){
@Override
protected void updateItem(TodoItem item, boolean empty) {
super.updateItem(item, empty);
// ...
}
};

// ...

return cell;
}
});

因此,当然, ListView 中的单元格是不可编辑的。

由于 ListView (至多)每个项目有一个列表单元格,因此您需要在单个单元格中提供所需的所有功能:

    todoListView.setCellFactory(new Callback<ListView<TodoItem>, ListCell<TodoItem>>() {
@Override
public ListCell<TodoItem> call(ListView<TodoItem> lv) {
TextFieldListCell<TodoItem> cell = new TextFieldListCell<TodoItem>(){
@Override
protected void updateItem(TodoItem item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setStyle("");
} else
if(item.getDeadline().isBefore(LocalDate.now().plusDays(1)))
setStyle("-fx-text-fill: red ;");
else if(item.getDeadline().equals(LocalDate.now().plusDays(1)))
setStyle("-fx-text-fill: brown;");
else
setStyle("");
}
};
cell.setConverter(new StringConverter<TodoItem>() {
@Override
public String toString(TodoItem object) {
return object.toString();
}

@Override
public TodoItem fromString(String string) {
return new TodoItem(string, null, null);
}
});
return cell;
}
});

另请注意,您的 updateItem() 方法需要处理所有情况(例如,如果该项目从明天到期的项目更改为明天到期的项目,则需要从该项目中删除颜色)单元格的文本)。

您的 onEditCommit 当前实现的方式,您将得到空指针异常,因为单元实现不处理 null 的截止日期(但是 onEditCommit 处理程序设置截止日期为空)。我将把它留给您,因为我不知道您在这部分代码中真正打算做什么。

关于JavaFX - 使自定义对象的 ListView 可编辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48204316/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com