Подтвердить что ты не робот

Обновления JavaFX 2.1 TableView

У меня такая распространенная проблема, как кажется. Мой вид таблицы не обновит мои объекты после я reset их. Я проверил данные, а новый.

Я попробовал несколько решений из Интернета, но не успел.

Невозможно reset все столбцы, потому что он добавляет один пустой лишний (не знаю почему) и просто изменяет размер.

Моя таблица не доступна для редактирования. Новые данные изменены.

Данные обновляются, если я изменить порядок элементов, а строки меняются (: |).

Я просто остался без идей.

В настоящий момент код обновления довольно прост.

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

Снова новые данные верны. Когда я делаю выбор в tableView, он возвращает новый правильный элемент.

4b9b3361

Ответ 1

У меня была аналогичная проблема с освежением. Мое решение состояло в том, чтобы ограничить операции над ObservableList теми, которые корректно работают с bind().

Предположим, что ObservableList obsList является базовым списком для TableView.

Тогда
obsList.clear() (унаследованный от java.util.List < > ) будет не обновлять таблицуView правильно, но.

Также вызов setItem (obsList) сделал не работает, чтобы вызвать обновление... но...

obsList.removeAll(obsList) (перезаписан ObservableList) отлично работает, потому что он правильно запускает changeEvent: -)

Заполняя список полностью новым контентом, он работает следующим образом:

  • obsList.removeAll(obsList);
  • obsList.add(...);//например. в цикле...

или

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

С наилучшими пожеланиями Ingo

Ответ 2

Обход проблемы:

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

Ответ 3

Так как JavaFX 8u60 вы можете использовать (предполагается, что tableView - это экземпляр класса TableView):

tableView.refresh();

Из документации:

Вызов refresh() заставляет элемент управления TableView воссоздать и повторно заполнить ячейки, необходимые для заполнения визуальных границ контроль. Другими словами, это заставляет TableView обновлять то, что он показывается пользователю. Это полезно в тех случаях, когда источник данных изменился таким образом, который не наблюдается в TableView сам по себе.

Ответ 4

UPDATE:
Наконец, обновление табличного представления разрешено в JavaFX 8u60, доступном для раннего доступа.


Об освежении см. Обновление строк в Tableview.
А про пустой столбец см. JavaFx 2 создайте TableView с одним столбцом. В принципе это не столбец, т.е. Вы не можете выбрать элемент, щелкнув по этим пустым элементам столбца. Это просто пустая область, стилизованная как строка.


UPDATE: Если вы обновляете 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. И, наконец, вы можете (и должны) изменить свой вопрос, чтобы улучшить его, переместив фрагменты кода в свой ответ на свой вопрос.

Ответ 5

Наконец-то я нашел уродливое обходное решение для обновления всех строк.

void refreshTable() {
    final List<Item> items = tableView.getItems();
    if( items == null || items.size() == 0) return;

    final Item item = tableView.getItems().get(0);
    items.remove(0);
    Platform.runLater(new Runnable(){
        @Override
        public void run() {
            items.add(0, item);
        }
    });
 }

Ответ 6

Я полагаю, этот поток имеет очень хорошее описание проблемы с обновлением таблицы.

Ответ 7

Кажется, что есть несколько отдельных проблем вокруг oldItems.equals(newItems)

Первая часть RT-22463: tableView не будет обновляться даже при вызове items.clear()

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

что исправлено. Очистка старых элементов перед установкой нового списка очищает все старые состояния, тем самым обновляя таблицу. Любой пример, когда это не работает, может быть регрессией.

Что еще не работает, это переустановка элементов без первой очистки

// refresh table
table.setItems(listEqualToOld); 

Это проблема, если в таблице отображаются свойства, которые не участвуют в равном решении элемента (см. пример в RT-22463 или Aubin) и покрыт - надеюсь - RT-39094

UPDATE: RT-39094 последнее исправлено, для 8u40! Должен пузыриться в ea через пару недель, размышляя о u12 или таком.

Техническая причина, по-видимому, является проверкой равенства в реализации ячеек: проверка изменений элемента перед фактическим вызовом updateItem (T, boolean) была введена для устранения проблем с производительностью. Разумный, просто для жесткого кода "change" == 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 index before update
     * @param oldItem cell item before update
     * @param wasEmpty cell empty before update
     */
    protected void updateItemIfNeeded(int oldIndex, T oldItem, boolean wasEmpty) {
        // weed out the obvious
        if (oldIndex != getIndex()) return;
        if (oldItem == null || getItem() == null) return;
        if (wasEmpty != isEmpty()) return;
        // here both old and new != null, check whether the item had changed
        if (oldItem != getItem()) return;
        // unchanged, check if it should have been changed
        T listItem = getTableView().getItems().get(getIndex());
        // update if not same
        if (oldItem != listItem) {
            // doesn't help much because itemProperty doesn't fire
            // so we need the help of the skin: it must listen
            // to invalidation and force an update if 
            // its super wouldn't get a changeEvent
            updateItem(listItem, isEmpty());
        }
    }


    @Override
    protected Skin<?> createDefaultSkin() {
        return new TableRowSkinX<>(this);
    }


    public static class TableRowSkinX<T> extends TableRowSkin<T> {

        private WeakReference<T> oldItemRef;
        private InvalidationListener itemInvalidationListener;
        private WeakInvalidationListener weakItemInvalidationListener;
        /**
         * @param tableRow
         */
        public TableRowSkinX(TableRow<T> tableRow) {
            super(tableRow);
            oldItemRef = new WeakReference<>(tableRow.getItem());
            itemInvalidationListener = o -> {
                T newItem = ((ObservableValue<T>) o).getValue();
                T oldItem = oldItemRef != null ? oldItemRef.get() : null;
                oldItemRef = new WeakReference<>(newItem);
                if (oldItem != null && newItem != null && oldItem.equals(newItem)) {
                    forceCellUpdate();
                }
            };
            weakItemInvalidationListener = new WeakInvalidationListener(itemInvalidationListener);
            tableRow.itemProperty().addListener(weakItemInvalidationListener);
        }

        /**
         * Try to force cell update for equal (but not same) items.
         * C&P'ed code from TableRowSkinBase.
         */
        private void forceCellUpdate() {
            updateCells = true;
            getSkinnable().requestLayout();

            // update the index of all children cells (RT-29849).
            // Note that we do this after the TableRow item has been updated,
            // rather than when the TableRow index has changed (as this will be
            // before the row has updated its item). This will result in the
            // issue highlighted in RT-33602, where the table cell had the correct
            // item whilst the row had the old item.
            final int newIndex = getSkinnable().getIndex();
            for (int i = 0, max = cells.size(); i < max; i++) {
                cells.get(i).updateIndex(newIndex);
            }
       }

    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(IdentityCheckingListCell.class.getName());

}

 // usage
 table.setRowFactory(p -> new IdentityCheckingTableRow());

