ListView 未反映更改 [英] ListView is not reflecting changes

查看:26
本文介绍了ListView 未反映更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不久前创建了一个 TableView 并将属性注册到每个 TableColumns.内部数据的编辑在 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 bean 属性.

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 中反映出来?我注意到 ListView 调用每个对象的 toString() 以在 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 中的单元格相比,您正在尝试对 ListView 中的单元格执行更复杂的操作代码>表视图.在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.

首先,修复您的方法名称:您发布的代码中有一些奇怪的不匹配.getX/setX/xProperty 方法名称都应该正确匹配.IE.而不是

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

和其他属性访问器方法类似.(显然,字段的名称可以是您喜欢的任何名称,因为它们是私有的.)使 get/set 方法成为 final 是一种很好的做法.

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.

然后,使用提取器创建列表.提取器是一个函数,它将列表中的每个元素映射到列表将观察到的 Observable 数组.如果这些值发生变化,它将向列表的观察者发出列表更新.由于您的 ActionSteptoString() 方法引用了 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,则可以使用以下(等效但更详细的)代码:

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 未反映更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