JavaFX 2.1 TableView refresh items

JavaJavafxTableviewJavafx 8Fxml

Java Problem Overview


I have this common issue, as it appears to be. My table view wont refresh my items after I reset them. I have checked the data and it's the new one.

I tried multiple solution from internet but no success.

Can't reset all the columns because it adds one empty one extra (dont know why) and the resize just breakes.

My table is not editable. The new data is changed.

The data is refreshed if I change the ordering of the items and the rows change (:|).

I'm just left without ideas.

At the moment the refresh code is pretty simple.

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

Again the new data is correct. When I make an selection to the tableView it returns the new correct Item.

Java Solutions


Solution 1 - Java

Since JavaFX 8u60 you can use(assuming tableView is an instance of TableView class):

tableView.refresh();

From the documentation:

> Calling refresh() forces the TableView control to recreate and > repopulate the cells necessary to populate the visual bounds of the > control. In other words, this forces the TableView to update what it > is showing to the user. This is useful in cases where the underlying > data source has changed in a way that is not observed by the TableView > itself.

Solution 2 - Java

Workaround:

 tableView.getColumns().get(0).setVisible(false);
 tableView.getColumns().get(0).setVisible(true);

Solution 3 - Java

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

Assume ObservableList obsList is the underlying list for the TableView.

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

Also calling setItem(obsList) did not work to trigger a refresh...but...

obsList.removeAll(obsList) (overwritten by ObservableList) works fine because it fires the changeEvent correctly.

Refilling a list with completely new content then works as follows:

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

or

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

Solution 4 - Java

UPDATE:
Finally tableview refreshing is resolved in JavaFX 8u60, which is available for early access.


About refreshing see the Updating rows in Tableview.
And about the blank column see the JavaFx 2 create TableView with single column. Basically it is not a column, i.e. you cannot select the item clicking on this blank column items. It is just a blank area styled like a row.


UPDATE: If you are updating the tableView via reseller_table.setItems(data) then you don't need to use SimpleStringProperty. It would be useful if you were updating one row/item only. Here is a working full example of refreshing the 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);

are almost equivalent. So I used the one to fill the table for the first time and other when the table is refreshed. It is for demo purposes only. I have tested the code in JavaFX 2.1. And finally, you can (and should) edit your question to improve it by moving the code pieces in your answer to your question.

Solution 5 - Java

I finally found an ugly workaround to refresh 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);
        }
    });
 }

Solution 6 - Java

There seem to be several separate issues around oldItems.equals(newItems)

The first part of RT-22463: tableView won't update even if calling items.clear()

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

that's fixed. Clearing out the old items before setting a new list clears out all old state, thus refreshing the table. Any example where this doesn't work might be a regression.

What's still not working is re-setting items without clearing first

// refresh table
table.setItems(listEqualToOld); 

That's a problem if the table is showing properties that are not involved into an item's equal decision (see example in RT-22463 or Aubin's) and covered - hopefully - by RT-39094

UPDATE: RT-39094 the latter is fixed as well, for 8u40! Should bubble up into the ea in a couple of weeks, speculating on u12 or such.

The technical reason seems to be an equality check in cell's implementation: checking for changes of the item before actually calling updateItem(T, boolean) was introduced to fix performance problems. Reasonable, just to hard-code "change" == old.equals(new) poses problems in some contexts.

A work-around that's fine for me (no formal testing!) is a custom TableRow which jumps in if 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's index before update
     * @param oldItem cell's item before update
     * @param wasEmpty cell's 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 custom row doesn't suffice it might be necessary to use a custom TableCell with a similar workaround (haven't run into an example where that's needed, though)

Solution 7 - Java

I suppose this thread has a very good description of the problem with table refresh.

Solution 8 - Java

What a BUG ! 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've done a SSCCE to show the bug. I encourage everyone to fix it by another more elegant way because my workaround is very ugly!

Solution 9 - Java

I have an use case where nothing else helped as the solution from Aubin. I adapted the method and changed it by removing and adding an item to the tables' item list as it works in the end only reliable with this hack, the column visible toggle did the job only the first time.

I reported it also in the Jira task: 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);
   } 

