UITableView - 通过绑定更好地编辑?

发布于 2024-12-12 05:23:28 字数 293 浏览 0 评论 0原文

链接到问题: JavaFX 2:在 TableCell 中保存编辑

建立可编辑的表格视图似乎需要分配管道 -即捕获每个文本字段的所有事件(获得/失去焦点、从文本字段切换、将编辑从文本字段提交到底层数据模型),并重写表单元格。

建立编辑的默认行为(在单元格中双击)对于我或标准表格控件的用户来说似乎并不熟悉。大多数情况下,我只想单击单元格并开始输入。

有没有完全实现的例子?请添加您的意见或对设计此类生物的评论。

Linked to question: JavaFX 2: Save edit in TableCell

There seems to be allot of plumbing required for to establish an editable tableview - namely trapping all the events for each textField (gained/lost focus, tabbing away from the textField, commiting edits from the textField to the underlying data model), and overriding several methods in the the TableCell.

The default behavior to establish editing - doubleclicking in a cell - doesn't seem familiar to me or users of a standard table control. I just want to click into the cell and start typing, for the most part.

Are there any fully implemented examples out there? Please add yours, or comments for designing such a creature.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白衬杉格子梦 2024-12-19 05:23:28

我们不是响应 TableCellTableColumn 级别的多个事件来启动单元格编辑并成功更新单元格的基础数据,而是提供自定义单元格工厂和覆盖单元格中的 updateItem() 方法,并将 textField 的 textProperty 直接“绑定”到 TableView 数据模型内的属性(在本例中为 字符串属性)。我添加了其他美感,使单元格内的文本字段看起来无缝并响应悬停和聚焦状态。

所有的魔法都发生在 updateItem() 方法中。您必须跟踪 textField 及其绑定的内容 - TableView API 会“回收”TableCell 以减少内存消耗:

    @Override
    protected void updateItem(String item, boolean empty) {
      super.updateItem(item, empty);        
      if(!empty) {
        // Show the Text Field
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        // Retrieve the actual String Property that should be bound to the TextField
        // If the TextField is currently bound to a different StringProperty
        // Unbind the old property and rebind to the new one
        ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
        SimpleStringProperty sp = (SimpleStringProperty)ov;

        if(this.boundToCurrently==null) {
            this.boundToCurrently = sp;
            this.textField.textProperty().bindBidirectional(sp);
        }
        else {
            if(this.boundToCurrently != sp) {
              this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
              this.boundToCurrently = sp;
              this.textField.textProperty().bindBidirectional(this.boundToCurrently);
            }
        }
        System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
        //this.textField.setText(item);  // No longer need this!!!
      }
      else {
        this.setContentDisplay(ContentDisplay.TEXT_ONLY);
      }
    }

下面是一个包含 4 列的表格的完整示例,所有列都绑定到底层 textField。一旦您在文本字段中输入内容,Observable 列表中的基础数据模型就会更新:

package tablevieweditingwithbinding;

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
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.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
 *
 * @author jKaufmann
 */
public class TableViewEditingWithBinding extends Application {
  public static class TableData {
    private SimpleStringProperty firstName, lastName, phone, email;
    private ObjectProperty<SimpleStringProperty> firstNameObject;

    public TableData(String firstName, String lastName, String phone, String email) {
        this.firstName = new SimpleStringProperty(firstName);
        this.firstNameObject = new SimpleObjectProperty(firstNameObject);
        this.lastName = new SimpleStringProperty(lastName);
        this.phone = new SimpleStringProperty(phone);
        this.email = new SimpleStringProperty(email);
    }

    public String getEmail() {
        return email.get();
    }
    public void setEmail(String email) {
        this.email.set(email);
    }
    public SimpleStringProperty emailProperty() { return email; } 

