JavaFX无法在枚举与自定义单元格工厂一起使用时设置数据



[附完整源代码]

我有一个javafx TableView,它有3列("Name"、"Gender"、"Country")。我将细胞工厂附加到我所有的专栏中,如下所示。

nameCol.setCellFactory(TextFieldTableCell.forTableColumn());
genderCol.setCellFactory(ComboBoxTableCell.forTableColumn(GenderEnum.values()));
countryCol.setCellFactory(ComboBoxTableCell.forTableColumn("India", "USA"));

我自己没有实现任何提交逻辑。现在我更改所有3列中的值,然后打印数据。我可以在除genderCol之外的所有列上看到更改后的值。该列的唯一区别在于它使用了枚举。

当我更改countryCol(也就是ComoboBoxTableCell)中的值时,countryProperty会被调用两次,先用旧值,然后用新值,但对于genderCol,genderProperty只调用一次。

您可以复制并执行代码,在不更改任何内容的情况下先打印数据,然后更改所有3列的值,然后打印数据。现在检查,除了genderCol之外,其他列都有更改的值。

枚举是否遗漏了什么或做错了什么

Main.java

package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application
{
@Override
public void start(final Stage primaryStage)
{
try
{
final VBox root = FXMLLoader.load(this.getClass().getResource("MainView.fxml"));
final Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
catch(final Exception e)
{
e.printStackTrace();
}
}
public static void main(final String[] args)
{
launch(args);
}
}

MainView.fxml

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<VBox spacing="10.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
<children>
<TableView fx:id="table" editable="true">
<columns>
<TableColumn prefWidth="100.0" text="Name" fx:id="nameCol">
<cellValueFactory><PropertyValueFactory property="name" /></cellValueFactory>
</TableColumn>
<TableColumn prefWidth="100.0" text="Gender" fx:id="genderCol">
<cellValueFactory><PropertyValueFactory property="gender" /></cellValueFactory>
</TableColumn>
<TableColumn prefWidth="100.0" text="Country" fx:id="countryCol">
<cellValueFactory><PropertyValueFactory property="country" /></cellValueFactory>
</TableColumn>
</columns>
</TableView>
<Button text="Print Data"  onAction="#printData"/>
</children>
</VBox>

MainController.java

package application;
import java.net.URL;
import java.util.ResourceBundle;
import application.Person.GenderEnum;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
/**
* @author Saravana Kumar M
*
*/
public class MainController implements Initializable
{
@FXML
TableView<Person> table;
@FXML
TableColumn<Person, String> nameCol;
@FXML
TableColumn<Person, GenderEnum> genderCol;
@FXML
TableColumn<Person, String> countryCol;
@Override
public void initialize(final URL location, final ResourceBundle resources)
{
this.nameCol.setCellFactory(TextFieldTableCell.forTableColumn());
this.genderCol.setCellFactory(ComboBoxTableCell.forTableColumn(GenderEnum.values()));
this.countryCol.setCellFactory(ComboBoxTableCell.forTableColumn("India", "USA"));
final Person p1 = new Person("A", "M", "India");
final Person p2 = new Person("B", "F", "USA");
final Person p3 = new Person("C", "N", "India");
final Person p4 = new Person("D", null, "USA");
final Person p5 = new Person("E", "M", "India");
final Person p6 = new Person("F", "F", "USA");
final Person p7 = new Person("G", "N", "India");
final Person p8 = new Person("H", null, "USA");
this.table.setItems(FXCollections.observableArrayList(p1, p2, p3, p4, p5, p6, p7, p8));
this.genderCol.setOnEditCommit((event) -> this.doThis(event));
}
private void doThis(final CellEditEvent<Person, GenderEnum> event)
{
System.out.println(event);
System.out.println(event.getOldValue());
System.out.println(event.getNewValue());
System.out.println(event.getRowValue());
}
@FXML
public void printData()
{
this.table.getItems().forEach(System.out::println);
}
}

Person.java

package application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
* @author Saravana Kumar M
*
*/
public class Person
{
private final StringProperty name;
private final ObjectProperty<GenderEnum> gender;
private final StringProperty country;
public Person(final String name, final String gender, final String country)
{
this.name = new SimpleStringProperty(name);
if(gender == null)
{
this.gender = new SimpleObjectProperty<>();
}
else
{
this.gender = new SimpleObjectProperty<>(GenderEnum.valueOf(gender));
}
this.country = new SimpleStringProperty(country);
}
public String getName()
{
return this.name.get();
}
public void setName(final String name)
{
this.name.set(name);
}
public StringProperty nameProperty()
{
return this.name;
}
public GenderEnum getGender()
{
return this.gender.get();
}
public void setGender(final GenderEnum gender)
{
this.gender.set(gender);
}
public ObjectProperty<GenderEnum> genderProperty()
{
return this.gender;
}
public String getCountry()
{
return this.country.get();
}
public void setCountry(final String country)
{
this.country.set(country);
}
public StringProperty countryProperty()
{
return this.country;
}
@Override
public String toString()
{
return "name : " + this.name + " name.get : " + this.name.get() + " gender : " + this.gender + " gender.get : " + this.gender.get() + " country : " + this.country.get() + " country.get : " + this.country.get();
}
public enum GenderEnum
{
M("Male"), F("Female"), N("None");
private final String label;
private GenderEnum(final String label)
{
this.label = label;
}
@Override
public String toString()
{
return this.label;
}
}
}

提前感谢。

来自TableView文档:

默认情况下,TableColumn编辑提交处理程序为非null尝试覆盖的属性值的默认处理程序当前正在编辑的行中的项。它能够作为在新值中传递Cell.commitEdit(Object)方法,这是通过CellEditEvent传递给编辑提交处理程序被解雇。这只是一个打电话的问题TableColumn.CellEditEvent.getNewValue()检索该值。

非常重要的是要注意,如果你打电话TableColumn.setOnEditCommit(javafx.event.EventHandler)EventHandler,则将删除默认处理程序。除非然后处理对属性(或相关数据)的写回来源),什么都不会发生。您可以使用TableColumnBase.addEventHandler(javafx.event.EventType, javafx.event.EventHandler)方法添加TableColumn.EDIT_COMMIT_EVENTEventType和您想要的EventHandler作为第二个论点。使用此方法,将不会替换默认实现,但当编辑提交时会通知您已发生。

因为你有

this.genderCol.setOnEditCommit((event) -> this.doThis(event));

在控制器类中,删除更新属性的默认处理程序。如果你用代替它

this.genderCol.addEventHandler(TableColumn.<Person, GenderEnum>editCommitEvent(),
event -> this.doThis(event));

它将按预期工作。(请注意,文档告诉您如何获取事件类型是不正确的。还要注意,您的处理程序将在默认处理程序之前调用,因此getRowValue()的输出将在更新之前显示值,但按下按钮显示值将显示新值。)

最新更新