Solution 10 - Java

I had the same problem and after some search this is my workaround. I found that if the columns are removed and then re-added 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);
}


Example of usage:

refreshTableView(myTableView, Arrays.asList(col1, col2, col3), rows);

Solution 11 - Java

The solution by user1236048 is correct, but the key point isn't called out. In your POJO classes used for the table's observable list, you not only have to set getter and setter methods, but a new one called Property. In Oracle's tableview tutorial (http://docs.oracle.com/javafx/2/ui_controls/table-view.htm), they left that key part off!

Here's what the Person class should look like:

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;
        }

}

Solution 12 - Java

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

a 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);

Solution 13 - Java

I have been trying to find a way to refresh the tableView(ScalaFx) for 3-4 hours. Finally I got a answer. I just want to publish my solution because of i wasted already hours.

-To retrieve the rows from database, i used to declare a method which returns 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 have created a TableView object.

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

-And Finally i got solution. In the refresh button, i have inserted this code;

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

model is the reference of my jdbc connection class

val model = new ScalaJdbcConnectSelect

This is the scalafx codes but it gives some idea to javafx

Solution 14 - Java

JavaFX8

I'm adding new Item by a DialogBox. Here is my code.

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

At initialize() 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 an ordinary JavaFX POJO. Hope this helps someone.

Solution 15 - Java

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);
 

Solution 16 - Java

Instead of refreshing manually you should use observeable properties. The answers of this question examples the purpose: https://stackoverflow.com/questions/13381067/simplestringproperty-and-simpleintegerproperty-tableview-javafx

Solution 17 - Java

Based on Daniel De León'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);
    }
}

Solution 18 - Java

My solution is similar to the the workaround of Daniel De León, but it also works when you need to hide the first column (index 0 in his example). Of course you could just change the index in his solution, but if you are rearranging the columns, my solution might work better for you. The idea is to hide and show the column by its name instead of hiding and showing 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, e.g. "First name"
    		if (column.getText().equals("Column Title")) {
    			column.setVisible(false);
    			column.setVisible(true);
    		}
    	}
	}
}

It's best to update your table in the UI update thread. However, it also works by just calling updateMyTableView(); after you've changed something in your table, since JavaFX seem to update in the UI thread anyway (not sure about that).

Platform.runLater(new Runnable() {
	public void run() {
         updateMyTableView();
	}
});

Solution 19 - Java

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

I change my table view based on queries / searches to a database. For example, a database table contains Patient data. My initial table view in my program contains all Patients. I can then search query for Patients by firstName and lastName. I use the results of this query to repopulate my Observable list. Then I reset the items in the tableview 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);
}

The if blocks update the ObservableList with the query results.

Solution 20 - Java

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

In initialize-method of controller, create an empty observableList and set it to the table:

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

In your update-method, just use the observableList, clear it and add the refreshed data:

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

It's not necessary to set the items of the table again

Solution 21 - Java

Following the answer of Daniel De León ...

  • I introduced a dummy property "modelChangedProperty" in my model and

  • created a method refresh() in my model that changes the value of that property.

  • In my controller I added a Listener to the dummy property that 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);
}

Solution 22 - Java

I know that this question is 4 years old but I have the same problem, I tried the solutions from above and didn't worked. I also called refresh() method but still not my expected result. So I post here my solution maybe 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 that before of this I used another variable in ObeservableList for setting items into the tableview, I call this a "filthy method" but until I get a better solution is ok.

Solution 23 - Java

for refresh my table I do this:

In my ControllerA who named RequisicionesController I do this

@FXML public TableView<Requisiciones>  reqtable;

public TableView<Requisiciones> getReqtable() {
	return reqtable;
}

public void setReqtable(TableView<Requisiciones> reqtable) {
	this.reqtable = reqtable;
}

in the FXML loader I get ControllerB who also named RevisionReqController

RevisionReqController updateReq = cargarevisionreq.<RevisionReqController>getController();
    
