JavaFX 2.1 TableView Updates

I have such a common problem as it seems. My view of the table will not update my objects after I reset them. I checked the data, and a new one.

I tried several solutions from the Internet, but did not succeed.

It is impossible to reset all columns, because it adds one empty extra (I don’t know why) and just resizes it.

My table is not editable . New data changed.

The data is updated if I change the order of the elements, and the rows change (: |).

I just was left without ideas.

Currently, the update code is pretty simple.

ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data); 

Again, the new data is correct. When I make a selection in tableView, it returns the new correct item.

+49
java javafx javafx-8 tableview fxml
Jun 16 '12 at 16:21
source share
23 answers

I had a similar refreshment problem. My solution was to restrict operations on the ObservableList to those that work correctly with bind ().

Suppose ObservableList obsList is the base list for a TableView.

Then
obsList.clear () (inherited from java.util.List <>) will not update the View table correctly, but.

Also the call to setItem (obsList) did not work to trigger the update ... but ...

obsList.removeAll (obsList) (overwritten by ObservableList) works fine because it runs changeEvent correctly :-)

Filling the list with completely new content, it works as follows:

  • obsList.removeAll (obsList);
  • obsList.add (...); // e.g. in a loop ...

or

  • obsList.removeAll (obsList);
  • FXCollections.copy (obsList, someSourceList)

Regards Ingo

+32
04 Oct
source share

Workaround:

  tableView.getColumns().get(0).setVisible(false); tableView.getColumns().get(0).setVisible(true); 
+55
Sep 27 '12 at 3:45
source share

Since JavaFX 8u60 you can use (it is assumed that tableView is an instance of the TableView class):

 tableView.refresh(); 

From the documentation:

The refresh () call causes the TableView control to recreate and refill the cells needed to fill the visual boundaries of the control. In other words, this causes the TableView to update what it displays to the user. This is useful in cases where the data source has changed in a way that is not observed in the TableView on its own.

+19
Sep 23 '16 at 22:37
source share

UPDATE:
Finally, updating a table view is enabled in JavaFX 8u60 , available for early access.




For refreshment, see Updating Rows in Tableview .
And about an empty column, see JavaFx 2, create a TableView with one column . In principle, this is not a column, i.e. You cannot select an element by clicking on these empty column elements. This is just an empty area stylized as a string.




