我正在尝试修改UITableView - Better Editing through Binding?中所述的解决方案(谢谢你,jKaufmann,这个优秀的例子),允许在表格中添加行。
我已经引入了一个按钮,当单击该按钮时,会调用代码将其他TableData行添加到支持该表的ObservableList中。
新行显示没有意外。但是,添加几行并使用向上/向下键几次滚动表后,表中的随机行开始被替换为空行。
通常需要添加几行,选择一行,沿着列表(使用键盘)遍历新行,再添加几行,遍历到新行,再一直到顶部再现问题。要选择表格中的行,我单击行的边缘,以便选择行而不是单个单元格。
源代码(基本上jkaufmann的示例已修改为包含“添加行”按钮)在此处。
package tablevieweditingwithbinding;
import javafx.application.Application;
import javafx.application.Platform;
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;
public class TableViewEditingExample2 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;";
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: transparent;"
+ //"-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-accent: derive(-fx-control-inner-background, -40%);" +
"-fx-cell-hover-color: derive(-fx-control-inner-background, -20%);"
+ "-fx-cursor: text;"
+ "";
//
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: transparent;"
+ //"-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-background-fill: green;" + /**/
//"-fx-background-color: green;" +
"-fx-background-opacity: 0;"
+ //"-fx-opacity: 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);
}
}
});
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());
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
}
private final TableView<TableData> table = new TableView<TableData>();
final ObservableList<TableData> ol =
FXCollections.observableArrayList(
new TableData("Wilma", "Flintstone", "555-123-4567", "WFlintstone@gmail.com"),
new TableData("Fred", "Flintstone", "555-123-4567", "FFlintstone@gmail.com"),
new TableData("Barney", "Flintstone", "555-123-4567", "Barney@gmail.com"),
new TableData("Bugs", "Bunny", "555-123-4567", "BugsB@gmail.com"),
new TableData("Yo", "Sam", "555-123-4567", "ysam@gmail.com"),
new TableData("Tom", "", "555-123-4567", "tom@gmail.com"),
new TableData("Jerry", "", "555-123-4567", "Jerry@gmail.com"),
new TableData("Peter", "Pan", "555-123-4567", "Ppan@gmail.com"),
new TableData("Daffy", "Duck", "555-123-4567", "dduck@gmail.com"),
new TableData("Tazmanian", "Devil", "555-123-4567", "tdevil@gmail.com"),
new TableData("Mickey", "Mouse", "555-123-4567", "mmouse@gmail.com"),
new TableData("Mighty", "Mouse", "555-123-4567", "mimouse@gmail.com"));
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(args);
}
static int counter = 1;
@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("Change value in table list");
Button b2 = new Button("Add row");
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>() {
@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");
}
}
});
b2.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
Platform.runLater(new Runnable() {
@Override
public void run() {
int dataListSize = 0;
dataListSize = ol.size();
System.out.println("Table size = " + dataListSize);
ol.add(new TableData("firstName" + counter,
"lastName" + counter,
"phone" + counter,
"email" + counter++));
dataListSize = ol.size();
System.out.println("Table size = " + dataListSize);
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
}
});
}
});
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
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);
scene.getStylesheets().add(TableViewEditingWithBinding.class.getResource("styles.css").toExternalForm());
Stage.setScene(scene);
Stage.show();
}
}
我尝试添加以下代码
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
在添加行之后addRow按钮的处理程序中,但是没有任何帮助。 我还尝试清除后备可观察列表,并在添加每行后将值重置为列表+新行;这也没有解决问题。
任何帮助都将非常感激。
答案 0 :(得分:0)
我遇到了同样的问题。删除一行后,其他一些行将被清空。如果我滚动了空白行改变了。
我的解决方案是移动线
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
到单元格的构造函数并删除行
setContentDisplay(ContentDisplay.TEXT_ONLY);
完全。
Cell.updateItem
州的API文档
empty
- 此单元格是否表示列表中的数据。如果它为空,则它不表示任何域数据,而是用于呈现“空”行的单元格。
对我而言,这看起来像是JavaFX中的一个错误,因为我的所有行都支持域数据,但其中一些(滚动时更改)会收到updateItem()
empty=true
。