本文介绍了ListView控件不反映变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个TableView中前阵子和注册属性到每个TableColumn来的。内部数据的编辑反映自己在TableView中回来就好了。

I created a TableView a while back and registered Properties to each of the TableColumns. Editing of the internal data reflected itself back in the TableView just fine.

通过一个ListView,但是,它是一个不同的故事。这些变化没有被立即显示,除非我关闭框架,然后再次打开它。

With a ListView, however, it is a different story. The changes are not being shown right away unless I close the frame and open it again.

我的ListView由ActionSteps的。请注意,我用JavaFX的豆属性。

My ListView consists of ActionSteps. Note that I used the Javafx beans properties.

package application.objects;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.function.IntPredicate;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class ActionStep {

   private StringProperty actionStepID;
   private ObjectProperty<LocalDate> dateSet, dateFinished;
   private StringProperty stepName;
   private IntegerProperty completion;
   private ArrayList<StepComment> comments;



   public ActionStep(String name) {
      actionStepID = new SimpleStringProperty();
      stepName = new SimpleStringProperty();
      dateSet = new SimpleObjectProperty<LocalDate>();
      dateFinished = new SimpleObjectProperty<LocalDate>();
      completion = new SimpleIntegerProperty();
      stepName.setValue(name);
   }



   public void setName(String name) {
      stepName.setValue(name);
   }



   public String getName() {
      return stepName.getValue();
   }



   public StringProperty stepNameProperty() {
      return actionStepID;
   }



   public void setID(String id) {
      actionStepID.setValue(id);
   }



   public String getID() {
      return actionStepID.get();
   }



   public StringProperty actionStepIDProperty() {
      return actionStepID;
   }



   public void setCompletion(int percent) {
      if (percent < 0 || percent > 100)
         return;
      completion.set(percent);
   }



   public int getCompletion() {
      return completion.get();
   }



   public IntegerProperty completionProperty() {
      return completion;
   }



   public void setDateSet(LocalDate date) {
      dateSet.set(date);
   }



   public LocalDate getDateSet() {
      return dateSet.get();
   }



   public ObjectProperty<LocalDate> dateSetProperty() {
      return dateSet;
   }



   public void setDateFinished(LocalDate date) {
      dateFinished.set(date);
   }



   public LocalDate getDateFinished() {
      return dateFinished.get();
   }



   public ObjectProperty<LocalDate> dateFinishedProperty() {
      return dateFinished;
   }



   public String toString() {
      return stepNameProperty().get();
   }

}

我的ListView控件使用一个ObservableList为好。

My ListView uses an ObservableList as well.

  @FXML
  private ListView<ActionStep> actionStepsListView;
  private ObservableList<ActionStep> listOfSteps;

  listOfSteps = FXCollections.observableArrayList();
  actionStepsListView.setItems(listOfSteps);
  if (plan != null) {
     ArrayList<ActionStep> arrayOfSteps = plan.getStepsArrayList();
     for (int i = 0; i < arrayOfSteps.size(); i++)
        listOfSteps.add(arrayOfSteps.get(i));
  } else
     plan = new ActionPlan();

如何来到ObservableList取得ListView中不反映自己的变化?我注意到,呼吁每一个对象的toString()ListView控件在ListView中显示它们的值,而不是将其绑定到他们的属性。

How come changes made to the ObservableList do not reflect themselves in the ListView? I noticed that the ListView called upon every object's toString() to display their values in the ListView, rather than binding it to their Properties.

我是什么做错了吗?我应该重写电池厂还是什么?

What am I doing wrong? Am I supposed to override a cell factory or something?

推荐答案

请注意,你试图做一些与细胞中的更复杂的的ListView 比你与在的TableView 细胞。在的TableView ,在单元格中显示的对象正在发生变化,所以很容易为细胞观察此。在的ListView ,你想要的单元格时,属于在单元格中显示的对象属性来更改的通知;这是一个另外的步骤中除去,所以你必须做一些额外的编码(虽然并不多,因为你会看到)。

Note that you're trying to do something more complex with the cells in your ListView than you were with the cells in the TableView. In the TableView, the objects displayed in the cells were changing, so it was easy for the cells to observe this. In the ListView, you want the cells to notice when properties that belong to the objects displayed in the cells change; this is one further step removed, so you have to do a bit of extra coding (though not much, as you'll see).

您可以创建一个自定义单元格工厂绑定到 stepNameProperty(),但它是棘手的(你必须确保解除绑定/移除旧的物品听众的updateItem()法)。

You could create a custom cell factory to bind to the stepNameProperty(), but it's tricky (you have to make sure to unbind/remove listeners from old items in the updateItem() method).

更简单的方法,不过,这是不是有据可查的是使用 ObservableList 与定义的提取。

The easier way, though, which isn't well documented is to use an ObservableList with an extractor defined.

首先,解决您的方法名:你在code你贴一些奇怪的不匹配。该的getX / setX的/ xProperty方法名称都应该匹配正确。即而不是

First, fix your method names: you have some weird mismatches in the code you posted. The getX/setX/xProperty method names should all match correctly. I.e. instead of

   public void setName(String name) {
      stepName.setValue(name);
   }



   public String getName() {
      return stepName.getValue();
   }



   public StringProperty stepNameProperty() {
      return actionStepID;
   }

你应该有

   public final void setName(String name) {
      stepName.setValue(name);
   }



   public final String getName() {
      return stepName.getValue();
   }


   public StringProperty nameProperty() {
      return stepName;
   }

和类似的其他属性访问方法。 (显然,字段的名称可以是任何你喜欢的,因为他们是私有的。)的

and similarly for the other property accessor methods. (Obviously, the names of the fields can be anything you like, as they're private.) Making the get/set methods final is good practice.

然后,创建具有提取名单。提取的是,在列表中的每个元素映射到的观测秒的数组,该列表将观察的功能。如果这些值的变化,它会火列表更新到列表中的观察员。由于您的 ActionStep 的toString()方法引用 nameProperty(),我假设你想要的的ListView 更新,如果 nameProperty()的变化。所以,你想要做的。

Then, create the list with an extractor. The extractor is a function that maps each element in the list to an array of Observables which the list will observe. If those values change, it will fire list updates to the list's observers. Since your ActionStep's toString() method references the nameProperty(), I assume you want the ListView to update if the nameProperty() changes. So you want to do

  listOfSteps = FXCollections.observableArrayList(
    actionStep -> new Observable[] { actionStep.nameProperty() } // the "extractor"
  );
  actionStepsListView.setItems(listOfSteps);

请注意,在早期版本的JavaFX 2.2的的ListView 没有正确观察名单更新事件;这是固定的(如果我没记错)前不久的Java 8的释放(由于标签问题JavaFX8,我假设你使用的是Java 8,所以你要在这里很好。)

Note that in earlier versions of JavaFX 2.2 the ListView did not properly observe the list for update events; this was fixed (if I remember correctly) shortly prior to the release of Java 8. (Since you tagged the question JavaFX8, I assume you're using Java 8 and so you should be fine here.)

如果您不使用Java 8,可以使用以下(折合但更详细)code:

If you are not using Java 8, you can use the following (equivalent but more verbose) code:

listOfSteps = FXCollections.observableArrayList(
    new Callback<ActionStep, Observable[]>() {
        @Override
        public Observable[] call(ActionStep actionStep) {
            return new Observable[] { actionStep.nameProperty() } ;
        }
    });
actionStepListView.setItems(listOfSteps);

这篇关于ListView控件不反映变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 19:26