【问题标题】:SimpleStringProperty and SimpleIntegerProperty TableView JavaFXSimpleStringProperty 和 SimpleIntegerProperty TableView JavaFX
【发布时间】:2012-11-03 01:57:30
【问题描述】:

所以我正在尝试学习如何使用 JavaFx Tableview,我偶然发现了本教程:

Oracle tableview tutorial

在本教程中,他们表明,为了填充 tableView,您必须使用字符串填充它,但不仅仅是任何字符串,您必须将 String 格式化为 SimpleStringProperty

我尝试不使用格式,结果是没有任何信息显示!

我还发现,如果您想在表中添加 Integer,则必须将其声明为 SimpleIntegerProperty

现在我对 JavaFx 还是很陌生,但这是否意味着当我创建一个对象时,我必须格式化我的所有整数和字符串才能填充我的 TableView?这似乎很愚蠢,但也许有更高的目的?或者有没有办法避免它?

【问题讨论】:

  • 这是一个写得很糟糕的教程。它们掩盖了太多重要的点,例如泛型。
  • 我同意这些教程没有展示很多功能和主题。

标签: java tableview javafx


【解决方案1】:

您不需要在表格数据对象中使用属性来显示它们,尽管在某些情况下使用属性是可取的。

以下代码将显示一个基于 Person 类的人员表,该类只有字符串字段。

import javafx.application.Application;
import javafx.collections.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class ReadOnlyTableView extends Application {
  private TableView<Person> table = new TableView<Person>();
  private final ObservableList<Person> data =
    FXCollections.observableArrayList(
      new Person("Jacob", "Smith", "jacob.smith@example.com"),
      new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
      new Person("Ethan", "Williams", "ethan.williams@example.com"),
      new Person("Emma", "Jones", "emma.jones@example.com"),
      new Person("Michael", "Brown", "michael.brown@example.com")
    );

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

  @Override public void start(Stage stage) {
    stage.setTitle("Table View Sample");
    stage.setWidth(450);
    stage.setHeight(500);

    final Label label = new Label("Address Book");
    label.setFont(new Font("Arial", 20));

    TableColumn firstNameCol = new TableColumn("First Name");
    firstNameCol.setMinWidth(100);
    firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));

    TableColumn lastNameCol = new TableColumn("Last Name");
    lastNameCol.setMinWidth(100);
    lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));

    TableColumn emailCol = new TableColumn("Email");
    emailCol.setMinWidth(200);
    emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));

    table.setItems(data);
    table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);

    final VBox vbox = new VBox();
    vbox.setSpacing(5);
    vbox.setPadding(new Insets(10, 0, 0, 10));
    vbox.getChildren().addAll(label, table);

    stage.setScene(new Scene(new Group(vbox)));
    stage.show();
  }

  public static class Person {
    private String firstName;
    private String lastName;
    private String email;

    private Person(String fName, String lName, String email) {
      this.firstName = fName;
      this.lastName = lName;
      this.email = email;
    }

    public String getFirstName() { return firstName; }
    public void setFirstName(String fName) { firstName = fName; }
    public String getLastName() { return lastName; }
    public void setLastName(String lName) { lastName = lName; }
    public String getEmail() { return email; }
    public void setEmail(String inMail) { email = inMail; }
  }
}

解释

使用 Properties 和 ObservableLists 的目的是这些是可监听的元素。使用properties时,如果datamodel中某个property属性的值发生变化,TableView中item的view会自动更新以匹配更新后的datamodel值。例如,如果一个人的电子邮件属性的值设置为一个新值,则该更新将反映在 TableView 中,因为它会侦听属性更改。相反,如果使用纯字符串来表示电子邮件,则 TableView 不会刷新,因为它不知道电子邮件值的变化。

PropertyValueFactory 文档详细描述了这个过程:

如何使用这个类的一个例子是:

TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name");
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName"));  

在此示例中,“firstName”字符串用作对 假定 Person 类类型中的 firstNameProperty() 方法(即 TableView 项目列表的类类型)。另外,这种方法 必须返回一个 Property 实例。如果一种方法满足这些 找到要求,然后用这个填充 TableCell 可观察值。另外,TableView 会自动添加一个 返回值的观察者,这样触发的任何更改都将 由 TableView 观察,导致单元格立即更新。