    public String getFirstName() {
        return firstName.get();
    }
    public SimpleStringProperty getFirstNameObject() {
        return firstNameObject.get();
    }
    public void setFirstNameObject(SimpleStringProperty firstNameObject) {
        this.firstNameObject.set(firstNameObject);
    }
    public ObjectProperty<SimpleStringProperty> firstNameObjectProperty() { return firstNameObject; }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }
    public SimpleStringProperty firstNameProperty() { 
        return firstName; 
    }
    public String getLastName() {
        return lastName.get();
    }
    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }
    public SimpleStringProperty lastNameProperty() { return lastName; }

    public String getPhone() {
        return phone.get();
    }
    public void setPhone(String phone) {
        this.phone.set(phone);
    }
    public SimpleStringProperty phoneProperty() { return phone; }

  }
  public static class TextFieldCellFactory  
     implements Callback<TableColumn<TableData,String>,TableCell<TableData,String>> {

    @Override
    public TableCell<TableData, String> call(TableColumn<TableData, String> param) {
        TextFieldCell textFieldCell = new TextFieldCell();
        return textFieldCell;
    }

    public static class TextFieldCell extends TableCell<TableData,String> {
        private TextField textField;
        private StringProperty boundToCurrently = null;

        public TextFieldCell() {
          String strCss;
          // Padding in Text field cell is not wanted - we want the Textfield itself to "be"
          // The cell.  Though, this is aesthetic only.  to each his own.  comment out
          // to revert back.  
          strCss = "-fx-padding: 0;";


          this.setStyle(strCss);

          textField = new TextField();

          // 
          // Default style pulled from caspian.css. Used to play around with the inset background colors
          // ---trying to produce a text box without borders
          strCss = "" +
                    //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                    "-fx-background-color: -fx-control-inner-background;" +
                    //"-fx-background-insets: 0, 1, 2;" +
                    "-fx-background-insets: 0;" +
                    //"-fx-background-radius: 3, 2, 2;" +
                    "-fx-background-radius: 0;" +
                    "-fx-padding: 3 5 3 5;" +   /*Play with this value to center the text depending on cell height??*/
                    //"-fx-padding: 0 0 0 0;" +
                    "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                    "-fx-cursor: text;" +
                    "";
          // Focused and hover states should be set in the CSS.  This is just a test
          // to see what happens when we set the style in code
          textField.focusedProperty().addListener(new ChangeListener<Boolean>() {

            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                TextField tf = (TextField)getGraphic();
                String strStyleGotFocus = "-fx-background-color: purple, -fx-text-box-border, -fx-control-inner-background;" +
                            "-fx-background-insets: -0.4, 1, 2;" +
                            "-fx-background-radius: 3.4, 2, 2;";
                String strStyleLostFocus = //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                                   "-fx-background-color: -fx-control-inner-background;" +
                                 //"-fx-background-insets: 0, 1, 2;" +
                                   "-fx-background-insets: 0;" +
                                 //"-fx-background-radius: 3, 2, 2;" +
                                   "-fx-background-radius: 0;" +
                                   "-fx-padding: 3 5 3 5;" +   /**/
                                   //"-fx-padding: 0 0 0 0;" +
                                   "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                                   "-fx-cursor: text;" +
                                   "";
                if(newValue.booleanValue())
                  tf.setStyle(strStyleGotFocus);
                else
                  tf.setStyle(strStyleLostFocus);             
            }
          });
          textField.hoverProperty().addListener(new ChangeListener<Boolean>() {

            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                TextField tf = (TextField)getGraphic();
                String strStyleGotHover = "-fx-background-color: derive(purple,90%), -fx-text-box-border, derive(-fx-control-inner-background, 10%);" +
                            "-fx-background-insets: 1, 2.8, 3.8;" +
                            "-fx-background-radius: 3.4, 2, 2;";
                String strStyleLostHover = //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                                   "-fx-background-color: -fx-control-inner-background;" +
                                 //"-fx-background-insets: 0, 1, 2;" +
                                   "-fx-background-insets: 0;" +
                                 //"-fx-background-radius: 3, 2, 2;" +
                                   "-fx-background-radius: 0;" +
                                   "-fx-padding: 3 5 3 5;" +   /**/
                                   //"-fx-padding: 0 0 0 0;" +
                                   "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                                   "-fx-cursor: text;" +
                                   "";
                String strStyleHasFocus = "-fx-background-color: purple, -fx-text-box-border, -fx-control-inner-background;" +
                            "-fx-background-insets: -0.4, 1, 2;" +
                            "-fx-background-radius: 3.4, 2, 2;";
                if(newValue.booleanValue()) {
                  tf.setStyle(strStyleGotHover);
                }
                else {
                  if(!tf.focusedProperty().get()) {
                    tf.setStyle(strStyleLostHover);
                  }
                  else {
                    tf.setStyle(strStyleHasFocus);
                  }
                }

            }
          });
          textField.setStyle(strCss);
          this.setGraphic(textField);
        }

        @Override
        protected void updateItem(String item, boolean empty) {
          super.updateItem(item, empty);        
          if(!empty) {
            // Show the Text Field
            this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

            // Retrieve the actual String Property that should be bound to the TextField
            // If the TextField is currently bound to a different StringProperty
            // Unbind the old property and rebind to the new one
            ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
            SimpleStringProperty sp = (SimpleStringProperty)ov;

            if(this.boundToCurrently==null) {
                this.boundToCurrently = sp;
                this.textField.textProperty().bindBidirectional(sp);
            }
            else {
                if(this.boundToCurrently != sp) {
                  this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
                  this.boundToCurrently = sp;
                  this.textField.textProperty().bindBidirectional(this.boundToCurrently);
                }
            }
            System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
            //this.textField.setText(item);  // No longer need this!!!
          }
          else {
            this.setContentDisplay(ContentDisplay.TEXT_ONLY);
          }
        }

    }
  }
  public static void printNodeKidsRecursively(Node n, String tabs) {    
    String toTab = tabs == null ? "" : tabs;
    String msg1 = toTab + n.getClass().getName();
    String msg2 = ":" + n.toString();

    // Spit out and text data from Text classes
    if(javafx.scene.text.Text.class.isAssignableFrom(n.getClass())) {
        javafx.scene.text.Text t = (javafx.scene.text.Text)n;
        msg2 += " \"" +t.getText() + "\"";
    }

    // if this Node does not extend from Parent, then it can't have kids.
    if(!Parent.class.isAssignableFrom(n.getClass())) {
        System.out.println(msg1+msg2);
        return;
    }

    Parent p = (Parent)n;
    System.out.println(toTab + n.getClass().getName() + 
          "(KIDS=" + 
          Integer.toString(p.getChildrenUnmodifiable().size()) + ")" +
          msg2);

    ObservableList<Node> kids = p.getChildrenUnmodifiable();
    toTab +="  ";
    for(Node n2 : kids) {
        printNodeKidsRecursively(n2, toTab);
    }
  }

  private final TableView<TableData> table = new TableView<TableData>();
  final ObservableList<TableData> ol = 
        FXCollections.observableArrayList(
        new TableData("Wilma","Flintstone","555-123-4567","[email protected]"),
        new TableData("Fred","Flintstone","555-123-4567","[email protected]"),
        new TableData("Barney","Flintstone","555-123-4567","[email protected]"),
        new TableData("Bugs","Bunny","555-123-4567","[email protected]"),
        new TableData("Yo","Sam","555-123-4567","[email protected]"),
        new TableData("Tom","","555-123-4567","[email protected]"),
        new TableData("Jerry","","555-123-4567","[email protected]"),
        new TableData("Peter","Pan","555-123-4567","[email protected]"),
        new TableData("Daffy","Duck","555-123-4567","[email protected]"),
        new TableData("Tazmanian","Devil","555-123-4567","[email protected]"),
        new TableData("Mickey","Mouse","555-123-4567","[email protected]"),
        new TableData("Mighty","Mouse","555-123-4567","[email protected]")
        );

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage Stage) {    
    Stage.setTitle("Editable Table");
    BorderPane borderPane = new BorderPane();
    Scene scene = new Scene(borderPane, 800, 600);

    // top of border pane
    Button b1 = new Button("Print Scene Graph for table Node");
    Button b2 = new Button("Change value in table list");
    HBox hbox = new HBox(10);
    hbox.setStyle("-fx-background-color: #336699");
    hbox.setAlignment(Pos.BOTTOM_CENTER);
    HBox.setMargin(b2, new Insets(10,0,10,0));
    HBox.setMargin(b1, new Insets(10,0,10,0));
    hbox.getChildren().addAll(b1,b2);
    borderPane.setTop(hbox);
    BorderPane.setAlignment(hbox, Pos.CENTER);

    // Button Events
    b1.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
          printNodeKidsRecursively(table,"");
        }
    }); 
    b2.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
         String curFirstName = ol.get(0).getFirstName();
         if(curFirstName.contentEquals("Jason"))
             ol.get(0).setFirstName("Paul");
         else
             ol.get(0).setFirstName("Jason");
        }
    });

    table.setItems(ol);
    borderPane.setCenter(table);
    BorderPane.setAlignment(table, Pos.CENTER);
    BorderPane.setMargin(table, new Insets(25));

    // Add columns
    TableColumn<TableData,String> c1 = new TableColumn<TableData,String>("FirstName");
    c1.setCellValueFactory(new PropertyValueFactory<TableData,String>("firstName"));
    c1.setCellFactory(new TextFieldCellFactory());

    TableColumn<TableData,String> c2 = new TableColumn<TableData,String>("LastName");
    c2.setCellValueFactory(new PropertyValueFactory<TableData,String>("lastName"));
    c2.setCellFactory(new TextFieldCellFactory());

    TableColumn<TableData,String> c3 = new TableColumn<TableData,String>("Phone");
    c3.setCellValueFactory(new PropertyValueFactory<TableData,String>("phone"));
    c3.setCellFactory(new TextFieldCellFactory());

    TableColumn<TableData,String> c4 = new TableColumn<TableData,String>("Email");
    c4.setCellValueFactory(new PropertyValueFactory<TableData,String>("email"));
    c4.setCellFactory(new TextFieldCellFactory());

    table.getColumns().addAll(c1,c2,c3,c4);

    Stage.setScene(scene);
    Stage.show();

  }
}

