【问题标题】:EDIT: Model for TableView with dynamic column number编辑:具有动态列号的 TableView 模型
【发布时间】:2016-06-23 21:41:47
【问题描述】:

我正在根据 cmets 修改我的问题。我有一个 JavaFX TableView,其复选框列的数量仅在运行时才知道。因此,要创建列,我会这样做:

    TableColumn attributeColumn = new TableColumn("Attribut");
    attributeColumn.setCellValueFactory(new PropertyValueFactory<AttributeRow, String>("name"));        
    attributeTable.getColumns().add(attributeColumn);

    for (String group : companyGroups)
    {
        TableColumn< AttributeRow, Boolean > groupColumn = new TableColumn<>( group );
        groupColumn.setCellFactory(CheckBoxTableCell.forTableColumn(groupColumn)); 
        groupColumn.setCellValueFactory( f -> f.getValue().activeProperty());
        groupColumn.setEditable(true);
        attributeTable.getColumns().add(groupColumn);
    }

问题是,这个 TableView 的表格模型是什么样子的?如果有固定数量的复选框列,比如 2 列,我的模型如下所示:

public class AttributeRow {

private SimpleStringProperty name;
private SimpleBooleanProperty active = new SimpleBooleanProperty(false);    

public AttributeRow(String name, Boolean active) {
    this.name= new SimpleStringProperty(name);         
}

public SimpleStringProperty nameProperty() {
    if (name == null) {
        name = new SimpleStringProperty(this, "name");
    }
    return name;
}

public String getAttributeName() {
    return name.get();
}

public void setAttributeName(String fName) {
    name.set(fName);
}

public final SimpleBooleanProperty activeProperty() {
    return this.active;
}
public final boolean isActive() {
    return this.activeProperty().get();
}
public final void setActive(final boolean active) {
    this.activeProperty().set(active);
}
}

如果我有一个字符串列和一个复选框列,则此模型有效。但是,如果我有多个仅在运行时知道其编号的复选框列,我该怎么办?

【问题讨论】:

  • 您能解释一下您要达到的目标吗?为什么不更改表格显示的模型中的相应属性?
  • 因为我有一个TableView,它的checkbox列数是动态的,也就是列数只能在运行时确定。所以我不能使用模型,因为我在设计时不知道我真正需要多少属性。
  • 那么数据是如何表示的呢?即使它在数组或列表中仍然是可能的。 TableView 采用单元虚拟化,因此更改控件 (UI) 可能无法可靠地更改所有数据对象。
  • @user41854 “列数只能在运行时确定”。您只是想在运行时设置复选框的选中状态。因此,在您的代码中,确定列数并更新属性。
  • 您修改后的代码没有意义。一方面,您在循环中创建的列上没有cellValueFactory。另一方面,类型不匹配:attributeName 的表列似乎具有PrivacySetting 类型(因此假设表中的每一行都是PrivacySetting 类型的项目)而其他列具有行类型@ 987654328@;你不能在这里有两种不同的类型。 复选框中表示的实际数据存储在哪里?

标签: java checkbox javafx


【解决方案1】:

您还没有真正描述数据的结构,但看起来有某种Strings (companyGroups) 的集合,并且每一行都是表格由String (@ 987654324@) 和 companyGroups 的每个元素一个布尔值。因此,一种方法就是在模型类AttributeRow 中定义一个Map&lt;String, BooleanProperty&gt;,其中映射中的键是companyGroups 的一个元素:

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class AttributeRow {

    private final StringProperty name = new SimpleStringProperty();

    private final Map<String, BooleanProperty> activeByGroup = new HashMap<>();

    public AttributeRow(List<String> companyGroups) {
        for (String group : companyGroups) {
            activeByGroup.put(group, new SimpleBooleanProperty()) ;
        }
    }

    public final BooleanProperty activeProperty(String group) {
        // might need to deal with the case where
        // there is no entry in the map for group
        // (else calls to isActive(...) and setActive(...) with 
        // a non-existent group will give a null pointer exception):

        return activeByGroup.get(group) ;
    }

    public final boolean isActive(String group) {
        return activeProperty(group).get();
    }

    public final void setActive(String group, boolean active) {
        activeProperty(group).set(active);
    }

    public final StringProperty nameProperty() {
        return this.name;
    }


    public final String getName() {
        return this.nameProperty().get();
    }


    public final void setName(final String name) {
        this.nameProperty().set(name);
    }



}

列的单元格值工厂没有什么特别之处 - 它仍然只需将每一行映射到列的适当可观察属性:

for (String group : groups) {
    TableColumn<AttributeRow, Boolean> groupColumn = new TableColumn<>(group);
    groupColumn.setCellFactory(CheckBoxTableCell.forTableColumn(groupColumn));
    groupColumn.setCellValueFactory(cellData -> cellData.getValue().activeProperty(group));
    attributeTable.getColumns().add(groupColumn);
}

当然要更新值,您只需更新模型:

Button selectAll = new Button("Select all");
selectAll.setOnAction(e -> {
    for (AttributeRow row : attributeTable.getItems()) {
        for (String group : groups) {
            row.setActive(group, true);
        }
    }
});

这是一个 SSCCE:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TableWithMappedBooleans extends Application {

    private static final List<String> groups = Arrays.asList("Group 1", "Group 2", "Group 3", "Group 4");

    @Override
    public void start(Stage primaryStage) {

        TableView<AttributeRow> attributeTable = new TableView<>();
        attributeTable.setEditable(true);

        TableColumn<AttributeRow, String> attributeColumn = new TableColumn<>("Attribute");
        attributeColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());

        attributeTable.getColumns().add(attributeColumn);

        for (String group : groups) {
            TableColumn<AttributeRow, Boolean> groupColumn = new TableColumn<>(group);
            groupColumn.setCellFactory(CheckBoxTableCell.forTableColumn(groupColumn));
            groupColumn.setCellValueFactory(cellData -> cellData.getValue().activeProperty(group));
            attributeTable.getColumns().add(groupColumn);
        }

        // generate data:
        for (int i = 1 ; i <= 10; i++) {
            AttributeRow row = new AttributeRow(groups);
            row.setName("Attribute "+i);
            attributeTable.getItems().add(row);
        }

        // button to select everything:

        Button selectAll = new Button("Select all");
        selectAll.setOnAction(e -> {
            for (AttributeRow row : attributeTable.getItems()) {
                for (String group : groups) {
                    row.setActive(group, true);
                }
            }
        });

        // for debugging, to check data are updated from check boxes:
        Button dumpDataButton = new Button("Dump data");
        dumpDataButton.setOnAction(e -> {
            for (AttributeRow row : attributeTable.getItems()) {
                String groupList = groups.stream()
                        .filter(group -> row.isActive(group))
                        .collect(Collectors.joining(", "));
                System.out.println(row.getName() + " : " + groupList);
            }
            System.out.println();
        });

        HBox buttons = new HBox(5, selectAll, dumpDataButton);
        buttons.setAlignment(Pos.CENTER);
        buttons.setPadding(new Insets(5));

        BorderPane root = new BorderPane(attributeTable, null, null, buttons, null);

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

【讨论】:

  • 哇,谢谢 James_D。我很佩服。有用。请为我最初的糟糕问题道歉。无论如何,谢谢你帮助我。 :-)
猜你喜欢
  • 2017-12-11
  • 1970-01-01
  • 2016-04-06
  • 2013-02-23
  • 1970-01-01
  • 2015-12-13
  • 2012-08-09
  • 1970-01-01
  • 2015-10-02
相关资源
最近更新 更多