UPDATE: If you update the tableView through reseller_table.setItems(data) , you do not need to use SimpleStringProperty . It would be helpful if you would only update one line / item. Here is a complete complete example of updating table data:

 import java.util.ArrayList; import java.util.List; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Dddeb extends Application { public static class Product { private String name; private String code; public Product(String name, String code) { this.name = name; this.code = code; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getName() { return name; } public void setName(String name) { this.name = name; } } private TableView<Product> productTable = new TableView<Product>(); @Override public void start(Stage stage) { Button refreshBtn = new Button("Refresh table"); refreshBtn.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent arg0) { // You can get the new data from DB List<Product> newProducts = new ArrayList<Product>(); newProducts.add(new Product("new product A", "1201")); newProducts.add(new Product("new product B", "1202")); newProducts.add(new Product("new product C", "1203")); newProducts.add(new Product("new product D", "1244")); productTable.getItems().clear(); productTable.getItems().addAll(newProducts); //productTable.setItems(FXCollections.observableArrayList(newProducts)); } }); TableColumn nameCol = new TableColumn("Name"); nameCol.setMinWidth(100); nameCol.setCellValueFactory(new PropertyValueFactory<Product, String>("name")); TableColumn codeCol = new TableColumn("Code"); codeCol.setCellValueFactory(new PropertyValueFactory<Product, String>("code")); productTable.getColumns().addAll(nameCol, codeCol); productTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); // You can get the data from DB List<Product> products = new ArrayList<Product>(); products.add(new Product("product A", "0001")); products.add(new Product("product B", "0002")); products.add(new Product("product C", "0003")); //productTable.getItems().addAll(products); productTable.setItems(FXCollections.observableArrayList(products)); final VBox vbox = new VBox(); vbox.setSpacing(5); vbox.getChildren().addAll(productTable, refreshBtn); Scene scene = new Scene(new Group()); ((Group) scene.getRoot()).getChildren().addAll(vbox); stage.setScene(scene); stage.setWidth(300); stage.setHeight(500); stage.show(); } public static void main(String[] args) { launch(args); } } 

note that

 productTable.setItems(FXCollections.observableArrayList(newProducts)); 

and

 productTable.getItems().clear(); productTable.getItems().addAll(newProducts); 

almost equivalent. So I used the first to populate the table for the first time and the other when the table is updated. It is intended for demonstration purposes only. I tested the code in JavaFX 2.1. And finally, you can (and should) change your question to improve it by moving code snippets to your answer to your question.

+7
Jun 16 '12 at 18:33
source share

I finally found an ugly workaround for updating all rows.

 void refreshTable() { final List<Item> items = tableView.getItems(); if( items == null || items.size() == 0) return; final Item item = tableView.getItems().get(0); items.remove(0); Platform.runLater(new Runnable(){ @Override public void run() { items.add(0, item); } }); } 
+6
Jul 24 2018-12-12T00:
source share

I believe this thread has a very good description of the problem with updating the table.

+2
Sep 22 '12 at 23:55
source share

It seems that there are several separate issues around oldItems.equals (newItems)

The first part of RT-22463 : tableView will not be updated even when items.clear () is called

 // refresh table table.getItems().clear(); table.setItems(listEqualToOld); 

what is fixed. Clearing old items before installing a new list clears all old states, thereby updating the table. Any example where this does not work can be regression.

What else doesn't work is reinstalling items without first cleaning

 // refresh table table.setItems(listEqualToOld); 

This is a problem if the table displays properties that do not participate in the equal solution of the element (see the example in RT-22463 or Aubin ) and is covered - I hope - RT-39094

UPDATE : RT-39094 last fixed, for 8u40! Must bubble up in ea in a couple of weeks, thinking about u12 or such.

The technical reason seems to be checking for equality in the implementation of the cells: checking for element changes before the actual call to updateItem (T, boolean) was introduced to fix performance issues. Reasonable, just for hard code, "change" == old.equals (new) creates problems in some contexts.

A workaround great for me (without formal testing!) Is a custom TableRow that jumps if an identity check is required:

 /** * Extended TableRow that updates its item if equal but not same. * Needs custom skin to update cells on invalidation of the * item property.<p> * * Looks ugly, as we have to let super doing its job and then * re-check the state. No way to hook anywhere else into super * because all is private. <p> * * Super might support a configuration option to check against * identity vs. against equality.<p> * * Note that this is _not_ formally tested! Any execution paths calling * <code>updateItem(int)</code> other than through * <code>indexedCell.updateIndex(int)</code> are not handled. * * @author Jeanette Winzenburg, Berlin */ public class IdentityCheckingTableRow<T> extends TableRow<T> { @Override public void updateIndex(int i) { int oldIndex = getIndex(); T oldItem = getItem(); boolean wasEmpty = isEmpty(); super.updateIndex(i); updateItemIfNeeded(oldIndex, oldItem, wasEmpty); } /** * Here we try to guess whether super updateIndex didn't update the item if * it is equal to the old. * * Strictly speaking, an implementation detail. * * @param oldIndex cell index before update * @param oldItem cell item before update * @param wasEmpty cell empty before update */ protected void updateItemIfNeeded(int oldIndex, T oldItem, boolean wasEmpty) { // weed out the obvious if (oldIndex != getIndex()) return; if (oldItem == null || getItem() == null) return; if (wasEmpty != isEmpty()) return; // here both old and new != null, check whether the item had changed if (oldItem != getItem()) return; // unchanged, check if it should have been changed T listItem = getTableView().getItems().get(getIndex()); // update if not same if (oldItem != listItem) { // doesn't help much because itemProperty doesn't fire // so we need the help of the skin: it must listen // to invalidation and force an update if // its super wouldn't get a changeEvent updateItem(listItem, isEmpty()); } } @Override protected Skin<?> createDefaultSkin() { return new TableRowSkinX<>(this); } public static class TableRowSkinX<T> extends TableRowSkin<T> { private WeakReference<T> oldItemRef; private InvalidationListener itemInvalidationListener; private WeakInvalidationListener weakItemInvalidationListener; /** * @param tableRow */ public TableRowSkinX(TableRow<T> tableRow) { super(tableRow); oldItemRef = new WeakReference<>(tableRow.getItem()); itemInvalidationListener = o -> { T newItem = ((ObservableValue<T>) o).getValue(); T oldItem = oldItemRef != null ? oldItemRef.get() : null; oldItemRef = new WeakReference<>(newItem); if (oldItem != null && newItem != null && oldItem.equals(newItem)) { forceCellUpdate(); } }; weakItemInvalidationListener = new WeakInvalidationListener(itemInvalidationListener); tableRow.itemProperty().addListener(weakItemInvalidationListener); } /** * Try to force cell update for equal (but not same) items. * C&P'ed code from TableRowSkinBase. */ private void forceCellUpdate() { updateCells = true; getSkinnable().requestLayout(); // update the index of all children cells (RT-29849). // Note that we do this after the TableRow item has been updated, // rather than when the TableRow index has changed (as this will be // before the row has updated its item). This will result in the // issue highlighted in RT-33602, where the table cell had the correct // item whilst the row had the old item. final int newIndex = getSkinnable().getIndex(); for (int i = 0, max = cells.size(); i < max; i++) { cells.get(i).updateIndex(newIndex); } } } @SuppressWarnings("unused") private static final Logger LOG = Logger .getLogger(IdentityCheckingListCell.class.getName()); } // usage table.setRowFactory(p -> new IdentityCheckingTableRow()); 

Note that TableCell has a similar hard-coded equality check, so if the user row is not enough, you might need to use a custom TableCell with a similar workaround (not running in an example where necessary, though)

+2
Oct 22 '14 at 15:13
source share

What a mistake! Here is another workaround ...

 public void forceRefresh() { final TableColumn< Prospect, ? > firstColumn = view.getColumns().get( 0 ); firstColumn.setVisible( false ); new Timer().schedule( new TimerTask() { @Override public void run() { Platform.runLater( new Runnable() { @Override public void run() { firstColumn.setVisible( true ); }}); }}, 100 ); } 

I made SSCCE to show error . I urge everyone to fix this in an even more elegant way, because my workaround is very ugly!

+1
Jul 25 '13 at 19:52
source share

I have a use case where nothing helped as a solution from Aubin. I adapted the method and changed it by deleting and adding an element to the list of table elements, since it works at the end, only reliably with this hack, the column displayed for switching completed the task only for the first time.

I also reported this in the Jira problem: https://javafx-jira.kenai.com/browse/RT-22463

  public <T> void tableItemsRefresh(final ObservableList<T> items) { if (items == null || items.size() == 0) return; int idx = items.size() -1; final T item = items.get(idx); items.remove(idx); new Timer().schedule(new TimerTask() { @Override public void run() { Platform.runLater(new Runnable() { @Override public void run() { items.add(item); } }); } }, 100); } 
+1
Aug 23 '13 at 9:23
source share

I had the same problem and after some searching this was my workaround. I found that if the columns are deleted and then added again, the table is updated.

 public static <T,U> void refreshTableView(final TableView<T> tableView, final List<TableColumn<T,U>> columns, final List<T> rows) { tableView.getColumns().clear(); tableView.getColumns().addAll(columns); ObservableList<T> list = FXCollections.observableArrayList(rows); tableView.setItems(list); } 


Usage example:

 refreshTableView(myTableView, Arrays.asList(col1, col2, col3), rows); 
+1
Sep 04 '13 at 0:05
source share

User Solution 1236048 is correct, but key point is not called. In your POJO classes used to list observable tables, you need to not only set the getter and setter methods, but also a new one called Property. In the Oracle tableview tutorial ( http://docs.oracle.com/javafx/2/ui_controls/table-view.htm ) they left this part of the key!

The Person class should look like this:

 public static class Person { private final SimpleStringProperty firstName; private final SimpleStringProperty lastName; private final SimpleStringProperty 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 SimpleStringProperty firstNameProperty(){ return firstName; } public String getLastName() { return lastName.get(); } public void setLastName(String fName) { lastName.set(fName); } public SimpleStringProperty lastNameProperty(){ return lastName; } public String getEmail() { return email.get(); } public void setEmail(String fName) { email.set(fName); } public SimpleStringProperty emailProperty(){ return email; } 

}

+1
Jun 12 '14 at 22:24
source share

Instead of updating manually, you should use visible properties. The answers to this question show the purpose: SimpleStringProperty and SimpleIntegerProperty TableView JavaFX

+1
Jul 04 '14 at 12:30
source share

Based on Daniel De Leon's answer

 public static void refresh_table(TableView table) { for (int i = 0; i < table.getColumns().size(); i++) { ((TableColumn)(table.getColumns().get(i))).setVisible(false); ((TableColumn)(table.getColumns().get(i))).setVisible(true); } } 
+1
Jul 15 '14 at 20:51
source share

Take a look at this issue in the Jira: https://bugs.openjdk.java.net/browse/JDK-8098085

Comment 2012-09-20 08:50 gave a workaround that works.

 //wierd JavaFX bug reseller_table.setItems(null); reseller_table.layout(); ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data); 
+1
Apr 04 '16 at 2:46
source share

JavaFX8

I am adding a new item to DialogBox. Here is my code.

 ObservableList<Area> area = FXCollections.observableArrayList(); 

When initializing () or setApp ()

 this.areaTable.setItems(getAreaData()); 

getAreaData ()

 private ObservableList<Area> getAreaData() { try { area = AreaDAO.searchEmployees(); // To inform ObservableList return area; } catch (ClassNotFoundException | SQLException e) { System.out.println("Error: " + e); return null; } } 

Add by dialog box.

 @FXML private void handleNewArea() { Area tempArea = new Area(); boolean okClicked = showAreaDialog(tempArea); if (okClicked) { addNewArea(tempArea); this.area.add(tempArea); // To inform ObservableList } } 

Area is a regular POJO JavaFX. Hope this helps someone.

+1
Mar 02 '17 at 13:10
source share

initialize () method

 fullNameColumn = new TableColumn("Full name"); fullNameColumn.setCellValueFactory(new PropertyValueFactory<User, String>("fullName")); usernameColumn = new TableColumn("Username"); usernameColumn.setCellValueFactory(new PropertyValueFactory<User, String>("test")); emailColumn = new TableColumn("Email"); emailColumn.setCellValueFactory(new PropertyValueFactory<User, String>("email")); reseller_table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); reseller_table.getColumns().addAll(usernameColumn, fullNameColumn, emailColumn); ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data); 

User Class (Hibernate POJO Class)

 private SimpleStringProperty test; public void setFullName(String fullName) { this.fullName = fullName; this.test = new SimpleStringProperty(fullName); } public SimpleStringProperty testProperty() { return test; } 

refresh () method

 ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data); 
0
Jun 17 '12 at 12:38
source share

My solution is similar to Daniel De León workaround, but it also works when you need to hide the first column (index 0 in his example). Of course, you can just change the index in your solution, but if you rearrange the columns, my solution may work better for you. The idea is to hide and show the column by name, rather than hide and show it by its index:

 private void updateMyTableView() { // update table view WORKAROUND !!! if (myTableView != null) { ObservableList<TableColumn<Entry, ?>> columns = myTableView.getColumns(); for (TableColumn<Entry, ?> column : columns) { // at this point, we look for the specific column, which should // always be visible // therefore we use the "Column Title" String, eg "First name" if (column.getText().equals("Column Title")) { column.setVisible(false); column.setVisible(true); } } } } 

It is best to refresh the table in the UI update thread. However, it also works by simply calling updateMyTableView(); after you change something in your table, since JavaFX seems to be updating in the UI thread anyway (not sure about that).

 Platform.runLater(new Runnable() { public void run() { updateMyTableView(); } }); 
0
Jul 21 '14 at 6:14
source share

I'm not sure if this applies to your situation, but I will post what worked for me.

I am changing my table view based on queries / searches in the database. For example, a database table contains patient data. My initial presentation of the table in my program contains all patients. Then I can search for patient queries by firstName and lastName. I use the results of this query to refill the Observable list. Then I reset the elements in the table view by calling tableview.setItems (observableList):

 /** * Searches the table for an existing Patient. */ @FXML public void handleSearch() { String fname = this.fNameSearch.getText(); String lname = this.lNameSearch.getText(); LocalDate bdate = this.bDateSearch.getValue(); if (this.nameAndDOBSearch(fname, lname, bdate)) { this.patientData = this.controller.processNursePatientSearch(fname, lname, bdate); } else if (this.birthDateSearch(fname, lname, bdate)) { this.patientData = this.controller.processNursePatientSearch(bdate); } else if (this.nameSearch(fname, lname, bdate)) { this.patientData = this.controller.processNursePatientSearch(fname, lname); } this.patientTable.setItems(this.patientData); } 

If blocks update the ObservableList with query results.

0
Nov 30 '14 at 18:06
source share

Same problem here, I tried some solutions, and the best thing for me is the following:

In the controller’s initialize method, create an empty observable list and set it to the table:

  obsBericht = FXCollections.observableList(new ArrayList<Bericht>(0)); tblBericht.setItems(obsBericht); 

In your update method, just use the observable list, clear it and add the updated data:

  obsBericht.clear(); obsBericht.addAll(FXCollections.observableList(DatabaseHelper.getBerichte())); // tblBericht.setItems(obsBericht); 

No need to set table items again

0
Feb 26 '15 at 12:36
source share

Following the answers of Daniel De Leon ...

  • In my model, I introduced the dummy property "modelChangedProperty" and
  • created a refresh () method in my model that changes the value of this property.
  • In my controller, I added a Listener to the dummy property, which updates the table view.

-

 /** * Adds a listener to the modelChangedProperty to update the table view */ private void createUpdateWorkAroundListener() { model.modelChangedProperty.addListener( (ObservableValue<? extends Boolean> arg0, final Boolean oldValue, final Boolean newValue) -> updateTableView() ); } /** * Work around to update table view */ private void updateTableView() { TableColumn<?, ?> firstColumn = scenarioTable.getColumns().get(0); firstColumn.setVisible(false); firstColumn.setVisible(true); } 
0
Apr 09 '15 at 11:40
source share

I know this question is 4 years old, but I have the same problem, I tried the solutions from above and did not work. I also called the refresh () method, but still did not expect the result. So I am posting my solution here, maybe it will help someone.

 Question db = center.getSelectionModel().getSelectedItem(); new QuestionCrud().deleteQ(db.getId()); ObservableList<Question> aftDelete = FXCollections.observableArrayList( (new QuestionCrud()).all() ); center.setItems(aftDelete); 

Even before that, I used another variable in the ObeservableList to set the elements in the tableview, I call it the "dirty method", but until I get a better solution, that's fine.

0
Dec 30 '16 at 19:18
source share

I am trying to find a way to update tableView (ScalaFx) within 3-4 hours. Finally I got an answer. I just want to post my decision because I have been wasting a few hours.

-To get rows from the database, I used to declare a method that returns an ObservableBuffer.

My JDBC Class

  //To get all customer details def getCustomerDetails : ObservableBuffer[Customer] = { val customerDetails = new ObservableBuffer[Customer]() try { val resultSet = statement.executeQuery("SELECT * FROM MusteriBilgileri") while (resultSet.next()) { val musteriId = resultSet.getString("MusteriId") val musteriIsmi = resultSet.getString("MusteriIsmi") val urununTakildigiTarih = resultSet.getDate("UrununTakildigiTarih").toString val bakimTarihi = resultSet.getDate("BakimTarihi").toString val urununIsmi = resultSet.getString("UrununIsmi") val telNo = resultSet.getString("TelNo") val aciklama = resultSet.getString("Aciklama") customerDetails += new Customer(musteriId,musteriIsmi,urununTakildigiTarih,bakimTarihi,urununIsmi,telNo,aciklama) } } catch { case e => e.printStackTrace } customerDetails } 

-And I created a TableView object.

 var table = new TableView[Customer](model.getCustomerDetails) table.columns += (customerIdColumn,customerNameColumn,productInstallColumn,serviceDateColumn, productNameColumn,phoneNoColumn,detailColumn) 

-And finally I got a decision. On the refresh button, I pasted this code;

 table.setItems(FXCollections.observableArrayList(model.getCustomerDetails.delegate)) 

model is a reference to my jdbc connection class

 val model = new ScalaJdbcConnectSelect 

These are scalafx codes, but it gives some javafx idea

0
Feb 21 '17 at 15:45
source share

我 始終 認為 利用 更改 TableColumn 的 的 visible 方法 屬性 違反 data binding 的 精神, 若 這 是 的 JavaFX error 那 也 早就 該 接 決 了, 不 應該 拖到 Java8 了 還不 解決.

經過 JavaFX trace 的 source code 後, 並 沒有 發現 error. 利用 Listener 等 方法 觀察 也 沒有 異樣. 也 嘗試 利用 JFace 中 的 PropertyChangeSupport 方式 宣告 POJO 內容 變更 也 沒有 效果. 最後 將 DoubleProperty 改為 WritableObjectValue, 問 提 就 解決 了.

  解決於台灣台北 

I had a confirmed change in use. The Column Visable property does not meet the goal of automating data binding.

After I traced the source code of the JavaFX TableView. I never found the problematic code for the tableview binding problem. After 4 weeks ago I changed the type of the POJO field from DoubleProperty to WritableObjectValue, the problem was resolved.

  resolve in Taiwan Taipei. 

Code example:

 public class CostAnalytics{ protected WritableObjectValue<Double> subtotal=new SimpleObjectProperty<Double>();//利用WritableObjectValue達到自動更新目的,不需要使用個別Column操作setVisable(false)及setVisable(true) //... public void setQuantity(double quantity) { this.pcs.firePropertyChange("quantity", this.quantity, quantity); this.quantity.set(quantity); this.calsSubtotal(); } public WritableObjectValue<Double> getSubtotal() {//利用WritableObjectValue達到自動更新目的,不需要使用個別Column操作setVisable(false)及setVisable(true) return subtotal; } ///... } TableColumn<CostAnalytics, Double> subtotal = new TableColumn<CostAnalytics, Double>( "小計"); subtotal.setCellValueFactory(new Callback<CellDataFeatures<CostAnalytics, Double>, ObservableValue<Double>>() { public ObservableValue<Double> call( CellDataFeatures<CostAnalytics, Double> p) { WritableObjectValue<Double> result = p.getValue().getSubtotal();// //利用WritableObjectValue達到自動更新目的,不需要使用個別Column操作setVisable(false)及setVisable(true) // return (ObservableValue<Double>) // result;//利用WritableObjectValue達到自動更新目的,不需要使用個別Column操作setVisable(false)及setVisable(true) // return new // ReadOnlyObjectWrapper<Double>(p.getValue().getSubtotal());//造成無法自動更新return (ObservableValue<Double>) p.getValue().getSubtotal();// 利用WritableObjectValue達到自動更新目的,不需要使用個別Column操作setVisable(false)及setVisable(true) } }); 
-10
31 '15 8:35
source share



All Articles