编辑表的javafx绑定代码片段对我不起作用

时间:2016-04-11 18:23:05

标签: javafx classcastexception

我使用此代码段来完成我的表的编辑提交。 UITableView - Better Editing through Binding?

我的问题是我得到了

Caused by: java.lang.ClassCastException: javafx.beans.property.ReadOnlyObjectWrapper cannot be cast to javafx.beans.property.SimpleStringProperty

在这一行:

     SimpleStringProperty sp = (SimpleStringProperty)ov;

我不知道我能做些什么。 我只使用SimpleStringProperty值作为我的数据类。

以下是完整代码:

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.util.Callback;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Supermain extends Application {



    @Override
    public void start(Stage primaryStage) {

        final TableView<myTextRow> table = new TableView<>();
        table.setEditable(true);
        table.setStyle("-fx-text-wrap: true;");

        //Table columns
        TableColumn<myTextRow, String> clmID = new TableColumn<>("ID");
        clmID.setMinWidth(160);
        clmID.setCellValueFactory(new PropertyValueFactory<>("ID"));


        TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
        clmtext.setMinWidth(160);
        clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
        clmtext.setCellFactory(new TextFieldCellFactory());

        //Add data
        final ObservableList<myTextRow> data = FXCollections.observableArrayList(
                new myTextRow(5, "Lorem"),
                new myTextRow(2, "Ipsum")
        );
        table.setItems(data);
        table.getColumns().addAll(clmID, clmtext);

        HBox hBox = new HBox();
        hBox.setSpacing(5.0);
        hBox.setPadding(new Insets(5, 5, 5, 5));

        Button btn = new Button();
        btn.setText("Get Data");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                for (myTextRow data1 : data) {
                    System.out.println("data:"+data1.getText());
                }
            }
        });

        hBox.getChildren().add(btn);


        BorderPane pane = new BorderPane();
        pane.setTop(hBox);
        pane.setCenter(table);
        primaryStage.setScene(new Scene(pane, 640, 480));
        primaryStage.show();

    }

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

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


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

        public static class TextFieldCell extends TableCell<myTextRow, String> {

            private TextArea 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 TextArea();
                textField.setWrapText(true);
                textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);



                //textField.setPrefHeight(real_lines_height(textField.getText(),this.getWidth(),30,23));
                // 
                // 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;"
                        + /*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>() {
                    @Override
                    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                        TextArea tf = (TextArea) getGraphic();
                        // System.out.println(".changed() index : "+  get_ID_from_table_index(getIndex()));

                        String strStyleGotFocus = "-fx-background-color: blue, -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-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);
                        }

                        if(!newValue)
                        {                                                                          


                            System.out.println("EDITABLE???? "+isEditing());
                           System.out.println("TEXT:::: "+textField.getText());
                        //    commitEdit(textField.getText());

                        }

                    }
                });
                textField.hoverProperty().addListener(new ChangeListener<Boolean>() {

                    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {

                        TextArea tf = (TextArea) getGraphic();
                        String strStyleGotHover = "-fx-background-color: derive(blue,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: blue, -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.textProperty().addListener(e -> {
                    double height = 25;
                    textField.setPrefHeight(height);
                    textField.setMaxHeight(height);


                    //System.out.println("textfield Parent: "+textField.getParent().toString()); 
                });
                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 class myTextRow {

        private final SimpleIntegerProperty ID;

        private final SimpleStringProperty text;

        public myTextRow(int ID, String text) {

            this.ID = new SimpleIntegerProperty(ID);
            this.text = new SimpleStringProperty(text);

        }

        public void setID(int id) {
            this.ID.set(id);
        }

        public void setText(String text) {
            this.text.set(text);
        }

        public int getID() {
            return ID.get();
        }

        public String getText() {
            return text.get();
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您的模型类缺少&#34;属性访问器&#34;。因此,PropertyValueFactory无法使用属性本身。如PropertyValueFactory documentation中所述:

  

如何使用此类的示例如下:

TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name"); 
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName"));   
     

在这个例子中,   "firstName"字符串用作对假设的引用   firstNameProperty()类类型中的Person方法(即{。}}   TableView项列表的类类型)。另外,这种方法   必须返回一个Property实例。如果满足这些方法   找到需求,然后填充TableCell   ObservableValue。另外,TableView会自动添加一个   观察者返回的值,以便触发任何更改   通过TableView观察,导致细胞立即更新。

     

如果不存在与此模式匹配的方法,则存在漏洞   支持尝试调用get()或is()(即   是,上例中的getFirstName()isFirstName()。如果一个方法   如果匹配此模式,则此方法返回的值为   包裹在ReadOnlyObjectWrapper中并返回TableCell

最后一段描述了您的情况,因为您的模型类中没有定义textProperty()iDProperty()方法。因此PropertyValueFactory为您创建ReadOnlyObjectWrapper并返回它,而不是返回实际的属性实例。

另请注意,id列的类型错误。该属性为IntegerProperty,为Property<Number>,而非Property<String>。因此,该表列必须是TableColumn<myTextRow, Number>。这将使得使用表格单元格实现变得相当棘手,因为您需要在文本字段中的字符串和作为id的值的整数之间进行转换。

一般情况下,按照JavaFX Property pattern编写类,如下所示:

public class myTextRow {

    private final IntegerProperty id;

    private final StringProperty text;

    public myTextRow(int ID, String text) {

        this.id = new SimpleIntegerProperty(ID);
        this.text = new SimpleStringProperty(text);

    }

    public void setId(int id) {
        this.id.set(id);
    }

    public void setText(String text) {
        this.text.set(text);
    }

    public int getId() {
        return id.get();
    }

    public String getText() {
        return text.get();
    }

    public StringProperty textProperty() {
        return text;
    }

    public IntegerProperty idProperty() {
        return id ;
    }
}

然后您可以将单元格值工厂定义为

TableColumn<myTextRow, Number> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(new PropertyValueFactory<>("id"));


TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));

或者,使用lambda表达式(使代码类型安全并允许编译器检查是否存在正确的方法):

TableColumn<myTextRow, Number> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(cellData -> cellData.getValue().idProperty());


TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(cellData -> cellData.getValue().textProperty());