在我的TableView
中,TableCol列
值之一是观察列表
。为了简化事情,它只包含StringProperty
值。在我的列的单元格值工厂中,我使用Bindings
类将这些值连接在一起。
我想要的结果应该是一个StringExpression,它会在ObservableList更改时更新。
我遇到的问题是,当列表中的任何值发生更改时,生成的StringExpression会正确更新,但当我向列表中添加或删除值时,它不会更新。
我的第一个想法是向行中添加一个ListChangeListener,但这似乎不切实际,因为表中可能有几十行或数百行。
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TestFx extends Application {
@Override
public void start(Stage primaryStage) {
//Note, I never really see this "row" value directly, they're loaded
//in from a database, and there can be dozens or hundreds of
//rows for the table, so I don't if adding a listener to each one
//is the best idea.
final ObservableList<StringProperty> row = FXCollections.observableArrayList();
row.add(new SimpleStringProperty("test"));
row.add(new SimpleStringProperty("one"));
row.add(new SimpleStringProperty("two"));
TableView<ObservableList<StringProperty>> table = new TableView();
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
TableColumn<ObservableList<StringProperty>, String> concatColumns = new TableColumn<>("Concatentated Values");
concatColumns.setCellValueFactory(new Callback<CellDataFeatures<ObservableList<StringProperty>, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(CellDataFeatures<ObservableList<StringProperty>, String> p) {
ObservableList<StringProperty> row = p.getValue();
List toConcat = new ArrayList();
for (int i = 0; i < row.size(); i++) {
toConcat.add(row.get(i));
if (i+1 < row.size()) {
toConcat.add(", ");
}
}
return Bindings.concat(toConcat.toArray());
}
});
table.getColumns().add(concatColumns);
table.getItems().add(row);
BorderPane root = new BorderPane();
HBox buttons = new HBox();
Button add = new Button();
add.setText("Add Item");
add.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
row.add(new SimpleStringProperty("added"));
}
});
Button remove = new Button();
remove.setText("Remove Item");
remove.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (row.size() > 0) {
row.remove(0);
}
}
});
Button change = new Button();
change.setText("Change Item");
change.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if (row.size() > 0) {
row.get(0).set("Changed");
}
}
});
buttons.getChildren().addAll(add, remove, change);
root.setCenter(table);
root.setBottom(buttons);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我知道“为什么”它不起作用。StringExpression链接到列表的StringProperty值,而不是列表本身。因此,每当我添加/删除值时,它都不会更新。
但是,当我删除值(删除第一个索引)时,这会导致StringExpression重新计算自身(我猜是吧?),在这种情况下,将显示新添加/删除的值。(按Remove,然后按Change)
简单地添加值是行不通的。(按Add,然后按Change)
那么,在单元格值工厂回调中,我如何使用代码来侦听可观察列表,并返回一个可观察值,该值可以连接列表并在发生更改时显示,包括添加/删除?
嗯,我算出来了,但我想知道我的解决方案是否可行。
我对JavaFX绑定和属性还不够熟悉,不知道这个解决方案是否很好,或者它是否会导致问题。
concatColumns.setCellValueFactory(new Callback<CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> p) {
final ObservableList row = p.getValue();
List<Observable> dependencies = new ArrayList<>();
for (Object value : row) {
if (value instanceof Observable) {
dependencies.add((Observable)value);
}
}
dependencies.add(row);
StringExpression se = Bindings.createStringBinding(new Callable<String>() {
@Override
public String call() throws Exception {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < row.size(); i++) {
//Check for Property objects and append the value
if (row.get(i) instanceof Property) {
sb.append(((Property)row.get(i)).getValue());
}
else {
sb.append(row.get(i));
}
if (i+1 < row.size()) {
sb.append(", ");
}
}
return sb.toString();
}
}, dependencies.toArray(new Observable[dependencies.size()]));
return se;
}
});
太长别读版本:
我使用绑定创建了自己的StringExpression。createStringBinding(),我添加了可观察列表及其任何可观察对象的值作为对StringExpression的依赖项。
我认为这样做的目的是,每当列表中的一个值发生更改时,就会通知StringExpression更新。另外,当列表本身更改(添加/删除)时,会通知StringExpression更新。
如果我对上述陈述有错,请告诉我!
问题内容: 有没有办法投来?我想不重复进行。 更具体地说,我正在使用ORMLite从数据库中获取数据,并且需要从DB中获取数据的方法作为输出。 目前我正在做这样的事情: 我想做这样的事情: 问题答案: 你可以做
我有一个班的学生有以下领域: 字段“状态”可以有2个值:1。现在,2。缺席的 然后我有一个可观察的列表: 因此,我将学生存储在这个列表中。每个学生都有出席或缺席状态。 我需要按状态对这个观察列表进行排序。我希望目前状态的学生在该列表中名列第一。 有什么建议吗? 如果有任何帮助,我将不胜感激。
我的问题涉及到JavaFX(JavaFX 8,虽然我猜它在2. x中是类似的)中观察列表和列表更改列表的正确用法。因为我是一个JavaFX初学者,我想知道我是否正确理解了它们应该如何使用。 假设我有一个自定义对象列表(我们称之为Slot),我想在GridPane中呈现这些对象:每个Slot都知道它应该在GridPane“grid”中的哪个位置(=行和列数据)。 将存在插槽的初始(数组)列表,但由于
希望我能把问题弄得尽可能清楚。我正在使用JavaFX库为GUI开发一个小型java应用程序。我正在做一个POP连接,并将消息存储为ObservableList。为此,我使用javax.mail。我将这个observablelist传递给一个tableview,并通过以下方式将所需的值传递给TableColumns: Subject和sentDate是完美的读入。但不幸的是,“from”将对象引用添
我想将所有囚犯数据显示到一个TableView中。囚犯看起来像这样(所有代码都是一个示例): 然后我有了我的TableView:数据是一个可观察列表 这工作正常,但我的问题是,如何在TableView中添加大小写?我试过了 但它不起作用。当然,我没有忘记在最后将所有列添加到TableView。
我有一个TableView(javafx.scene.control.TableView),我用数据填充了它。该数据作为ArrayList从数据库中检索,因此我使用了folowing流: 我用预算数据填充ArrayList 我更新数组中的值 初始数据显示正确。我原本期望通过更改ArrayList(最后一步),ObservableList会看到更改并将其传递给我的TableView。为了使数组中的更