2014-02-09 3 views
1

Мне нужен TableView с редактированием.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", "[email protected]")); 
        persons.add(new Person("Isabella", "Johnson", "[email protected]")); 
        persons.add(new Person("Ethan", "Williams", "[email protected]")); 
        persons.add(new Person("Jacob2", "Smith2", "[email protected]")); 
        persons.add(new Person("Isabella2", "Johnson2", "[email protected]")); 
        persons.add(new Person("Ethan2", "Williams2", "[email protected]")); 
        persons.add(new Person("Jacob3", "Smith3", "[email protected]")); 
        persons.add(new Person("Isabella3", "Johnson3", "[email protected]")); 
        persons.add(new Person("Ethan3", "Williams3", "[email protected]")); 
        persons.add(new Person("Jacob4", "Smith4", "[email protected]")); 
        persons.add(new Person("Isabella4", "Johnson4", "[email protected]")); 
        persons.add(new Person("Ethan4", "Williams4", "[email protected]")); 
        persons.add(new Person("Jacob5", "Smith5", "[email protected]")); 
        persons.add(new Person("Isabella5", "Johnson5", "[email protected]")); 
        persons.add(new Person("Ethan5", "Williams5", "[email protected]")); 
        persons.add(new Person("Jacob6", "Smith6", "[email protected]")); 
        persons.add(new Person("Isabella6", "Johnson6", "[email protected]")); 
        persons.add(new Person("Ethan6", "Williams6", "[email protected]")); 

       } 
       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("[email protected]"); 
       } 
      } 
     }); 

     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("[]")){ 
         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

ответ

0

После некоторых поисков я еще думаю, Попробую из комбинации GridPane VBox &. Документация TableView гласит: «Элемент управления TableView предназначен для VISUALIZE (не вводить) неограниченное количество строк данных» и «Если вы хотите разместить свой пользовательский интерфейс в виде сетки, рассмотрите макет GridPane».

Смежные вопросы