Instead of responding to several events at the TableCell and TableColumn level to initiate editing of a cell, and successfully update the cell's underlying data - instead we provide a custom cell factory and override theupdateItem() method in the cell and 'bind' the textProperty of the textField directly to the property inside our data model for the TableView (in this case a StringProperty). I have added other aesthetics to make the textField inside the cell seem seamless and respond to hover and focused states.

All the magic happens in updateItem() method. You have to keep track of the textField and what it is bound to - the TableView API 'recycles' TableCells to reduce memory consumption:

    @Override
    protected void updateItem(String item, boolean empty) {
      super.updateItem(item, empty);        
      if(!empty) {
        // Show the Text Field
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        // Retrieve the actual String Property that should be bound to the TextField
        // If the TextField is currently bound to a different StringProperty
        // Unbind the old property and rebind to the new one
        ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
        SimpleStringProperty sp = (SimpleStringProperty)ov;

        if(this.boundToCurrently==null) {
            this.boundToCurrently = sp;
            this.textField.textProperty().bindBidirectional(sp);
        }
        else {
            if(this.boundToCurrently != sp) {
              this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
              this.boundToCurrently = sp;
              this.textField.textProperty().bindBidirectional(this.boundToCurrently);
            }
        }
        System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
        //this.textField.setText(item);  // No longer need this!!!
      }
      else {
        this.setContentDisplay(ContentDisplay.TEXT_ONLY);
      }
    }