Обратите внимание, что TableCell имеет аналогичную проверку жестко закодированного равенства, поэтому, если пользовательская строка не достаточна, может потребоваться использовать пользовательский TableCell с аналогичным обходным решением (не запущенный в пример, где это необходимо, хотя )

Ответ 8

Что за ошибка! Вот еще одно обходное решение...

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 в показать ошибку. Я призываю всех исправить это еще более элегантным способом, потому что мой обход очень уродлив!

Ответ 9

У меня есть вариант использования, где ничего не помогло как решение от Aubin. Я адаптировал метод и изменил его, удалив и добавив элемент в список элементов таблицы, поскольку он работает в конце, только надежно с этим хаком, столбец, отображаемый для переключения, выполнил задание только в первый раз.

Я сообщил об этом также в задаче Джиры:  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);
   } 

Ответ 10

У меня была такая же проблема, и после некоторого поиска это было моим обходным решением. Я обнаружил, что если столбцы удалены, а затем снова добавлены, таблица обновляется.

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

Ответ 11

Решение пользователя1236048 является правильным, но ключевой момент не вызывается. В ваших классах POJO, используемых для списка наблюдаемых таблиц, вам необходимо не только устанавливать методы getter и setter, но и новый, называемый Property. В учебнике 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;
        }

}

Ответ 13

На основании ответа Даниэля Де Леона

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

Ответ 14

Взгляните на эту проблему в Джире: 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);

Ответ 15

JavaFX8

Я добавляю новый элемент в DialogBox. Вот мой код.

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 является обычным POJO JavaFX. Надеюсь, это поможет кому-то.

Ответ 16

метод 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);

Ответ 17

Мое решение похоже на обходное решение Daniel De Leó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);
            }
        }
    }
}

Лучше всего обновить таблицу в потоке обновления пользовательского интерфейса. Однако он также работает, просто вызывая updateMyTableView(); после того, как вы что-то изменили в своей таблице, поскольку JavaFX, похоже, все равно обновляется в потоке пользовательского интерфейса (не уверен в этом).

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

Ответ 18

Я не уверен, что это относится к вашей ситуации, но я опубликую то, что сработало для меня.

Я изменяю свое табличное представление на основе запросов/поисков в базе данных. Например, таблица базы данных содержит данные пациента. В моем первоначальном представлении таблицы в моей программе содержатся все пациенты. Затем я могу выполнить поиск запросов для пациентов по имени firstName и lastName. Я использую результаты этого запроса для повторного заполнения списка Observable. Затем я reset элементы в представлении таблицы, вызывая 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 с результатами запроса.

Ответ 19

Такая же проблема здесь, я пробовал некоторые решения, и лучшее для меня следующее:

В initialize-методе контроллера создайте пустой наблюдаемый список и установите его в таблицу:

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

В вашем методе обновления просто используйте наблюдаемый список, очистите его и добавьте обновленные данные:

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

Нет необходимости снова устанавливать элементы таблицы

Ответ 20

Следуя ответам Даниэля Де Леона...

  • В моей модели я представил фиктивное свойство "modelChangedProperty" и
  • создал метод 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);
}

Ответ 21

Я знаю, что этот вопрос составляет 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, я называю это "грязным методом", но пока я не получу лучшее решение, это нормально.

Ответ 22

Я пытаюсь найти способ обновить 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

Ответ 23

我 始終 認為 利用 更改 TableColumn 的 的 видимые 方法 屬性 違反 привязки данных 的 精神, 若 這 是 的 JavaFX ошибка 那 也 早就 該 接 決 了, 不 應該 拖到 Java8 了 還不 解決.

經過 трассировка JavaFX 的 исходный код 後, 並 沒有 發現 ошибка. 利用 Слушатель 等 方法 觀察 也 沒有 異樣. 也 嘗試 利用 JFace 中 的 СвойствоChangeSupport 方式 宣告 POJO 內容 變更 也 沒有 效果. 最後 將 DoubleProperty 改為 WritableObjectValue, 問 提就 解決 了.

                                                           解決於台灣台北

У меня было подтвержденное изменение использования. Свойство Column Visable не соответствует цели автоматизации привязки данных.

После того, как я проследил исходный код 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)
        }

    });