0

I'm writing a JavaFX application. I have a TableView with all entries from a database, populated as follows:

public class AdvertisementListController {

    @FXML public TableView<Advertisement> advertisementTable;
    @FXML public TableColumn<Advertisement, String> dateColumn;
    @FXML public TableColumn<Advertisement, String> productColumn;
    @FXML public TableColumn<Advertisement, String> vendorColumn;
    @FXML public TableColumn<Advertisement, Integer> priceColumn;
    @FXML public TableColumn<Advertisement, Integer> quantityColumn;

    // ...

     public void initialize() {
        dateColumn.setCellValueFactory(new PropertyValueFactory<>("stringDate"));
        productColumn.setCellValueFactory(new PropertyValueFactory<>("productName"));
        vendorColumn.setCellValueFactory(new PropertyValueFactory<>("vendorId"));
        priceColumn.setCellValueFactory(new PropertyValueFactory<>("price"));
        quantityColumn.setCellValueFactory(new PropertyValueFactory<>("quantity"));

        // ...

        AdvertisementDAO advertisementDAO = new AdvertisementDAO();
        annunciTable.setItems(advertisementDAO.getAdvertisementObservableList());
    }

From another window of my application I can insert new entries in the table of the database. I'm new to GoF patterns, and I'm trying to implement here an Observer pattern in order to keep the table updated, but I don't really know where to start. What's the subject here? What's the Observer class?

Robb1
  • 4,587
  • 6
  • 31
  • 60

1 Answers1

2

JavaFX is a framework that uses the Model-View-Controller (MVC) design pattern. If you do some research, you will realize that MVC also uses the Observer design pattern.

JavaFX took one step further in its support for the Observer design pattern. JavaFX has concept of Property, which is basically Observer design pattern. A Property object holds the value, and it can be used to observe for value changes. The base interface for Property (and ObservableList etc) is Observable.

Therefore, by using Property (and in your case ObservableList), you are already using Observer design pattern.

So in order to do it properly, these are what you need:

  1. Make sure your Advertisement class stores stringDate, productName, vendorId, price and quantity as Property.
  2. Instead of getting the ObservableList from AdvertisementDAO via getAdvertisementObservableList(), shift the ObservableList out, as a field of AdvertisementListController. You should instead alter the ObservableList whenever your data changes.
  3. Depending on how the other window changes the data, you may also need to create your ObservableList with FXCollections.observableArrayList(Callback) overload.

Example:

public class Advertisement {
    private final StringProperty stringDate = new SimpleStringProperty();
    public final StringProperty stringDateProperty() { return stringDate; }
    public final String getStringDate() { return stringDate.get(); }
    public final void setStringDate(String s) { stringDate.set(s); }

    // Other properties
}

public class AdvertisementListController {

    @FXML public TableView<Advertisement> advertisementTable;
    @FXML public TableColumn<Advertisement, String> dateColumn;
    @FXML public TableColumn<Advertisement, String> productColumn;
    @FXML public TableColumn<Advertisement, String> vendorColumn;
    @FXML public TableColumn<Advertisement, Integer> priceColumn;
    @FXML public TableColumn<Advertisement, Integer> quantityColumn;

    private final ObservableList advertisements = FXCollections.observableArrayList(advertisement -> new Observable[] { advertisement.stringDateProperty() });

    public void initialize() {
        dateColumn.setCellValueFactory(new PropertyValueFactory<>("stringDate"));
        productColumn.setCellValueFactory(new PropertyValueFactory<>("productName"));
        vendorColumn.setCellValueFactory(new PropertyValueFactory<>("vendorId"));
        priceColumn.setCellValueFactory(new PropertyValueFactory<>("price"));
        quantityColumn.setCellValueFactory(new PropertyValueFactory<>("quantity"));

        // ...

        AdvertisementDAO advertisementDAO = new AdvertisementDAO();
        advertisements.setAll(advertisementDAO.getAdvertisementList());
        advertisementTable.setItems(advertisements);
    }
}
Jai
  • 8,165
  • 2
  • 21
  • 52
  • Thanks for your answer, very clear. I still don't get the `stringDateProperty()` call inside the declaration of `advertisements` variable. Can you explain me it? – Robb1 Dec 19 '17 at 15:07
  • Moreover, using `StringProperty` instead of `String` forces me to change all usege of `Advertisement` attributes I make in my project... But I can't find an easy way to parse a `String` into a `StringProperty` (also being `StringProperty` an `abstract class`). Help! – Robb1 Dec 19 '17 at 15:15
  • 2
    @Robb1 "I can't find an easy way to parse a String into a StringProperty". What is wrong with the code in the answer? `private final StringProperty stringDate = new SimpleStringProperty();` and `stringDate.set(s)`? – James_D Dec 19 '17 at 15:41
  • @James_D Ouch, I was trying to instantiate it with `new StringProperty()`, thanks for making me notice the mistake :) – Robb1 Dec 19 '17 at 16:15