Here is a full example of a table with 4 columns, all bound to the underlying textField. As soon as you type in the textField, the underlying data model in the Observable list is updated:

package tablevieweditingwithbinding;

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
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.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
 *
 * @author jKaufmann
 */
public class TableViewEditingWithBinding extends Application {
  public static class TableData {
    private SimpleStringProperty firstName, lastName, phone, email;
    private ObjectProperty<SimpleStringProperty> firstNameObject;

    public TableData(String firstName, String lastName, String phone, String email) {
        this.firstName = new SimpleStringProperty(firstName);
        this.firstNameObject = new SimpleObjectProperty(firstNameObject);
        this.lastName = new SimpleStringProperty(lastName);
        this.phone = new SimpleStringProperty(phone);
        this.email = new SimpleStringProperty(email);
    }

    public String getEmail() {
        return email.get();
    }
    public void setEmail(String email) {
        this.email.set(email);
    }
    public SimpleStringProperty emailProperty() { return email; } 

    public String getFirstName() {
        return firstName.get();
    }
    public SimpleStringProperty getFirstNameObject() {
        return firstNameObject.get();
    }
    public void setFirstNameObject(SimpleStringProperty firstNameObject) {
        this.firstNameObject.set(firstNameObject);
    }
    public ObjectProperty<SimpleStringProperty> firstNameObjectProperty() { return firstNameObject; }