如果不存在与此模式匹配的方法,则存在失败 支持尝试调用 get() 或 is()(即 是上面示例中的 getFirstName() 或 isFirstName())。如果一个方法 匹配此模式存在,此方法返回的值为 包装在 ReadOnlyObjectWrapper 中并返回到 TableCell。 但是,在这种情况下,这意味着 TableCell 不会 能够观察 ObservableValue 的变化(如 上面的第一种方法)。

更新

这是一个与第一个示例形成对比的示例,它演示了 TableView 如何根据其 ObservableList 项的更改和基于属性的项属性值的更改来观察和自动刷新。

import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.event.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class PropertyBasedTableView extends Application {
  private TableView<Person> table = new TableView<Person>();
  private final ObservableList<Person> data = FXCollections.observableArrayList();
  private void initData() {
    data.setAll(
      new Person("Jacob", "Smith", "jacob.smith@example.com"),
      new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
      new Person("Ethan", "Williams", "ethan.williams@example.com"),
      new Person("Emma", "Jones", "emma.jones@example.com"),
      new Person("Michael", "Brown", "michael.brown@example.com")
    );
  }

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

  @Override public void start(Stage stage) {
    initData();

    stage.setTitle("Table View Sample");
    stage.setWidth(450);
    stage.setHeight(500);

    final Label label = new Label("Address Book");
    label.setFont(new Font("Arial", 20));

    TableColumn firstNameCol = new TableColumn("First Name");
    firstNameCol.setMinWidth(100);
    firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));

    TableColumn lastNameCol = new TableColumn("Last Name");
    lastNameCol.setMinWidth(100);
    lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));

    TableColumn emailCol = new TableColumn("Email");
    emailCol.setMinWidth(200);
    emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));

    table.setItems(data);
    table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
    table.setPrefHeight(300);

    final Button setEmailButton = new Button("Set first email in table to wizard@frobozz.com");
    setEmailButton.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        if (data.size() > 0) {
          data.get(0).setEmail("wizard@frobozz.com");
        }  
      }
    });

    final Button removeRowButton = new Button("Remove first row from the table");
    removeRowButton.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        if (data.size() > 0) {
          data.remove(0);
        }  
      }
    });

    final Button resetButton = new Button("Reset table data");
    resetButton.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        initData();
      }
    });

    final VBox vbox = new VBox(10);
    vbox.setPadding(new Insets(10, 0, 0, 10));
    vbox.getChildren().addAll(label, table, setEmailButton, removeRowButton, resetButton);

    stage.setScene(new Scene(new Group(vbox)));
    stage.show();
  }

  public static class Person {
    private final StringProperty firstName;
    private final StringProperty lastName;
    private final StringProperty email;

    private Person(String fName, String lName, String email) {
      this.firstName = new SimpleStringProperty(fName);
      this.lastName = new SimpleStringProperty(lName);
      this.email = new SimpleStringProperty(email);
    }

    public String getFirstName() { return firstName.get(); }
    public void setFirstName(String fName) { firstName.set(fName); }
    public StringProperty firstNameProperty() { return firstName; }
    public String getLastName() { return lastName.get(); }
    public void setLastName(String lName) { lastName.set(lName); }
    public StringProperty lastNameProperty() { return lastName; }
    public String getEmail() { return email.get(); }
    public void setEmail(String inMail) { email.set(inMail); }
    public StringProperty emailProperty() { return email; }  // if this method is commented out then the tableview will not refresh when the email is set.
  }
}

【讨论】:

  • 首先非常感谢您的回复,如果可以的话,我会给您超过 1 个竖起大拇指 :) 第二,您的意思是,通过将字符串转换为 SimpleStringProperty,表格将自动更新?如果选择不这样做,您将不得不手动更新表格?
  • 在回答 Marc 的附加问题时添加了来自 PropertyValueFactory 的引用。
  • 当其中一个属性发生变化时,表格会自动更新吗?如果是,你怎么做?您是否使用 object.setName() 更改列表或设置值(作为示例)
  • 添加了另一个示例来演示如何在属性值更改或支持 tableview 的列表被修改时自动更新表。
  • @AndrewS 它是 JavaBeans 中描述的必需的命名约定。 docs.oracle.com/javase/8/javafx/properties-binding-tutorial/… 在此链接中转到“了解属性”
猜你喜欢
  • 2012-11-11
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 2016-08-26
  • 1970-01-01
  • 2013-01-17
相关资源
最近更新 更多