よくあることですが、この共通の問題があります。テーブルビューでは、アイテムをリセットした後、アイテムが更新されません。私はデータをチェックしましたが、それは新しいものです。
インターネットから複数のソリューションを試しましたが、成功しませんでした。
すべての列をリセットできません。空の列が1つ余分に追加され(理由はわかりません)、サイズ変更が中断するだけです。
私のテーブルは編集可能ではありません。新しいデータが変更されます。
データが更新されるのは、アイテムのI 順序の変更と行の変更(:|)の場合です。
私はアイデアがなかった。
現時点では、更新コードは非常に簡単です。
ObservableList<User> data = FXCollections.observableArrayList(User.getResellers());
reseller_table.setItems(data);
再び、新しいデータは正しいです。 tableViewを選択すると、新しい正しいItemが返されます。
リフレッシュに関しても同様の問題がありました。私の解決策は、ObservableList
の操作をbind()
で正しく動作するものに制限することでした。
ObservableList obsList
がTableView
の基になるリストであると仮定します。
次にobsList.clear()
(Java.util.List<>
から継承)は、更新ではなくTableView
は正しくなります。
また、setItem(obsList)
を呼び出して動作しない更新をトリガーしました...しかし...
obsList.removeAll(obsList)
(ObservableList
で上書き)正常に動作します changeEventを正しく起動するため。
完全に新しいコンテンツでリストを補充すると、次のように機能します。
obsList.removeAll(obsList);
obsList.add(...); //e.g. in a loop...
または
obsList.removeAll(obsList);
FXCollections.copy(obsList, someSourceList)
敬具インゴ
回避策:
tableView.getColumns().get(0).setVisible(false);
tableView.getColumns().get(0).setVisible(true);
JavaFX 8u60
を使用できるため(tableView
は TableView classのインスタンスであると仮定):
tableView.refresh();
ドキュメントから:
Refresh()を呼び出すと、TableViewコントロールは、コントロールの視覚的な境界を設定するために必要なセルを強制的に再作成および再設定します。言い換えると、これにより、TableViewはユーザーに表示されているものを強制的に更新します。これは、基になるデータソースがTableView自体で観察されない方法で変更された場合に役立ちます。
UPDATE:
最後に、Tableviewの更新はJavaFX 8u60で解決されます。これは早期アクセスに使用できます。
更新については Tableviewの行の更新 をご覧ください。
そして空白の列については JavaFx 2は単一列でTableViewを作成します を参照してください。基本的には列ではありません。つまり、この空白の列項目をクリックして項目を選択することはできません。行のようなスタイルの単なる空白の領域です。
UPDATE:reseller_table.setItems(data)
を介してtableViewを更新する場合、SimpleStringProperty
を使用する必要はありません。 1つの行/アイテムのみを更新する場合に役立ちます。次に、テーブルデータを更新する完全な実例を示します。
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);
ほぼ同等です。そこで、最初にテーブルを埋めるために1つを使用し、テーブルが更新されたときにもう1つを使用しました。デモのみを目的としています。 JavaFX 2.1でコードをテストしました。最後に、質問への回答のコード部分を移動することにより、質問を編集して改善することができます(また、そうする必要があります)。
最終的に、すべての行を更新するい回避策を見つけました。
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-2246 の最初の部分:items.clear()を呼び出してもtableViewは更新されません
// refresh table
table.getItems().clear();
table.setItems(listEqualToOld);
それは修正されました。新しいリストを設定する前に古いアイテムを消去すると、古い状態がすべて消去され、テーブルが更新されます。これが機能しない例は、リグレッションです。
まだ機能していないのは、最初にクリアせずにアイテムを再設定することです
// refresh table
table.setItems(listEqualToOld);
テーブルがアイテムの同等の決定に関係しないプロパティを表示している場合は問題です( RT-2246 または Aubin's の例を参照)-できれば-によって- RT-39094
UPDATE: RT-39094 後者も8u40で修正されました!数週間でeaにバブルアップし、u12などで推測されるはずです。
技術的な理由は、セルの実装の等価性チェックであるようです。実際にupdateItem(T、boolean)を呼び出す前にアイテムの変更をチェックして、パフォーマンスの問題を修正しました。合理的で、単に「変更」をハードコードする== old.equals(new)は、いくつかのコンテキストで問題を引き起こします。
私にとって大丈夫な回避策(正式なテストはありません!)は、アイデンティティチェックが必要な場合にジャンプするカスタム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を使用する必要がある場合があります(ただし、必要な場合は実行しません)
このスレッド には、テーブルの更新に関する問題の非常に良い説明があると思います。
User1236048による解決策は正しいですが、重要な点は指摘されていません。テーブルの監視可能リストに使用されるPOJOクラスでは、ゲッターメソッドとセッターメソッドだけでなく、プロパティと呼ばれる新しいメソッドを設定する必要があります。 Oracleのテーブルビューチュートリアル( http://docs.Oracle.com/javafx/2/ui_controls/table-view.htm )では、重要な部分は省略されています!
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;
}
}
Aubinのソリューションとして他に何も役に立たないユースケースがあります。このハックで最終的に信頼できるだけで動作するため、メソッドを適応させ、テーブルのアイテムリストにアイテムを削除して追加することで変更しました。
Jiraタスクでも報告しました: https://javafx-jira.kenai.com/browse/RT-2246
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);
}
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);
私は同じ問題を抱えていて、いくつかの検索の後、これは私の回避策です。列を削除してから再度追加すると、テーブルが更新されることがわかりました。
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);
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です。これが誰かを助けることを願っています。
3〜4時間、tableView(ScalaFx)を更新する方法を探しています。ついに答えが返ってきました。すでに何時間も無駄になっているため、ソリューションを公開したいだけです。
-データベースから行を取得するには、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
}
-そして、私はTableViewオブジェクトを作成しました。
var table = new TableView[Customer](model.getCustomerDetails)
table.columns += (customerIdColumn,customerNameColumn,productInstallColumn,serviceDateColumn,
productNameColumn,phoneNoColumn,detailColumn)
-そして最後に解決策を得ました。更新ボタンに、このコードを挿入しました。
table.setItems(FXCollections.observableArrayList(model.getCustomerDetails.delegate))
モデルは私のjdbc接続クラスの参照です
val model = new ScalaJdbcConnectSelect
これはscalafxコードですが、javafxに何らかのアイデアを与えます
なんてバグ!ここに別の回避策があります...
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 を バグを表示 にした。私の回避策は非常にいので、誰もが別のよりエレガントな方法で修正することをお勧めします!
ここで同じ問題、私はいくつかの解決策を試してみましたが、私にとって最善は次のとおりです:
コントローラーのinitialize-methodで、空のobservableListを作成し、テーブルに設定します。
obsBericht = FXCollections.observableList(new ArrayList<Bericht>(0));
tblBericht.setItems(obsBericht);
更新メソッドで、observableListを使用し、それをクリアして、更新されたデータを追加します。
obsBericht.clear();
obsBericht.addAll(FXCollections.observableList(DatabaseHelper.getBerichte()));
// tblBericht.setItems(obsBericht);
テーブルのアイテムを再度設定する必要はありません
これがあなたの状況に当てはまるかどうかはわかりませんが、うまくいったことを投稿します。
データベースへのクエリ/検索に基づいてテーブルビューを変更します。たとえば、データベーステーブルには患者データが含まれています。私のプログラムの最初のテーブルビューには、すべての患者が含まれています。次に、firstNameとlastNameで患者のクエリを検索できます。このクエリの結果を使用して、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を更新します。
私の解決策は Daniel DeLeón の回避策に似ていますが、最初の列(彼の例ではインデックス0)を非表示にする必要がある場合にも機能します。もちろん、彼のソリューションでインデックスを変更することもできますが、列を再配置する場合は、私のソリューションがより適切に機能する可能性があります。インデックスで列を非表示および表示するのではなく、名前で列を非表示および表示するという考え方です。
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);
}
}
}
}
UI更新スレッドでテーブルを更新することをお勧めします。ただし、テーブル内の何かを変更した後にupdateMyTableView();
を呼び出すだけでも機能します。JavaFXはとにかくUIスレッドで更新されるようだからです(それについてはわかりません)。
Platform.runLater(new Runnable() {
public void run() {
updateMyTableView();
}
});
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);
手動で更新する代わりに、監視可能なプロパティを使用する必要があります。この質問の答えは、目的の例です。 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);
}
}
私はこの質問が4歳であることを知っていますが、私は同じ問題を抱えています。私は上記の解決策を試みましたが、うまくいきませんでした。また、refresh()メソッドを呼び出しましたが、まだ期待した結果ではありません。だから私はここに私の解決策を投稿すると誰かの助けになるでしょう。
Question db = center.getSelectionModel().getSelectedItem();
new QuestionCrud().deleteQ(db.getId());
ObservableList<Question> aftDelete = FXCollections.observableArrayList(
(new QuestionCrud()).all()
);
center.setItems(aftDelete);
この前に、テーブルビューに項目を設定するためにObeservableListの別の変数を使用しましたが、これを「不潔なメソッド」と呼びますが、より良い解決策が得られるまでは大丈夫です。
ダニエル・デ・レオンの答えに従って...
-
/**
* 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);
}