簡體   English   中英

ListView沒有反映更改

[英]ListView is not reflecting changes

我在前面創建了一個TableView,並為每個TableColumns注冊了Properties。 編輯內部數據反映在TableView中就好了。

但是,使用ListView,它是一個不同的故事。 除非我關閉框架並再次打開,否則不會立即顯示更改。

我的ListView包含ActionSteps。 請注意,我使用了Javafx bean屬性。

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。

  @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中顯示它們的值,而不是將它綁定到它們的Properties。

我究竟做錯了什么? 我應該覆蓋一家細胞工廠嗎?

請注意,您嘗試使用ListView的單元格比使用TableView的單元格執行更復雜的操作。 TableView ,單元格中顯示的對象正在發生變化,因此單元格很容易觀察到這一點。 ListView ,您希望單元格注意屬於單元格中顯示的對象的屬性何時更改; 這是進一步的步驟,所以你必須做一些額外的編碼(雖然不多,你會看到)。

您可以創建一個自定義單元工廠來綁定到stepNameProperty() ,但它很棘手(您必須確保在updateItem()方法中取消綁定/從舊項中刪除偵聽器)。

但是,更簡單的方法是使用帶定義提取器的ObservableList

首先,修復您的方法名稱:您發布的代碼中存在一些奇怪的不匹配。 getX / setX / xProperty方法名稱應該都正確匹配。 即代替

   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是很好的做法。

然后, 使用提取器創建列表 提取器是一個函數,它將列表中的每個元素映射到列表將觀察的Observable數組。 如果這些值發生變化,它將向列表的觀察者發送列表更新。 由於ActionSteptoString()方法引用了nameProperty() ,我假設您希望在nameProperty()更改時更新ListView 所以你想做

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

請注意,在早期版本的JavaFX 2.2中, ListView沒有正確觀察更新事件的列表; 在Java 8發布之前不久就修復了這個問題(如果我沒記錯的話)。(因為你標記了JavaFX8這個問題,我假設你使用的是Java 8,所以你應該沒問題。)

如果您不使用Java 8,則可以使用以下(等效但更詳細)代碼:

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

以下是使用自定義對象制作listview的示例:

public class JavaFX_ListView extends Application {

    class MyObject {
        String day;
        int number;

        MyObject(String d, int n) {
            day = d;
            number = n;
        }

        String getDay() {
            return day;
        }

        int getNumber() {
            return number;
        }

        @Override
        public String toString() {

            return number + " " + day;
        }
    }

    ObservableList<MyObject> myList;

    // Create dummy list of MyObject
    private void prepareMyList() {
        myList = FXCollections.observableArrayList();
        myList.add(new MyObject("Sunday", 50));
        myList.add(new MyObject("Monday", 60));
        myList.add(new MyObject("Tuesday", 20));

    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("sample");
        prepareMyList();
        ListView<MyObject> listView = new ListView<>();
        listView.setItems(myList);

        Pane root = new Pane();
        root.getChildren().add(listView);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
        // testing
        Timer timer = new Timer();
        timer.schedule(new UpdateListTask(), 1000, 1000);
    }

    public static void main(String[] args) {
        launch(args);
    }

    // testing
    public class UpdateListTask extends TimerTask {
        @Override
        public void run() {
            Platform.runLater(new Runnable() {

                @Override
                public void run() {
                    myList.add(new MyObject("sample", Calendar.getInstance()
                            .getTime().getSeconds()));
                }
            });
        }
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM