Binding UITableView-通过绑定进行更好的编辑?
链接到问题: 建立可编辑的tableview似乎需要分配管道——即捕获每个textField的所有事件(获得/失去焦点、从textField切换、将编辑从textField提交到基础数据模型),以及覆盖TableCell中的几个方法 建立编辑的默认行为—在单元格中双击—对于我或标准表控件的用户来说似乎并不熟悉。我只想点击单元格并开始打字,大部分情况下Binding UITableView-通过绑定进行更好的编辑?,binding,tableview,javafx,javafx-2,Binding,Tableview,Javafx,Javafx 2,链接到问题: 建立可编辑的tableview似乎需要分配管道——即捕获每个textField的所有事件(获得/失去焦点、从textField切换、将编辑从textField提交到基础数据模型),以及覆盖TableCell中的几个方法 建立编辑的默认行为—在单元格中双击—对于我或标准表控件的用户来说似乎并不熟悉。我只想点击单元格并开始打字,大部分情况下 有没有完全实现的例子?请为设计这样的生物添加您的意见或评论 我们没有在TableCell和TableColumn级别响应多个事件来启动单元格编辑,
有没有完全实现的例子?请为设计这样的生物添加您的意见或评论 我们没有在
TableCell
和TableColumn
级别响应多个事件来启动单元格编辑,并成功更新单元格的基础数据,而是提供一个自定义单元格工厂并覆盖updateItem()
方法,并将textField的textProperty直接“绑定”到TableView
的数据模型内的属性(在本例中为StringProperty
)。我还添加了其他美学元素,使单元格内的文本字段看起来天衣无缝,并对悬停和聚焦状态做出响应
所有的神奇都发生在updateItem()
方法中。您必须跟踪textField及其绑定内容-TableView API“回收”TableCells以减少内存消耗:
@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);
}
}
@覆盖
受保护的void updateItem(字符串项,布尔值为空){
super.updateItem(项,空);
如果(!空){
//显示文本字段
此.setContentDisplay(仅限ContentDisplay.GRAPHIC_);
//检索应绑定到TextField的实际字符串属性
//如果TextField当前绑定到其他StringProperty
//解除旧属性的绑定并重新绑定到新属性
ObservableValue ov=getTableColumn().getCellObservableValue(getIndex());
SimpleStringProperty sp=(SimpleStringProperty)ov;
if(this.boundToCurrent==null){
this.boundtocurrency=sp;
this.textField.textProperty().bindbiodic(sp);
}
否则{
if(this.boundTocurrent!=sp){
this.textField.textProperty();
this.boundtocurrency=sp;
this.textField.textProperty();
}
}
System.out.println(“item=“+item+”observeValue=“+ov.getValue());
//this.textField.setText(项目);//不再需要这个!!!
}
否则{
this.setContentDisplay(仅限ContentDisplay.TEXT_);
}
}
下面是一个包含4列的表的完整示例,所有列都绑定到基础textField。键入文本字段后,可观察列表中的基础数据模型将立即更新:
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","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);
}
@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();
}
}
package tablevieweditingwithbinding;
导入javafx.application.application;
导入javafx.beans.property.ObjectProperty;
导入javafx.beans.property.SimpleObject属性;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.Node;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.*;
导入javafx.scene.control.cell.PropertyValueFactory;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.layout.HBox;
导入javafx.stage.stage;
导入javafx.util.Callback;
/**
*
*@作者jKaufmann
*/
公共类TableViewEditingWithBinding扩展了应用程序{
公共静态类TableData{
私有SimpleStringProperty名字、姓氏、电话、电子邮件;
私有对象属性firstNameObject;
公共表数据(字符串firstName、字符串lastName、字符串phone、字符串email){
this.firstName=新的SimpleStringProperty(firstName);
this.firstNameObject=新的SimpleObject属性(firstNameObject);
this.lastName=新的SimpleStringProperty(lastName);
this.phone=新的SimpleStringProperty(电话);
this.email=新的SimpleStringProperty(电子邮件);
}
公共字符串getEmail(){
返回email.get();
}
公用电子邮件(字符串电子邮件){
this.email.set(email);
}
公共SimpleStringProperty emailProperty(){return email;}
公共字符串getFirstName(){
返回firstName.get();
}
公共SimpleStringProperty getFirstNameObject(){
返回firstNameObject.get();
}
公共void setFirstNameObject(SimpleStringProperty firstNameObject){
this.firstNameObject.set(firstNameObject);
}
public ObjectProperty firstNameObjectProperty(){return firstNameObject;}
public void setFirstName(字符串firstName){
this.firstName.set(firstName);
}
公共SimpleStringProperty firstNameProperty(){
返回名字;
}
公共字符串getLastName(){
返回lastName.get();
}
public void setLastName(字符串lastName){
this.lastName.set(lastName);
}
公共SimpleStringProperty lastNameProperty(){return lastName;}
公共字符串getPhone(){
返回电话。get();
}
公用无效设置电话(字符串电话){
this.phone.set(电话);
}
公共SimpleStringProperty phoneProperty(){return phone;}
}
公共静态类TextFieldCellFactory
实现回调{
@凌驾
公共TableCell调用(TableColumn参数){
TextFieldCell TextFieldCell=新的TextFieldCell();
返回文本字段单元格;
}
公共静态类