Javafx 带单元格编辑的TableView
我需要一个具有编辑功能的TableView 因此,我已经尝试了一点,并整理了以下代码,这些代码似乎对我来说很好——直到我开始使用更多的数据行进行测试 问题:TableView不能一次初始化所有人员/行,只能初始化进入视图的人员/行;将行移出并再次移入视图会重新初始化其内容 能否强制TableView一次加载并保留所有可用数据?我不会有超过200-300行,所以没有内存问题。还是有更好的方法 我已经尝试了标准的Oracle EditingCell示例,并对其进行了一些修改,但我无法想象在分发应用程序时,用户需要在输入文本之前四次单击一个字段(然后再次四次单击下一个字段) 以下是单个类中的代码:Javafx 带单元格编辑的TableView,javafx,javafx-2,tableview,tablecell,Javafx,Javafx 2,Tableview,Tablecell,我需要一个具有编辑功能的TableView 因此,我已经尝试了一点,并整理了以下代码,这些代码似乎对我来说很好——直到我开始使用更多的数据行进行测试 问题:TableView不能一次初始化所有人员/行,只能初始化进入视图的人员/行;将行移出并再次移入视图会重新初始化其内容 能否强制TableView一次加载并保留所有可用数据?我不会有超过200-300行,所以没有内存问题。还是有更好的方法 我已经尝试了标准的Oracle EditingCell示例,并对其进行了一些修改,但我无法想象在分发应用程
package config_V1;
import java.util.Vector;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.scene.Scene;
/**
*
* Standard person table in a self running application <br>
* - some configurable textField derivatives within<br>
* - Person class within
*
* - unfortunately not working as expected:
* first row gets initialised always twice
* fields not in view are not initialised
* the same row gets initialised again whenever coming in view during scrolling
* issues with sorting (after sorting changing age updates the wrong row)
* this can be circumvented with setSortable(false) on each column;
*
*/
public class TestCustomCellFactories extends Application {
private Vector<Person> persons;
private TableView <Object>tableView = new TableView<Object>();
private ObservableList<Object> tableData = FXCollections.observableArrayList();
private static Vector<TextField> textFields=new Vector<TextField>();
private CheckBox focusFirstNameCB;
Button addButton = new Button("Add Rows");
Button removeButton= new Button("Remove Rows");
Button defaultButton= new Button("set defaults");
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void start(Stage stage) {
//*********** CREATE COLUMNS *****************************************
tableView.setEditable(true);
TableColumn firstNameCol = new TableColumn<Object,String>("First Name");
firstNameCol.setCellFactory(makeEditableStringCellFactory(0,0));
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn<Object,String>("Last Name");
lastNameCol.setCellFactory(makeEditableStringCellFactory(3,1));
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn<Object,String>("Email");
emailCol.setCellFactory(makeEditableStringCellFactory(1,2));
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
emailCol.setMinWidth(200);
TableColumn age = new TableColumn<Object,String>("age");
age.setCellFactory(makeEditableStringCellFactory(2,3));
age.setCellValueFactory(
new PropertyValueFactory<Person, String>("age"));
TableColumn ageMinus5 = new TableColumn<Object,String>("real age");
ageMinus5.setCellFactory(makeEditableStringCellFactory(2,4));
ageMinus5.setCellValueFactory(
new PropertyValueFactory<Person, String>("realAge"));
//************* ADD EVENT HANDLER TO BUTTONS ****************************
focusFirstNameCB= new CheckBox("focus column 1");
focusFirstNameCB.setSelected(true);
addButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
//prt(Platform.isFxApplicationThread());
if(persons==null){
persons = new Vector<Person>();
persons.add(new Person("Jacob", "Smith", "jacob.smith@example.com"));
persons.add(new Person("Isabella", "Johnson", "isabella.johnson@example.com"));
persons.add(new Person("Ethan", "Williams", "ethan.williams@example.com"));
persons.add(new Person("Jacob2", "Smith2", "jacob.smith@example.com"));
persons.add(new Person("Isabella2", "Johnson2", "isabella.johnson@example.com"));
persons.add(new Person("Ethan2", "Williams2", "ethan.williams@example.com"));
persons.add(new Person("Jacob3", "Smith3", "jacob.smith@example.com"));
persons.add(new Person("Isabella3", "Johnson3", "isabella.johnson@example.com"));
persons.add(new Person("Ethan3", "Williams3", "ethan.williams@example.com"));
persons.add(new Person("Jacob4", "Smith4", "jacob.smith@example.com"));
persons.add(new Person("Isabella4", "Johnson4", "isabella.johnson@example.com"));
persons.add(new Person("Ethan4", "Williams4", "ethan.williams@example.com"));
persons.add(new Person("Jacob5", "Smith5", "jacob.smith@example.com"));
persons.add(new Person("Isabella5", "Johnson5", "isabella.johnson@example.com"));
persons.add(new Person("Ethan5", "Williams5", "ethan.williams@example.com"));
persons.add(new Person("Jacob6", "Smith6", "jacob.smith@example.com"));
persons.add(new Person("Isabella6", "Johnson6", "isabella.johnson@example.com"));
persons.add(new Person("Ethan6", "Williams6", "ethan.williams@example.com"));
}
tableView.setItems(tableData);
for(Person p:persons){
if(!p.isOnTable) tableData.add(p);
p.isOnTable=true;
}
updateFocus();//does not work here
}
});
removeButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
for(Person person: persons){
person.updatePerson();
prt(person.getFirstName()+";"+person.getLastName()+";" + person.getEmail() + ";" + person.getAge() + ";" + person.getRealAge());
tableData.remove(person); //or tableView.getItems().remove(p);
person.isOnTable=false;
}
}
});
defaultButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
for(Person person: persons){
prt("default for " + person.getEmail() );
person.setFirstName("John");
person.setLastName("Doe");
// person.setEmail("John.Doe@xy.com");
}
}
});
focusFirstNameCB.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
for(TextField tf:textFields){
if(tf.getId().equals("0"))tf.setFocusTraversable(focusFirstNameCB.isSelected());
}
}
});
//*********** ASSEMBLE GUI *****************************************
Scene scene = new Scene(new StackPane());
stage.setTitle("Table View Sample");
stage.setWidth(550);
stage.setHeight(500);
tableView.getColumns().addAll(firstNameCol, lastNameCol, emailCol, age, ageMinus5);
StackPane sp= new StackPane();
sp.getChildren().add(tableView);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(5, 5, 5, 5));
vbox.getChildren().addAll( addButton,removeButton,defaultButton,focusFirstNameCB,sp);
VBox.setVgrow(sp, Priority.ALWAYS);
((StackPane) scene.getRoot()).getChildren().add(vbox);
stage.setScene(scene);
stage.show();
}
private void updateFocus(){
prt(textFields.size());
for(TextField tf:textFields){
switch(Integer.parseInt(tf.getId())){
case 0: tf.setFocusTraversable(focusFirstNameCB.isSelected());
}
}
}
//*********** TABLE CELL CREATION *****************************************
public static Callback<TableColumn<Object, String>, TableCell<Object, String>> makeEditableStringCellFactory(final int type, final int id){
return new Callback<TableColumn<Object,String>, TableCell<Object,String>>() {
@Override
public TableCell<Object, String> call(final TableColumn<Object, String> tableColumn) {
TableCell <Object, String> cell = new TableCell<Object, String>(){
private boolean ini=true;
private TextField tf=null;
private Person person;
@Override
public void updateItem(String s, boolean empty)
{
super.updateItem(s, empty);
if (empty) {
if(tf!=null) setText(getString());//or once removed the textFields cannot be added again
else
{
setText(null);
setGraphic(null);
}
}
else
if(ini){
ini=false;
tableColumn.getTableView().getSelectionModel().select(getIndex());
person = (Person)tableColumn.getTableView().getSelectionModel().getSelectedItem();
switch (type){
case 0: {
tf= new TextField();break;
}
case 1: {
tf= new RightAlignedUnEditableTextField();break;
}
case 2: {
tf= new IntegerTextField();break;
}
case 3: {
tf= new UpperCaseTextField();
}
}
tf.setId(""+id);
person.registerTF(tf);
tf.setEditable(true);
setGraphic(tf);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
tf.setText(s);
this.textProperty().bindBidirectional(tf.textProperty()) ;
textFields.add(tf);
}else
if(tf!=null){
setText(getString());
}
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
};
return cell;
}
};
}
//************************* PERSON CLASS *****************************************************
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private final SimpleStringProperty age=new SimpleStringProperty();
private final SimpleStringProperty realAge=new SimpleStringProperty();
private boolean isOnTable = false;
private Vector<TextField> vtf = new Vector<TextField>();
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public void setFirstName(final String s) {
firstName.set("");
firstName.set(s);
}
public void setLastName(final String s) {
lastName.set("");
lastName.set(s);
}
public void setEmail(final String s) {
email.set("");
email.set(s);
}
public void setAge(final String s) {
age.set("");
age.set(s);
}
public void setRealAge(final String s) {
realAge.set("");
realAge.set(s);
}
public String getLastName() {
return lastName.get();
}
public String getFirstName() {
return firstName.get();
}
public String getEmail() {
return email.get();
}
public String getAge() {
return age.get();
}
public String getRealAge() {
return realAge.get();
}
public SimpleStringProperty lastNameProperty(){
return lastName;
}
public SimpleStringProperty firstNameProperty(){
return firstName;
}
public SimpleStringProperty emailProperty(){
return email;
}
public SimpleStringProperty ageProperty(){
return age;
}
public SimpleStringProperty realAgeProperty(){
return realAge;
}
public void registerTF(TextField tf){
prt("registered a TextField for "+ this.getFirstName());
vtf.add(tf);
int id=Integer.parseInt(tf.getId());
if(id==3){
//
tf.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable,
String oldValue, String newValue) {
if(newValue !=null && newValue.length()>1 && getFirstName().startsWith("Isabella")) {
setRealAge((Integer.parseInt(newValue)+5)+"");
}else setRealAge(newValue);
}
});
}
}
public void updatePerson(){ //starts with id 0!!!
for(TextField tf:vtf){
switch(Integer.parseInt(tf.getId())){
case 0: setFirstName(tf.getText());
case 1: setLastName(tf.getText());
case 2: setEmail(tf.getText());
case 3: setAge(tf.getText());
case 4: setRealAge(tf.getText());
}
}
}
}
//************************* TEXT FIELD CLASSES *****************************************************
private static class IntegerTextField extends TextField {
public IntegerTextField() {
super();
addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
if(!event.getCharacter().matches("[0123456789]")){
event.consume();
}
}
});
}
}
private static class UpperCaseTextField extends TextField {
public UpperCaseTextField() {
super();
focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue)
{
if (newPropertyValue) {//Textfield on focus
}
else
if(oldPropertyValue) { //Textfield out focus
setText(getText().trim().toUpperCase());
if(getText().length()>10) setText( getText().substring(0, 10));
}
}
});
}
}
private static class RightAlignedUnEditableTextField extends TextField {
public RightAlignedUnEditableTextField() {
super();
this.setAlignment(Pos.CENTER_RIGHT);
this.setEditable(false);
this.setFocusTraversable(false);
}
}
private static void prt(Object o) {System.out.println(o);}
}
package-config\u V1;
导入java.util.Vector;
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.control.Button;
导入javafx.scene.control.CheckBox;
导入javafx.scene.control.ContentDisplay;
导入javafx.scene.control.TableCell;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.TextField;
导入javafx.scene.control.cell.PropertyValueFactory;
导入javafx.scene.input.KeyEvent;
导入javafx.scene.layout.Priority;
导入javafx.scene.layout.StackPane;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
导入javafx.util.Callback;
导入javafx.scene.scene;
/**
*
*自运行应用程序中的标准人员表
*-在
*-个人类别
*
*-不幸的是,没有按预期工作:
*第一行总是初始化两次
*不在视图中的字段不会初始化
*在滚动过程中,只要出现在视图中,同一行就会再次初始化
*排序问题(排序后更改年龄更新错误行)
*这可以通过在每列上设置可排序(false)来避免;
*
*/
公共类TestCustomCellFactorys扩展了应用程序{
私人媒介人士;
private TableView TableView=new TableView();
私有ObservableList tableData=FXCollections.observableArrayList();
私有静态向量textFields=新向量();
私有复选框focusFirstNameCB;
Button addButton=新建按钮(“添加行”);
按钮移除按钮=新按钮(“移除行”);
按钮默认按钮=新按钮(“设置默认值”);
公共静态void main(字符串[]args){
发射(args);
}
@SuppressWarnings({“rawtypes”,“unchecked”})
公众假期开始(阶段){
//***********创建列*****************************************
tableView.setEditable(true);
TableColumn firstNameCol=新的TableColumn(“名字”);
firstNameCol.setCellFactory(makeEditableStringCellFactory(0,0));
firstNameCol.setCellValueFactory(
新财产价值工厂(“名字”);
TableColumn lastNameCol=新的TableColumn(“姓氏”);
lastNameCol.setCellFactory(makeEditableStringCellFactory(3,1));
lastNameCol.setCellValueFactory(
新财产价值工厂(“姓氏”);
TableColumn emailCol=新的TableColumn(“电子邮件”);
emailCol.setCellFactory(makeEditableStringCellFactory(1,2));
emailCol.setCellValueFactory(
新物业价值工厂(“电子邮件”);
设置最小宽度(200);
TableColumn年龄=新TableColumn(“年龄”);
年龄:setCellFactory(makeEditableStringCellFactory(2,3));
age.setCellValueFactory(
新物业价值工厂(“年龄”);
TableColumn ageMinus5=新的TableColumn(“真实年龄”);
ageMinus5.setCellFactory(makeEditableStringCellFactory(2,4));
ageMinus5.setCellValueFactory(
新房产价值工厂(“realAge”);
//*************将事件处理程序添加到按钮****************************
focusFirstNameCB=新复选框(“焦点列1”);
focusFirstNameCB.setSelected(true);
addButton.setOnAction(新的EventHandler(){
@凌驾
公共无效句柄(ActionEvent e){
//prt(Platform.isFxApplicationThread());
if(persons==null){
persons=新向量();
添加(新的人(“雅各布”、“史密斯”、“雅各布”)。smith@example.com"));
人员。添加(新人员(“伊莎贝拉”、“约翰逊”、“伊莎贝拉”)。johnson@example.com"));
人员。添加(新人员(“Ethan”、“Williams”、“Ethan”)。williams@example.com"));
人员。添加(新人员(“Jacob2”、“Smith2”、“jacob。smith@example.com"));
人员。添加(新人员(“Isabella2”、“Johnson 2”、“isabella”)。johnson@example.com"));
人员。添加(新人员(“Ethan2”、“Williams2”、“ethan。williams@example.com"));
人员。添加(新人员(“Jacob3”、“Smith3”、“jacob。smith@example.com"));
人员。添加(新人员(“Isabella3”、“Johnson 3”、“isabella”)。johnson@example.com"));
人员。添加(新人员(“Ethan3”、“Williams3”、“ethan。williams@example.com"));
人员。添加(新人员(“Jacob4”、“Smith4”、“jacob。smith@example.com"));
人员。添加(新人员(“Isabella4”、“Johnson 4”、“isabella”)。johnson@example.com"));
人员。添加(新人员(“Ethan4”、“Williams4”、“ethan。williams@example.com"));
人员。添加(新人员(“Jacob5”、“Smith5”、“jacob。smith@example.com"));