JavaFX 2.1 TableView обновить элементы
У меня есть эта общая проблема, как это кажется. Мое представление таблицы не будет обновлять мои элементы после их сброса. Я проверил данные, и это новый.
Я пробовал несколько решений из интернета, но без успеха.
не удается сбросить все столбцы, потому что он добавляет один пустой один дополнительный (не знаю, почему) и размер просто ломается.
моя таблица не редактировать. Новые данные будут изменены.
данные обновляется, если я изменить заказ изменения элементов и строк (:/).
Я просто остался без идей.
на данный момент код обновления довольно прост.
ObservableList<User> data = FXCollections.observableArrayList(User.getResellers());
reseller_table.setItems(data);
снова новые данные верны. Когда я делаю выбор в tableView он возвращает новый правильный элемент.
24 ответа:
у меня была похожая проблема с обновлением. Мое решение состояло в том, чтобы ограничить операции на
ObservableList
для тех, кто работает правильно сbind()
.предположим
ObservableList obsList
является базовым списком дляTableView
.затем
obsList.clear()
(наследуется отjava.util.List<>
) составит обновление theTableView
правильно, но.призвал
setItem(obsList)
сделал не работает чтобы вызвать a обновить...но...
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 класс):tableView.refresh();
из документации:
вызов refresh () заставляет элемент управления TableView воссоздавать и повторно заполнить ячейки, необходимые для заполнения визуальных границ управление. Другими словами, это заставляет TableView обновлять то, что он показывает пользователю. Это полезно в тех случаях, когда основное источник данных изменился в некотором роде что не наблюдается в TableView для себя.
обновление:
Наконец обновление tableview разрешается в JavaFX 8u60, который доступен для раннего доступа.
об обновлении см. обновление строк в Tableview.
А про пустую колонку смотрите в JavaFx 2 создать TableView с одним столбцом. В основном это не столбец, т. е. вы не можете выбрать элемент, нажав на этот пустой столбец элементов. Это просто пустая область, стилизованная под ряд.
обновление: если вы обновляете tableView через
reseller_table.setItems(data)
тогда вам не нужно использовать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);
практически эквивалентны. Поэтому я использовал один, чтобы заполнить таблицу в первый раз, и другой, когда таблица обновляется. Это для демонстрации только цели. Я проверил код в 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.равна(newItems)
первая часть RT-22463: tableView не будет обновляться даже при вызове элементов.очистить()
// refresh table table.getItems().clear(); table.setItems(listEqualToOld);
это исправлено. Очистка старых элементов Перед установкой нового списка очищает все старые состояния, тем самым обновляя таблицу. Любой пример, где это не работает, может быть регрессией.
что все еще не работает, это переустановка элементов без очистки первый
// refresh table table.setItems(listEqualToOld);
это проблема, если таблица показывает свойства, которые не участвуют в равном решении элемента (см. пример в RT-22463 или Обен) и - надеюсь - с RT-39094
обновление:RT-39094 последний также исправлен, для 8u40! Должен всплыть в Советник через пару недель, спекулируя на u12 или таком.
кажется, что техническая причина проверка равенства в реализации ячейки: проверка изменений элемента перед фактическим вызовом updateItem (T, boolean) была введена для устранения проблем с производительностью. Разумно, просто для жесткого кода "изменить" = = старый.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 имеет аналогичную жестко закодированную проверку равенства, поэтому если пользовательская строка не достаточно может потребоваться использовать пользовательскую табличную ячейку с аналогичным обходным путем (не сталкивались с примером, где это необходимо, хотя)
Я думаю этой теме имеет очень хорошее описание проблемы с обновлением таблицы.
какая ошибка ! Вот еще один обходной путь...
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 до показать ошибки. Я призываю всех исправить это другим более элегантным способом, потому что мой обходной путь очень уродлив!
У меня есть прецедент, когда ничто другое не помогло как решение от Aubin. Я адаптировал метод и изменил его, удалив и добавив элемент в список элементов таблиц, поскольку он работает в конце концов только надежно с этим взломом, столбец visible toggle выполнил работу только в первый раз.
Я сообщил об этом также в задаче 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); }
у меня была та же проблема и после некоторых поиск это мое решение. Я обнаружил, что если столбцы удаляются, а затем повторно добавляются, таблица обновляется.
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 является правильным, но ключевой момент не вызывается. В ваших классах POJO, используемых для наблюдаемого списка таблицы, вам нужно не только установить методы getter и setter, но и новое свойство. В учебнике Oracle tableview (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; }
}
вместо обновления вручную вы должны использовать наблюдаемые свойства. Ответы на этот вопрос примеры цели: 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
я добавляю новый элемент с помощью диалогового окна. Вот мой код.
ObservableList<Area> area = FXCollections.observableArrayList();
при инициализации () или 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 () 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);
класс пользователя (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 ()
ObservableList<User> data = FXCollections.observableArrayList(User.getResellers()); reseller_table.setItems(data);
мое решение похоже на обходной путь Даниэль Де Леон, но он также работает, когда вам нужно скрыть первый столбец (индекс 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); } } } }
лучше всего обновить таблицу в потоке обновления пользовательского интерфейса. Тем не менее, он также работает, просто позвонив
updateMyTableView();
после того, как вы что-то изменили в своей таблице, так как JavaFX, похоже, обновляется в потоке пользовательского интерфейса в любом случае (не уверен в этом).Platform.runLater(new Runnable() { public void run() { updateMyTableView(); } });
Я не уверен, что это относится к вашей ситуации, но я опубликую то, что сработало для меня.
Я изменяю представление таблицы на основе запросов / поисков в базе данных. Например, таблица базы данных содержит данные пациента. Мой первоначальный вид таблицы в моей программе содержит всех пациентов. Затем я могу искать запрос для пациентов по имени и фамилии. Я использую результаты этого запроса для повторного заполнения моего наблюдаемого списка. Затем я сбрасываю элементы в tableview, вызывая 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 обновляют список ObservableList с результатами запроса.
та же проблема здесь, я попробовал некоторые решения и лучшее для меня следующее:
в initialize-методе контроллера создайте пустой observableList и установите его в таблицу:
obsBericht = FXCollections.observableList(new ArrayList<Bericht>(0)); tblBericht.setItems(obsBericht);
в вашем методе обновления просто используйте observableList, очистите его и добавьте обновленные данные:
obsBericht.clear(); obsBericht.addAll(FXCollections.observableList(DatabaseHelper.getBerichte())); // tblBericht.setItems(obsBericht);
нет необходимости снова устанавливать элементы таблицы
после ответа Даниэля Де Леона ...
- Я ввел фиктивное свойство "modelChangedProperty" в моей модели и
- создал метод refresh () в моей модели, который изменяет значение этого свойства.
- в моем контроллере я добавил прослушиватель к фиктивному свойству, которое обновляет представление таблицы.
-
/** * 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 года, но у меня та же проблема, я пробовал решения сверху и не работал. Я также вызвал метод refresh (), но все еще не мой ожидаемый результат. Поэтому я размещаю здесь свое решение, возможно, поможет кому-то.
Question db = center.getSelectionModel().getSelectedItem(); new QuestionCrud().deleteQ(db.getId()); ObservableList<Question> aftDelete = FXCollections.observableArrayList( (new QuestionCrud()).all() ); center.setItems(aftDelete);
даже то, что до этого я использовал другую переменную в ObeservableList для установки элементов в tableview, я называю это "грязным методом", но пока я не получу лучшее решение, все в порядке.
Я пытался найти способ обновить tableView (ScalaFx) в течение 3-4 часов. Наконец я получил ответ. Я просто хочу опубликовать свое решение, потому что я потратил уже несколько часов.
-чтобы получить строки из базы данных, я использовал, чтобы объявить метод, который возвращает 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
Ну после поиска всех возможных решений. Сначала попробовал Очистить данные, а затем добавил в tableview
tableView.getItems().clear();
тем не менее, это не решило мою проблему. Я попробовал все ответы, приведенные здесь, но не работал для меня, и у меня все еще были устаревшие объекты в моей таблице, как показано на рисунке ниже:чтобы исправить это, я создал фиктивную метку и использовал
setGraphic
следующим образом:
我始終認為利用更改TableColumn的visable屬性的方法違反databinding的精神,若這是JavaFX的bug那也早就該接決了,不應該拖到Java8了還不解決。
經過trace JavaFX с 的source code後,並沒有發現bug。利用Listener等方法觀察也沒有異樣。也嘗試利用JFace中的PropertyChangeSupport方式宣告pojo內容變更也沒有效果。最後將DoubleProperty 改為WritableObjectValue,問提就解決了。
解決於台灣台北
Я имел фиксированный использовать колонку изменения свойств видимых не соответствуют обязательным целях автоматизации данных.
после того, как я проследил исходный код JavaFX TableView. Я никогда не обнаруживал никакого проблемного кода для Проблема привязки Tableview. После того, как 4 недели назад я изменил тип поля POJO с 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) } });