    public void setFirstName(String firstName) {
        this.firstName.set(firstName);
    }
    public SimpleStringProperty firstNameProperty() { 
        return firstName; 
    }
    public String getLastName() {
        return lastName.get();
    }
    public void setLastName(String lastName) {
        this.lastName.set(lastName);
    }
    public SimpleStringProperty lastNameProperty() { return lastName; }

    public String getPhone() {
        return phone.get();
    }
    public void setPhone(String phone) {
        this.phone.set(phone);
    }
    public SimpleStringProperty phoneProperty() { return phone; }

  }
  public static class TextFieldCellFactory  
     implements Callback<TableColumn<TableData,String>,TableCell<TableData,String>> {

    @Override
    public TableCell<TableData, String> call(TableColumn<TableData, String> param) {
        TextFieldCell textFieldCell = new TextFieldCell();
        return textFieldCell;
    }

    public static class TextFieldCell extends TableCell<TableData,String> {
        private TextField textField;
        private StringProperty boundToCurrently = null;

        public TextFieldCell() {
          String strCss;
          // Padding in Text field cell is not wanted - we want the Textfield itself to "be"
          // The cell.  Though, this is aesthetic only.  to each his own.  comment out
          // to revert back.  
          strCss = "-fx-padding: 0;";


          this.setStyle(strCss);

          textField = new TextField();

          // 
          // Default style pulled from caspian.css. Used to play around with the inset background colors
          // ---trying to produce a text box without borders
          strCss = "" +
                    //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                    "-fx-background-color: -fx-control-inner-background;" +
                    //"-fx-background-insets: 0, 1, 2;" +
                    "-fx-background-insets: 0;" +
                    //"-fx-background-radius: 3, 2, 2;" +
                    "-fx-background-radius: 0;" +
                    "-fx-padding: 3 5 3 5;" +   /*Play with this value to center the text depending on cell height??*/
                    //"-fx-padding: 0 0 0 0;" +
                    "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                    "-fx-cursor: text;" +
                    "";
          // Focused and hover states should be set in the CSS.  This is just a test
          // to see what happens when we set the style in code
          textField.focusedProperty().addListener(new ChangeListener<Boolean>() {

            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                TextField tf = (TextField)getGraphic();
                String strStyleGotFocus = "-fx-background-color: purple, -fx-text-box-border, -fx-control-inner-background;" +
                            "-fx-background-insets: -0.4, 1, 2;" +
                            "-fx-background-radius: 3.4, 2, 2;";
                String strStyleLostFocus = //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                                   "-fx-background-color: -fx-control-inner-background;" +
                                 //"-fx-background-insets: 0, 1, 2;" +
                                   "-fx-background-insets: 0;" +
                                 //"-fx-background-radius: 3, 2, 2;" +
                                   "-fx-background-radius: 0;" +
                                   "-fx-padding: 3 5 3 5;" +   /**/
                                   //"-fx-padding: 0 0 0 0;" +
                                   "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                                   "-fx-cursor: text;" +
                                   "";
                if(newValue.booleanValue())
                  tf.setStyle(strStyleGotFocus);
                else
                  tf.setStyle(strStyleLostFocus);             
            }
          });
          textField.hoverProperty().addListener(new ChangeListener<Boolean>() {

            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                TextField tf = (TextField)getGraphic();
                String strStyleGotHover = "-fx-background-color: derive(purple,90%), -fx-text-box-border, derive(-fx-control-inner-background, 10%);" +
                            "-fx-background-insets: 1, 2.8, 3.8;" +
                            "-fx-background-radius: 3.4, 2, 2;";
                String strStyleLostHover = //"-fx-background-color: -fx-shadow-highlight-color, -fx-text-box-border, -fx-control-inner-background;" +
                                   "-fx-background-color: -fx-control-inner-background;" +
                                 //"-fx-background-insets: 0, 1, 2;" +
                                   "-fx-background-insets: 0;" +
                                 //"-fx-background-radius: 3, 2, 2;" +
                                   "-fx-background-radius: 0;" +
                                   "-fx-padding: 3 5 3 5;" +   /**/
                                   //"-fx-padding: 0 0 0 0;" +
                                   "-fx-prompt-text-fill: derive(-fx-control-inner-background,-30%);" +
                                   "-fx-cursor: text;" +
                                   "";
                String strStyleHasFocus = "-fx-background-color: purple, -fx-text-box-border, -fx-control-inner-background;" +
                            "-fx-background-insets: -0.4, 1, 2;" +
                            "-fx-background-radius: 3.4, 2, 2;";
                if(newValue.booleanValue()) {
                  tf.setStyle(strStyleGotHover);
                }
                else {
                  if(!tf.focusedProperty().get()) {
                    tf.setStyle(strStyleLostHover);
                  }
                  else {
                    tf.setStyle(strStyleHasFocus);
                  }
                }

            }
          });
          textField.setStyle(strCss);
          this.setGraphic(textField);
        }

