SimpleStringProperty и SimpleIntegerProperty TableView JavaFX

Итак, я пытаюсь научиться использовать JavaFx Tableview, и я наткнулся на этот учебник:

Руководство по просмотру таблиц Oracle

в этом уроке они показывают, что для того, чтобы заполнить ваш tableView, вы должны заполнить его строками, а не просто любой строкой, которую вам нужно отформатировать String к SimpleStringProperty

я попытался без формата, и результат был, что никакая информация не показала бы!

Также я обнаружил, что если вы хотите добавить Integer к столу вы должны были бы объявить его как SimpleIntegerProperty

Теперь я довольно новичок в JavaFx, но означает ли это, что когда я создаю объект, мне нужно отформатировать все мои целые числа и строки, чтобы иметь возможность заполнить мой TableView? это кажется довольно глупым, но может быть, есть более высокая цель? или есть способ этого избежать?

1 ответ

Решение

Вам не нужно использовать Properties в ваших объектах данных таблиц для их отображения, хотя использование Properties в определенных обстоятельствах желательно.

Следующий код отобразит таблицу людей на основе класса Person, которая имеет только поля String.

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 является то, что это прослушиваемые элементы. Когда используются свойства, если значение атрибута свойства в модели данных изменяется, представление элемента в табличном представлении автоматически обновляется, чтобы соответствовать обновленному значению модели данных. Например, если значение свойства электронной почты человека установлено на новое значение, это обновление будет отражено в TableView, так как оно прослушивает изменение свойства. Если вместо этого для представления электронной почты использовалась простая строка, TableView не обновлялся бы, поскольку не знал бы об изменениях значений электронной почты.

Документация PropertyValueFactory подробно описывает этот процесс:

Пример использования этого класса:

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

В этом примере строка "firstName" используется как ссылка на предполагаемый метод firstNameProperty() в типе класса Person (который является типом класса в списке элементов TableView). Кроме того, этот метод должен возвращать экземпляр свойства. Если найден метод, отвечающий этим требованиям, то TableCell заполняется этим ObservableValue. Кроме того, 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.
  }
}
Другие вопросы по тегам