RequisicionesController.this.setReqtable(selecciondedatosreq());		   		  
updateReq.setGetmodeltable(RequisicionesController.this.getReqtable());

in my ControllerB I do this:

public TableView<Requisiciones>  getmodeltable;     
        
public TableView<Requisiciones> getGetmodeltable() {
   	return getmodeltable;
}
    
public void setGetmodeltable(TableView<Requisiciones> getmodeltable) {
    this.getmodeltable = getmodeltable;
}

then:

public void refresh () {
    mybutton.setonMouseClicked(e -> {
    ObservableList<Requisiciones> datostabla = FXCollections.observableArrayList();
    try {
        // rest of code

        String Query= " select..";
     
        PreparedStatement pss =Conexion.prepareStatement(Query);
        ResultSet rs = pss.executeQuery();
        while(rs.next()) {
            datostabla.add(new Requisiciones(
                // al requisiciones data
            ));
        }
        RevisionReqController.this.getGetmodeltable().getItems().clear();
   	    RevisionReqController.this.getGetmodeltable().setItems(datostabla);
    } catch(Exception ee) {
         //my message here
    }
}

so in my controllerA I just load the table with setCellValueFactory , that's its all.

Solution 24 - Java

You just need to clear the table and call the function that generates the filling of the table.

> ButtonRefresh.setOnAction((event) -> { > tacheTable.getItems().clear(); > PopulateTable(); > });

Solution 25 - Java

Well after looking for all the possible solutions. Tried clearing data first and then added in tableview tableView.getItems().clear(); still that does not resolved my problem. I tried all the answers given here but did not worked for me and I still had stale objects in my table as shown in image below:

enter image description here

In order to fix it I created a DUMMY label and used setGraphic as follows:

enter image description here

Solution 26 - Java

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

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

                                                           解決於台灣台北

I had firmed use change Column Visable Property is not conform data binding automation purpose.

After I traced JavaFX TableView source code. I never discovered any problem code for Tableview binding issue. After 4 weeks ago, I changed POJO field's type from DoubleProperty to WritableObjectValue, problem was solved.

                                               resolve in Taiwan Taipei.

Sample code:

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)
		}

	});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1236048View Question on Stackoverflow
Solution 1 - JavaElltzView Answer on Stackoverflow
Solution 2 - JavaDaniel De LeónView Answer on Stackoverflow
Solution 3 - JavaIngoView Answer on Stackoverflow
Solution 4 - JavaUluk BiyView Answer on Stackoverflow
Solution 5 - JavaJavarianView Answer on Stackoverflow
Solution 6 - JavakleopatraView Answer on Stackoverflow
Solution 7 - JavaAlexView Answer on Stackoverflow
Solution 8 - JavaAubinView Answer on Stackoverflow
Solution 9 - JavaAndreas NiemeyerView Answer on Stackoverflow
Solution 10 - JavaceklockView Answer on Stackoverflow
Solution 11 - JavaKevin ReynoldsView Answer on Stackoverflow
Solution 12 - JavaAndrei KrasutskiView Answer on Stackoverflow
Solution 13 - JavaMuhammed Yalçın KuruView Answer on Stackoverflow
Solution 14 - JavaSudhakar KrishnanView Answer on Stackoverflow
Solution 15 - Javauser1236048View Answer on Stackoverflow
Solution 16 - JavaAndreasView Answer on Stackoverflow
Solution 17 - JavaFlorin VirtejView Answer on Stackoverflow
Solution 18 - JavaMichaelView Answer on Stackoverflow
Solution 19 - Javauser2951579View Answer on Stackoverflow
Solution 20 - JavaTomView Answer on Stackoverflow
Solution 21 - JavaStefanView Answer on Stackoverflow
Solution 22 - JavaWolf MarianView Answer on Stackoverflow
Solution 23 - JavaRicardo RoaView Answer on Stackoverflow
Solution 24 - JavaM E S A B OView Answer on Stackoverflow
Solution 25 - JavaVishrantView Answer on Stackoverflow
Solution 26 - Java楊竣壹View Answer on Stackoverflow