        @Override
        protected void updateItem(String item, boolean empty) {
          super.updateItem(item, empty);        
          if(!empty) {
            // Show the Text Field
            this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

            // Retrieve the actual String Property that should be bound to the TextField
            // If the TextField is currently bound to a different StringProperty
            // Unbind the old property and rebind to the new one
            ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
            SimpleStringProperty sp = (SimpleStringProperty)ov;

            if(this.boundToCurrently==null) {
                this.boundToCurrently = sp;
                this.textField.textProperty().bindBidirectional(sp);
            }
            else {
                if(this.boundToCurrently != sp) {
                  this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
                  this.boundToCurrently = sp;
                  this.textField.textProperty().bindBidirectional(this.boundToCurrently);
                }
            }
            System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
            //this.textField.setText(item);  // No longer need this!!!
          }
          else {
            this.setContentDisplay(ContentDisplay.TEXT_ONLY);
          }
        }

    }
  }
  public static void printNodeKidsRecursively(Node n, String tabs) {    
    String toTab = tabs == null ? "" : tabs;
    String msg1 = toTab + n.getClass().getName();
    String msg2 = ":" + n.toString();

    // Spit out and text data from Text classes
    if(javafx.scene.text.Text.class.isAssignableFrom(n.getClass())) {
        javafx.scene.text.Text t = (javafx.scene.text.Text)n;
        msg2 += " \"" +t.getText() + "\"";
    }

    // if this Node does not extend from Parent, then it can't have kids.
    if(!Parent.class.isAssignableFrom(n.getClass())) {
        System.out.println(msg1+msg2);
        return;
    }

    Parent p = (Parent)n;
    System.out.println(toTab + n.getClass().getName() + 
          "(KIDS=" + 
          Integer.toString(p.getChildrenUnmodifiable().size()) + ")" +
          msg2);

    ObservableList<Node> kids = p.getChildrenUnmodifiable();
    toTab +="  ";
    for(Node n2 : kids) {
        printNodeKidsRecursively(n2, toTab);
    }
  }

  private final TableView<TableData> table = new TableView<TableData>();
  final ObservableList<TableData> ol = 
        FXCollections.observableArrayList(
        new TableData("Wilma","Flintstone","555-123-4567","[email protected]"),
        new TableData("Fred","Flintstone","555-123-4567","[email protected]"),
        new TableData("Barney","Flintstone","555-123-4567","[email protected]"),
        new TableData("Bugs","Bunny","555-123-4567","[email protected]"),
        new TableData("Yo","Sam","555-123-4567","[email protected]"),
        new TableData("Tom","","555-123-4567","[email protected]"),
        new TableData("Jerry","","555-123-4567","[email protected]"),
        new TableData("Peter","Pan","555-123-4567","[email protected]"),
        new TableData("Daffy","Duck","555-123-4567","[email protected]"),
        new TableData("Tazmanian","Devil","555-123-4567","[email protected]"),
        new TableData("Mickey","Mouse","555-123-4567","[email protected]"),
        new TableData("Mighty","Mouse","555-123-4567","[email protected]")
        );

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage Stage) {    
    Stage.setTitle("Editable Table");
    BorderPane borderPane = new BorderPane();
    Scene scene = new Scene(borderPane, 800, 600);

    // top of border pane
    Button b1 = new Button("Print Scene Graph for table Node");
    Button b2 = new Button("Change value in table list");
    HBox hbox = new HBox(10);
    hbox.setStyle("-fx-background-color: #336699");
    hbox.setAlignment(Pos.BOTTOM_CENTER);
    HBox.setMargin(b2, new Insets(10,0,10,0));
    HBox.setMargin(b1, new Insets(10,0,10,0));
    hbox.getChildren().addAll(b1,b2);
    borderPane.setTop(hbox);
    BorderPane.setAlignment(hbox, Pos.CENTER);

    // Button Events
    b1.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
          printNodeKidsRecursively(table,"");
        }
    }); 
    b2.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {
         String curFirstName = ol.get(0).getFirstName();
         if(curFirstName.contentEquals("Jason"))
             ol.get(0).setFirstName("Paul");
         else
             ol.get(0).setFirstName("Jason");
        }
    });

    table.setItems(ol);
    borderPane.setCenter(table);
    BorderPane.setAlignment(table, Pos.CENTER);
    BorderPane.setMargin(table, new Insets(25));

    // Add columns
    TableColumn<TableData,String> c1 = new TableColumn<TableData,String>("FirstName");
    c1.setCellValueFactory(new PropertyValueFactory<TableData,String>("firstName"));
    c1.setCellFactory(new TextFieldCellFactory());

    TableColumn<TableData,String> c2 = new TableColumn<TableData,String>("LastName");
    c2.setCellValueFactory(new PropertyValueFactory<TableData,String>("lastName"));
    c2.setCellFactory(new TextFieldCellFactory());

    TableColumn<TableData,String> c3 = new TableColumn<TableData,String>("Phone");
    c3.setCellValueFactory(new PropertyValueFactory<TableData,String>("phone"));
    c3.setCellFactory(new TextFieldCellFactory());

    TableColumn<TableData,String> c4 = new TableColumn<TableData,String>("Email");
    c4.setCellValueFactory(new PropertyValueFactory<TableData,String>("email"));
    c4.setCellFactory(new TextFieldCellFactory());

    table.getColumns().addAll(c1,c2,c3,c4);

    Stage.setScene(scene);
    Stage.show();

  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文