所有!
当我在Java上设计我的项目时遇到了以下主要问题:
我需要编写的程序是允许用户输入一些数据然后以特定格式保存的接口。在项目中,我将数据存储在ArrayList<>
中。
public class CQuestionnaire
{
// fields
private final List<CQuestStage> m_lstStages;
…
}
用户界面基于TableView。所以我需要ObservableList<>
来连接数据和TableView
。我认为将TableView
与CQuestionnaire
的列表直接关联是一个很好的决定。所以我为此目的实施了getObservableList()
:
public class CQuestionnaire
{
// fields
private final List<CQuestStage> m_lstStages;
public ObservableList<CQuestStage> getObservableList()
{
return FXCollections.observableArrayList(m_lstStages);
}
…
}
这不起作用,因为FXCollections.observableArrayList()
会返回列表的副本,而CQuestionnaire
成员的所有用户操作都不会更改。
问题如下:是否有任何方法如何将TableView
与ArrayList<>
相关联,而不将其类型更改为ObservableList<>
(分别保留数据及其视图)并且不创建仅TableView
所需的不同列表?
我当然读过这个主题(JavaFX, Casting ArrayList to ObservableList)。但问题是FXCollections.observableArrayList()
副本列表CQuestionnaire
和TableView
中的源列表之间没有链接。
答案 0 :(得分:5)
使用FXCollections.observableList(m_lstStages)
,它返回由指定列表支持的可观察列表,而不是FXCollections.observableArrayList(m_lstStages)
,它创建一个新的可观察数组列表并将集合的内容添加到其中。
这样,对表视图内容所做的更改将自动传播回原始列表。 (但请注意,虽然对基础列表的更改将更改可观察列表,但由于基础列表不可观察,因此无法通知表格此类更改,因此无法自动更新。)< / p>
注意,没有必要将此功能添加到模型类中;您可以在需要的时候用FXCollections.observableList(...)
包装列表。这可以防止您的模型依赖于JavaFX API,我认为这是目标的一部分。
这是一个简单的SSCCE。
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.value.ObservableValueBase;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Spinner;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class TableWithModelWithPlainList extends Application {
@Override
public void start(Stage primaryStage) {
Model model = new Model();
for (int i = 1 ; i <= 20 ; i++) {
model.getItems().add(new Item("Item "+i, i*i));
}
TableView<Item> table = new TableView<>();
// use observable list wrapping model data for table items:
table.setItems(FXCollections.observableList(model.getItems()));
// normal table setup:
table.getColumns().add(column("Item", Item::getName));
table.getColumns().add(column("Value", Item::getValue));
// controls to modify table data:
TextField itemNameField = new TextField();
Spinner<Integer> spinner = new Spinner<>(1, 1000, 200);
Button add = new Button("Add");
EventHandler<ActionEvent> addHandler = e -> {
table.getItems().add(new Item(itemNameField.getText(), spinner.getValue()));
itemNameField.clear();
};
add.setOnAction(addHandler);
itemNameField.setOnAction(addHandler);
Button remove = new Button("Remove");
remove.disableProperty().bind(table.getSelectionModel().selectedItemProperty().isNull());
remove.setOnAction(e -> table.getItems().remove(table.getSelectionModel().getSelectedIndex()));
// checks that model and table are in sync:
Button debug = new Button("Debug");
debug.setOnAction(e -> {
System.out.println("Model has "+model.getItems().size()+" items; table has "+table.getItems().size()+" items");
for (int i = 0 ; i < model.getItems().size() && i < table.getItems().size(); i++) {
Item modelItem = model.getItems().get(i);
Item tableItem = table.getItems().get(i);
System.out.printf("Index %d: model %s (%d); table %s (%d); equal: %s%n",
i, modelItem.getName(), modelItem.getValue(),
tableItem.getName(), tableItem.getValue(),
tableItem.getValue()==modelItem.getValue() && tableItem.getName().equals(modelItem.getName()));
}
System.out.println();
});
// layout stuff:
HBox controls = new HBox(2, itemNameField, spinner, add, remove, debug);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(10));
BorderPane root = new BorderPane(table);
root.setBottom(controls);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private static <S,T> TableColumn<S,T> column(String title, Function<S,T> property) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> new ObservableValueBase<T>() {
@Override
public T getValue() {
return property.apply(cellData.getValue());
};
});
return col ;
}
public static class Model {
private List<Item> items ;
public Model() {
this.items = new ArrayList<>();
}
public List<Item> getItems() {
return items ;
}
}
public static class Item {
private String name ;
private int value ;
public Item(String name, int value) {
this.name = name ;
this.value = value ;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
public static void main(String[] args) {
launch(args);
}
}
答案 1 :(得分:1)