我使用此代码段来完成我的表的编辑提交。 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();
}
}
}
答案 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());