- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
链接到问题:JavaFX 2: Save edit in TableCell
建立一个可编辑的 tableview 似乎需要大量的管道 - 即捕获每个 textField 的所有事件(获得/失去焦点,从 textField 切换,从 textField 提交编辑到底层数据模型),并覆盖几个TableCell 中的方法。
建立编辑的默认行为 - 在单元格中双击 - 我或标准表格控件的用户似乎并不熟悉。在大多数情况下,我只想单击单元格并开始输入。
有没有完全实现的例子?请添加您的或评论以设计这样的生物。
最佳答案
而不是响应 TableCell
和 TableColumn
级别的几个事件来启动单元格的编辑,并成功更新单元格的底层数据 - 相反,我们提供自定义单元格工厂并覆盖单元格中的 updateItem()
方法并“绑定(bind)” textField 直接添加到 TableView
数据模型中的属性(在本例中为 StringProperty
)。我添加了其他美学,使单元格内的 textField 看起来无缝并响应悬停和聚焦状态。
所有的魔法都发生在 updateItem()
方法中。您必须跟踪 textField 及其绑定(bind)的内容 - 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);
}
}
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();
}
}
关于binding - UITableView - 通过绑定(bind)更好地编辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7880494/
我有一个 foo 类,它有一个 bar 方法,它接受可调用的东西(函数指针/仿函数)。这个可调用的东西应该作为绑定(bind)元素传递给另一个方法 doit 和第三个方法 bar_cb 方法。 #in
我正在尝试在我的 WPF 4.0 应用程序(使用 VS 2010 Pro RTM)中创建自定义 TabItem 模板/样式,但尽管一切似乎都正常工作,但我注意到跟踪窗口中存在绑定(bind)错误。 我
作为一名刚接触 Android 的开发人员,我想我可能误解了绑定(bind)服务。 我创建了一项服务来结束对服务器的访问。作为此服务的一部分,该服务正在监听多播地址,以识别本地网络上的设备何时出现和消
这个问题在这里已经有了答案: What is the use of the JavaScript 'bind' method? (23 个回答) 关闭 7 年前。 所以我一直在尝试了解一些 JS 上
我不明白这三种语法之间的区别: where a = f (b) do a <- f (b) do let a = f (b) 我确实明白了a <- f(b)与其他两个不同,在大多数情况下,我尝试了所有
我在将 Cocoa 项目从手动同步接口(interface)模型转换为绑定(bind)模型时遇到问题,这样我就不必担心接口(interface)粘合代码。 我关注了 CocoaDevCentral C
我正在尝试找出一种好的方法来对处理大数据集的代码进行并行化,然后将结果数据导入 RavenDb。 数据处理受 CPU 限制和数据库导入 IO 限制。 我正在寻找一种解决方案,以对 Environmen
我正在 foreach 循环中生成单选按钮。我试图将选中的属性绑定(bind)到父级中的基本可观察值。不幸的是,当单击单选按钮时,父级的属性似乎没有在单击处理程序中更新。 基于一些previous w
在我的 Windows Phone 应用程序中,我有两个 LongListSelectors并排在页面上。我想做到这一点,以便当用户滚动其中一个时,另一个滚动相同的量。 两个 LongListSele
我在网上看到这个问题准备面试: Given a non-preemptive kernel which type of process will get affected morein terms o
我有一个 foreach 绑定(bind),如下所示: Summary Permitting 原因是有两个选项卡始终存在,并且我根据是否添加了其他选项卡来添加其他选项
任何人都有绑定(bind)相同的情况DataContext到 TextBlock 中的 Text 属性(例如)。 我必须分配 DataContext以我的风格反射(reflect)基于 Datacon
给定以下代码: Login 和下面的javascript $(function () { $('#btnLogin').click(function () { co
我使用 boost::asio 创建了一个服务器。我在绑定(bind)到端点时遇到问题。所以,如果我在构造函数中初始化一个接受器: Server::Server(QWidget *parent) :
我正在将现有项目从 MySQL 转换为 Postgres。代码中有相当多的原始 SQL 文字使用 ? 作为占位符,例如 SELECT id FROM users WHERE
似乎在绑定(bind)某些数据时出错了,有人可以帮我解决我哪里出错了,尽管我无法弄清楚。 真的不需要在这里显示太多,这是 Binding,我已经通过移除背景并在其中放置颜色来测试背景,效果很好。 编辑
我正在尝试使用 wcf 构建一个 http 监听器(web 服务)。这个监听器是一个更大的桌面应用程序的一部分。此桌面应用程序还会调用 http 监听器。 当监听器接收到数据时,它应该被传递到桌面应用
嘿嘿。 我正在使用 Node.JS 和 child_process 来生成 bash 进程。我试图了解我是否正在执行 I/O 绑定(bind)、CPU 绑定(bind)或两者兼而有之。 我正在使用 p
尝试执行以下操作并出现“Got interpolation ({{}}) where expression was expected”错误。 {{item.name}} 谢谢!
我有一个导入的 Java 库,它是我解决方案中的“绑定(bind)库”项目。 我正在尝试从解决方案中的另一个项目绑定(bind)到第 3 方库中的服务。 第 3 方库文档 [在 java 中] 非常简
我是一名优秀的程序员,十分优秀!