看起来你想要一个ControlsFX
PropertySheet:
类似的实现是在JavaFX 2 TableView : different cell factory depending on the data inside the cell的答案中.尽管该问题的答案基于TableView,ListView和TableView都是虚拟化控件,因此实现概念有点类似于在问题中概述的使用带有HBox的ListView.
根据问题的示例代码进行更新.
我仍然认为ControlsFX PropertySheet似乎是您尝试完成的最合适的解决方案.像ListView一样使用虚拟控件来完成这样的任务只会让事情变得比他们需要的更复杂.
基于ListView的属性编辑器的完整解决方案是一个相当复杂的事情,超出了StackOverflow答案中可合理提供的范围.
您在问题中提供的示例代码存在一些问题. ListView是一个虚拟化控件,因此您不应创建新的图形节点,以便在调用更新时始终放在ListView中.会发生什么是TextField获得焦点,然后在ListView上调用update并创建一个新的TextField,默认情况下新的TextField没有焦点.
我认为ListView本身对于您的特定情况有一些实现问题,并且调用更新次数太多了.无论如何,您应该编写代码,以便在单个单元格上适当地处理多次调用的更新.如果你这样做,ListView调用你的方法的次数多于它需要的时间并不重要.
以下是一些示例代码,可以帮助您取得更多进展.我不相信示例代码是您问题的完整解决方案,它当然不是作为Java对象的综合属性编辑器提供的,但它可能会给您一些灵感来帮助改进和实现您的代码(假设您决定继续尝试以这种方式解决这个问题).如果继续使用ListView,您可能需要查看ListView的编辑例程(类似于Oracle JavaFX教程中为editing table cells定义的内容).
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.lang.reflect.Field;
import java.time.LocalDate;
/**
* @author dmitrynelepov
* Modified by Jewelsea
*/
public class EvilHasSurvived extends Application {
static class TestClassForListView {
public String fieldString;
public LocalDate fieldDate;
@Override
public String toString() {
return "TestClassForListView{" +
"fieldString='" + fieldString + '\'' +
", fieldDate=" + fieldDate +
'}';
}
}
static class MyListCell extends ListCell {
private TextField textField;
private DatePicker datePicker;
private Object editedObject;
private ChangeListener editCommitHandler;
public MyListCell(Object editedObject) {
this.editedObject = editedObject;
setContentDisplay(ContentDisplay.RIGHT);
}
@Override
protected void updateItem(Field t, boolean bln) {
super.updateItem(t, bln);
if (datePicker != null) {
datePicker.focusedProperty().removeListener(editCommitHandler);
}
if (textField != null) {
textField.focusedProperty().removeListener(editCommitHandler);
}
if (t == null) {
setText(null);
setGraphic(null);
return;
}
if (t.getType().equals(String.class)) {
if (textField == null) {
textField = new TextField();
}
editCommitHandler = (observable, oldValue, newValue) -> {
try {
t.set(editedObject, textField.getText());
System.out.println(editedObject + " for " + textField + " value " + textField.getText());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
};
textField.focusedProperty().addListener(editCommitHandler);
setText(t.getName());
setGraphic(textField);
} else if (t.getType().equals(LocalDate.class)) {
if (datePicker == null) {
datePicker = new DatePicker();
}
editCommitHandler = (observable, oldValue, newValue) -> {
try {
t.set(editedObject, datePicker.getValue());
System.out.println(editedObject + " for " + datePicker + " value " + datePicker.getValue());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
};
datePicker.focusedProperty().addListener(editCommitHandler);
setText(t.getName());
setGraphic(datePicker);
}
}
}
@Override
public void start(Stage stage) throws Exception {
ListView listView = new ListView<>();
listView.setItems(
FXCollections.observableArrayList(
TestClassForListView.class.getFields()
)
);
TestClassForListView testObject = new TestClassForListView();
listView.setCellFactory(p -> new MyListCell(testObject));
stage.setScene(new Scene(listView));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}