TableView与单元格编辑

时间:2014-02-09 22:49:02

标签: 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);}
}

enter image description here

1 个答案:

答案 0 :(得分:0)

经过一番搜索,我想我会尝试一下VBox&amp; GridPane组合。 TableView文档说“TableView控件设计为VISUALIZE(不输入)无限数量的数据行”和“如果你想以类似网格的方式放置用户界面,请考虑GridPane布局。”