JavaFX 2.1 TableView刷新项目
我有这个共同的问题,因为它似乎是。 我重置他们后,我的表格视图不会刷新我的项目。 我已经检查了数据,这是新的。
我尝试了互联网的多种解决scheme,但没有成功
无法重置所有的列,因为它增加了一个空的额外(不知道为什么)和resize刚刚打破。
我的表是不可编辑的 。 新数据已更改。
如果更改项目的顺序并更改行(:|),数据将刷新。
我只是没有想法而离开。
目前刷新代码非常简单。
ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data);
新的数据也是正确的。 当我对tableView进行select时,它会返回新的正确的Item。
我有一个类似的问题清爽。 我的解决scheme是将ObservableList上的操作限制为可以正确使用bind()的操作。
假设ObservableList obsList是TableView的底层列表。
然后
obsList.clear() (inheritance自java.util.List <>) 不会正确更新 tableView。
另外调用setItem(obsList) 无法触发刷新…但…
obsList.removeAll(obsList) (由ObservableList覆盖) 工作正常,因为它正确地触发changeEvent 🙂
用全新的内容重新填充列表,然后按如下方式工作:
- obsList.removeAll(obsList);
- obsList.add(…); //例如在循环中…
要么
- obsList.removeAll(obsList);
- FXCollections.copy(obsList,someSourceList)
最好的问候Ingo
解决方法:
tableView.getColumns().get(0).setVisible(false); tableView.getColumns().get(0).setVisible(true);
既然JavaFX 8u60
可以使用(假设tableView
是TableView类的一个实例):
tableView.refresh();
从文档:
调用refresh()强制TableView控件重新创build并重新填充必要的单元格以填充控件的可视范围。 换句话说,这迫使TableView更新它向用户显示的内容。 这在底层数据源以TableView本身没有观察到的方式发生变化的情况下非常有用。
更新:
最后,在JavaFX 8u60中解决了tableview的刷新问题。
关于刷新,请参阅更新Tableview中的行 。
而关于空白栏,请参阅JavaFx 2创build单列的TableView 。 基本上它不是一个列,即你不能select项目点击这个空白列项目。 这只是一个像一排风格的空白区域。
更新:如果通过reseller_table.setItems(data)
更新tableView,则不需要使用SimpleStringProperty
。 如果您仅更新一行/项目,这将是有用的。 以下是刷新表数据的完整示例:
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); } }
注意
productTable.setItems(FXCollections.observableArrayList(newProducts));
和
productTable.getItems().clear(); productTable.getItems().addAll(newProducts);
几乎相同。 所以我用这个来第一次填表,其他时候刷新表格。 仅用于演示目的。 我已经testing了JavaFX 2.1中的代码。 最后,你可以(也应该)编辑你的问题,通过移动你的问题答案中的代码块来改善它。
我终于find了一个丑陋的解决方法来刷新所有行。
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); } }); }
oldItems.equals(newItems)似乎有几个单独的问题,
RT-22463的第一部分:即使调用items.clear(),tableView也不会更新。
// refresh table table.getItems().clear(); table.setItems(listEqualToOld);
这是固定的。 在设置新列表之前清除旧项目会清除所有旧状态,从而刷新表格。 任何例子,这不起作用可能是一个回归。
什么还没有工作是重新设置项目,而不先清除
// refresh table table.setItems(listEqualToOld);
如果表格显示的是不涉及项目平等决策的属性(请参阅RT-22463或Aubin的示例),并希望通过RT-39094
更新 : RT-39094后者也是固定的,为8u40! 应该在几个星期之内泡进EA,投机于U12或者其他。
技术原因似乎是在单元实现中进行相等性检查:在实际调用updateItem(T,boolean)之前检查项目的更改以解决性能问题。 合理的,只是硬编码“改变”== old.equals(新)在某些情况下造成问题。
解决方法对我来说很好(没有正式的testing!)是一个自定义的TableRow,如果需要身份检查,它将跳转:
/** * 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());
请注意,TableCell具有类似的硬编码的相等性检查,所以如果自定义行不够,可能需要使用类似解决方法的自定义TableCell(虽然没有运行到需要的示例中)
我想这个线程有一个很好的表刷新问题的描述。
什么错误! 这是另一个解决方法…
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 ); }
我已经做了一个SSCCE来显示错误 。 我鼓励大家用另一种更优雅的方式修复它,因为我的解决方法非常难看!
我有一个用例,没有别的帮助作为奥宾的解决scheme。 我调整了方法,并通过删除和添加一个项目到表中的项目列表来改变它,因为它在最后工作到最后只有这个黑客可靠,列可见切换只在第一次完成了这项工作。
我也在Jira的任务中报告过: 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); }
我有同样的问题,并经过一些search这是我的解决方法。 我发现,如果列被删除,然后重新添加表更新。
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); }
使用示例:
refreshTableView(myTableView, Arrays.asList(col1, col2, col3), rows);
用户1236048的解决scheme是正确的,但关键点不被调出。 在用于表的可观察列表的POJO类中,不仅需要设置getter和setter方法,而且还要设置一个名为Property的新方法。 在Oracle的tableview教程( http://docs.oracle.com/javafx/2/ui_controls/table-view.htm )中,他们将关键部分closures了!
Person类应该是这样的:
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; }
}
而不是手动刷新你应该使用可观察的属性。 这个问题的答案举例说明了目的: SimpleStringProperty和SimpleIntegerProperty TableView JavaFX
根据丹尼尔德莱昂的答案
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); } }
在Jira看看这个问题: https : //bugs.openjdk.java.net/browse/JDK-8098085
2012-09-20 08:50发表了一个解决方法。
//wierd JavaFX bug reseller_table.setItems(null); reseller_table.layout(); ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data);
JavaFX8
我正在通过DialogBox添加新项目。 这是我的代码。
ObservableList<Area> area = FXCollections.observableArrayList();
在initialize()或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; } }
通过对话框添加。
@FXML private void handleNewArea() { Area tempArea = new Area(); boolean okClicked = showAreaDialog(tempArea); if (okClicked) { addNewArea(tempArea); this.area.add(tempArea); // To inform ObservableList } }
Area
是一个普通的JavaFX POJO。 希望这有助于某人。
initialize()方法
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);
用户类(Hibernate POJO类)
private SimpleStringProperty test; public void setFullName(String fullName) { this.fullName = fullName; this.test = new SimpleStringProperty(fullName); } public SimpleStringProperty testProperty() { return test; }
refresh()方法
ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data);
我的解决scheme类似于Daniel DeLeón的解决方法,但是当您需要隐藏第一列(他的示例中的索引0)时,它也起作用。 当然,你可以在他的解决scheme中改变索引,但是如果你正在重新安排列,我的解决scheme可能会更好地为你工作。 这个想法是隐藏和显示列的名称,而不是隐藏和显示它的索引:
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); } } } }
最好在UI更新线程中更新你的表格。 但是,它也可以通过调用updateMyTableView();
在你的表中改变了一些东西之后,因为JavaFX似乎在UI线程中更新(不确定)。
Platform.runLater(new Runnable() { public void run() { updateMyTableView(); } });
我不确定这是否适用于您的情况,但我会发布对我有用的东西。
我基于查询/search将我的表视图更改为数据库。 例如,数据库表包含患者数据。 我的程序中的初始表格视图包含所有患者。 然后,我可以通过firstName和lastNamesearch患者的查询。 我使用这个查询的结果来重新填充我的Observable列表。 然后我通过调用tableview.setItems(observableList)来重置tableview中的项目:
/** * 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块用查询结果更新ObservableList。
同样的问题在这里,我尝试了一些解决scheme,最适合我的是:
在控制器的初始化方法中,创build一个空的observableList并将其设置为表:
obsBericht = FXCollections.observableList(new ArrayList<Bericht>(0)); tblBericht.setItems(obsBericht);
在你的update-method中,只需使用observableList,清除它并添加刷新的数据:
obsBericht.clear(); obsBericht.addAll(FXCollections.observableList(DatabaseHelper.getBerichte())); // tblBericht.setItems(obsBericht);
没有必要再次设置表格的项目
在丹尼尔德莱昂的回答之后…
- 我在模型中引入了一个虚拟属性“modelChangedProperty”
- 在我的模型中创build了一个方法refresh()来改变这个属性的值。
- 在我的控制器中,我添加了一个Listener到更新表视图的dummy属性。
–
/** * 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); }
我知道这个问题是4岁,但我有同样的问题,我尝试了上面的解决scheme,没有工作。 我也叫refresh()方法,但仍然不是我预期的结果。 所以我在这里发布我的解决scheme可能会帮助别人。
Question db = center.getSelectionModel().getSelectedItem(); new QuestionCrud().deleteQ(db.getId()); ObservableList<Question> aftDelete = FXCollections.observableArrayList( (new QuestionCrud()).all() ); center.setItems(aftDelete);
即使在这之前,我用ObeservableList中的另一个variables来设置项目到tableview,我称之为“肮脏的方法”,但直到我得到一个更好的解决scheme是好的。
我一直在试图find一种刷新tableView(ScalaFx)3-4小时的方法。 最后我得到了答案。 我只是想发布我的解决scheme,因为我已经浪费了几个小时。
– 为了从数据库中检索行,我用来声明一个返回ObservableBuffer的方法。
我的JDBC类
//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 }
而且我创build了一个TableView对象。
var table = new TableView[Customer](model.getCustomerDetails) table.columns += (customerIdColumn,customerNameColumn,productInstallColumn,serviceDateColumn, productNameColumn,phoneNoColumn,detailColumn)
最后我得到了解决scheme。 在刷新button中,我已经插入了这个代码;
table.setItems(FXCollections.observableArrayList(model.getCustomerDetails.delegate))
模型是我的jdbc连接类的参考
val model = new ScalaJdbcConnectSelect
这是scalafx代码,但它给了javafx一些想法
我始终认为利用更改的TableColumn的visable属性的方法违反数据绑定的精神,若这是JavaFX的错误的那也早就该接决了,不应该拖到Java8了还不解决。
经过跟踪JavaFX的源代码后,并没有发现bug。利用Listener等方法观察也没有异样。也尝试利用JFace中的PropertyChangeSupport方式宣告POJO内容变更也没有效果。最后将DoubleProperty改为WritableObjectValue,问提就解决了。
解決於台灣台北
我坚决使用改变Column Visable Property不符合数据绑定自动化的目的。
我跟踪了JavaFX TableView的源代码。 我从来没有发现任何问题的Tableview绑定问题的代码。 4周之前,我将POJO字段的types从DoubleProperty更改为WritableObjectValue,问题解决了。
resolve in Taiwan Taipei.
示例代码:
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) } });