柱形成的可重复使用方法

时间:2017-03-16 22:24:36

标签: java javafx

我的javafx应用程序中有以下方法:

columExample.setCellFactory((TableColumn<Person, Person> column) -> {
        return new TableCell<Peson, Person>() {
            @Override
            protected void updateItem(Person item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null || empty) {
                    setText(null);
                } else {
                    setText(item.getPerson_name());
                }
            }
        };
    });

现在这个工作正常,但是,我想让这个可重复使用,我有例如Book的模型,并且有不同的getter,然后这变得无法使用。

我可以做一个方法,我可以申请任何Model对象。

[编辑] 稍微澄清一下,我正在为我的GUI使用fxml文件,我正在使用hibernate与使用非属性值的模型(虽然我可以切换,因为我只是测试);

我以这种方式构建我的数据; 我使用hql查询,我后来添加到observable列表,然后我将该可观察列表放在tableview上;

tableview.setItems(someObservableList);

在我的初始化方法中我有

 columnX.setCellValueFactory(new PropertyValueFactory("name"));

  @FXML
TableColumn columnX;

此时我的所有列都填充了数据。现在是棘手的部分,我的模型类中的所有原始数据都显示正常,但是对象字符串方法显示了objecst。这就是为什么我使用我首先链接的方法

columExample.setCellFactory((TableColumn<Person, Person> column) -> {
    return new TableCell<Peson, Person>() {
        @Override
        protected void updateItem(Person item, boolean empty) {
            super.updateItem(item, empty);
            if (item == null || empty) {
                setText(null);
            } else {
                setText(item.getPerson_name());
            }
        }
    };
});

所以我只得到人名,而不是整个字符串方法。

那么有什么简单的方法可以做到这一点

TableColumn<Person, String> columnExample = new TableColumn<>("Name");
columnExample.setCellValueFactory(cellData -> 
new SimpleStringProperty(cellData.getValue().getPersonName()));

因为我无法在我当前的设置中使用它,我的程序只是在应用程序启动时显示错误。(我假设因为这会创建新的tablecolum,我希望将其应用于我当前的@FXML列。)

干杯

2 个答案:

答案 0 :(得分:2)

在您引用的情况下,您应该使用单元格值工厂:

TableColumn<Person, String> columnExample = new TableColumn<>("Name");

columnExample.setCellValueFactory(cellData -> 
    new SimpleStringProperty(cellData.getValue().getPersonName()));

然后默认的单元工厂会做你想要的。

如果您使用JavaFX property pattern实施模型,即您有

public class Person {

    private final StringProperty personName = new SimpleStringProperty();

    public StringProperty personNameProperty() {
        return personName ;
    }

    public final String getPersonName() {
        return personNameProperty().get();
    }

    public final void setPersonName(String name) {
        personNameProperty().set(name);
    }
}

然后这就变成了

TableColumn<Person, String> columnExample = new TableColumn<>("Name");
columnExample.setCellValueFactory(cellData -> cellData.getValue().personNameProperty());

我经常使用实用程序方法来创建列以减少代码。基本思想是编写一个参数化变化的方法。在前两行中,根据您创建的列而变化的内容是:

  1. 示例中列("Name")的文本和
  2. 行项目Person实例)到包含要显示的值的属性的函数。
  3. 第一个很简单:它只是String。第二个有点棘手:你可以将它表示为Function<Person, StringProperty>,它将被定义为lambda表达式p -> p.personNameProperty()或方法引用Person::personNameProperty

    这里的问题当然是,并非每个列都属于TableView类型Person,而且并非每列都有String类型。所以我们也需要对它们进行参数化。这可以通过使用两个类型参数定义泛型方法来完成。我们将Person替换为类型参数,例如S,将String替换为第二个类型参数,例如T。然后我们正在创建TableColumn<S,T>,我们需要Function<S, Property<T>>。所以方法如下:

    private <S,T> TableColumn<S,T> column(String text, Function<S, Property<T>> prop) {
        TableColumn<S,T> col = new TableColumn<>(text);
        col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
        return col ;
    }
    

    你可以用

    来调用它
    TableColumn<Person, String> columnExample = this.<Person, String>column("Name", Person::personNameProperty);
    

    在Java 8中,编译器可以推断出方法的泛型类型(基本上,它看到Person::personNamePropertyFunction<Person, Property<String>>,因此它推断出S是{{1 }}和PersonT),所以你可以这样做:

    String

    我经常发现使用此设置我不需要列,除非将其传递到表中,因此代码通常看起来像

    TableColumn<Person, String> columnExample = column("Name", Person::personNameProperty);
    

    如果确实需要一种生成单元工厂的方法,则可以使用类似的技术。您的示例中的内容有所不同:

    1. 行和单元格中的项目类型
    2. 从单元格中的项目获取table.getColumns().add(column("Name", Person::personNameProperty)); 的函数(即从传递给String方法的项目中获取){/ li>

      所以第一个是通过创建一个通用方法来解决的,updateItem(...)返回<S,T>。第二个是通过使用Callback<TableColumn<S,T>, TableCell<S,T>>类型的参数来解决的,该参数将单元格项(类型Function<T, String>)映射到T

      String

      然后您的原始示例变为

      public <S,T> Callback<TableColumn<S,T>, TableCell<S,T>> 
              cellFactory(Function<T, String> textExtractor) {
      
          return col -> new TableCell<S,T>() {
              @Override
              protected void updateItem(T item, boolean empty) {
                  super.updateItem(item, empty) ;
                  if (empty || item == null) {
                      setText(null);
                  } else {
                      setText(textExtractor.apply(item));
                  }
              }
          };
      }
      

      最后,如果您需要,您可以将所有这些想法结合起来。假设您有一个columnExample.setCellFactory(cellFactory(Person::getPersonName)); 类:

      Address

      public class Address { private String street ; private String city ; // etc etc public String shortTextForm() { return street+" ,"+city; } // ... } 类:

      Person

      现在创建一个可重用的方法来创建列。这个将设置public class Person { private final StringProperty name = new SimpleStringProperty(); public StringProperty nameProperty() { return name ; } public final String getName() { return nameProperty().get(); } public final void setName(String name) { nameProperty().set(name); } private final ObjectProperty<Address> address = new SimpleObjectProperty<>(); public ObjectProperty<Address> addressProperty() { return address ; } public Address getAddress() { return addressProperty().get(); } public void setAddress(Address address) { addressProperty().set(address); } // other properties... } (因此需要cellValueFactory)和Function<S,Property<T>>(因此需要cellFactory):

      Function<T, String>

      然后你就做了

      private <S,T> TableColumn<S,T> column(String text, Function<S,Property<T>> prop, 
          Function<T,String> textExtractor) {
      
          TableColumn<S,T> col = new TableColumn<>(text);
          col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
          col.setCellFactory(c -> new TableCell<S,T>() {
              @Override
              protected void updateItem(T item, boolean empty) {
                  super.updateItem(item, empty);
                  if (empty || item == null) {
                      setText(null);
                  } else {
                      setText(textExtractor.apply(item));
                  }
              }
          });
          return col ;
      }
      

答案 1 :(得分:0)

我可能会忽略这一点,但如果您对person类进行了适当的封装,那么您可以使用PropertyValueFactory。如果person_name是Person类中的属性,则

columExample.setCellValueFactory(new PropertyValueFactory<Person, String>("person_name"));

应该做的伎俩。