2017-05-17 1 views
0

単純なリストビューを作成し、選択したアイテムをリストに含まれる文字列と同期させたい。私はメソッドsetCellFactory()を使うことができると分かっています。項目が選択/選択解除されているときに文字列リストを更新しますが、文字列のリストが変更されたときにListView項目の選択を更新する方法はわかりません。リストボックスを文字列のリストと同期させた状態でチェックボックスを保持する

は、これまでのところ私が持っている:

ListView<String> selectedAttributes = new ListView<>(); 
String[] toppings = {"Cheese", "Pepperoni", "Black Olives"}; 
     listViewAttributes.getItems().addAll(toppings); 
     listViewAttributes.setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() { 
      @Override 
      public ObservableValue<Boolean> call(String item) { 
       BooleanProperty observable = new SimpleBooleanProperty(); 
       observable.addListener((obs, wasSelected, isNowSelected) -> { 
        if (isNowSelected) { 
         selectedAttributes.add(item); 
        } else { 
         selectedAttributes.remove(item); 
        } 
        System.out.println(selectedAttributes.size()); 

       }); 
       return observable; 
      } 
     })); 

これは、リストselectedAttributes要素が更新されますListViewの項目がチェックされたときに/チェックを外し、今私はリストの内容が変更されたときにリストビュー項目の選択を更新します。

どうすればいいですか? selectedAttributesは(あなたは慎重にあなたが同じ項目を複数回追加しないチェックまたはObservableListObservableSet、であると仮定すると、

+0

ListView<String> listViewAttributes = new ListView<>(); List<String> selectedAttributes = new ArrayList<>(); selectedAttributes.add("Pepperoni"); String[] toppings = { "Cheese", "Pepperoni", "Black Olives" }; listViewAttributes.getItems().addAll(toppings); listViewAttributes .setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() { @Override public ObservableValue<Boolean> call(String item) { BooleanProperty observable = new SimpleBooleanProperty(); for (int i = 0; i < selectedAttributes.size(); i++) { if (item.equals(selectedAttributes.get(i))) { observable.set(true); } } observable.addListener((obs, wasSelected, isNowSelected) -> { if (isNowSelected) { selectedAttributes.add(item); } else { selectedAttributes.remove(item); } System.out.println(selectedAttributes.size()); }); return observable; } })); 
あなたは、[ 'ObserveableList'(https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ObservableList.html)(というより、例えば、使用することができプリミティブ配列)を作成し、リストが変更されたときに 'ListView'を再生成するためにリスナーを登録します。 – Michael

答えて

1

はここ

observable.set(selectedAttributes.contains(item)); 
selectedAttributes.addListener((ListChangeListener.Change<? extends String> c) -> 
    observable.set(selectedAttributes.contains(item))); 

を追加し、このアプローチでSSCCEです:

import javafx.application.Application; 
import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableSet; 
import javafx.collections.SetChangeListener; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.ListView; 
import javafx.scene.control.cell.CheckBoxListCell; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class ListViewWithCheckBoxes extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ListView<String> toppingsList = new ListView<>(); 
     String[] toppings = {"Cheese", "Tomato Sauce", "Pepperoni", "Black Olives"}; 
     toppingsList.getItems().addAll(toppings); 

     ObservableSet<String> selectedToppings = FXCollections.observableSet(); 

     toppingsList.setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() { 
      @Override 
      public ObservableValue<Boolean> call(String item) { 
       BooleanProperty observable = new SimpleBooleanProperty(); 
       observable.addListener((obs, wasSelected, isNowSelected) -> { 
        if (isNowSelected) { 
         selectedToppings.add(item); 
        } else { 
         selectedToppings.remove(item); 
        } 
        System.out.println(selectedToppings.size()); 

       }); 

       observable.set(selectedToppings.contains(item)); 
       selectedToppings.addListener((SetChangeListener.Change<? extends String> c) -> 
        observable.set(selectedToppings.contains(item))); 

       return observable; 
      } 
     })); 


     // example of a button that changes what's selected in the list 
     // This selects "Cheese" and "Tomato Sauce" and deselects everything else 
     Button justCheese = new Button("Just a cheese pizza"); 
     justCheese.setOnAction(e -> { 
      selectedToppings.clear(); 
      selectedToppings.add("Cheese"); 
      selectedToppings.add("Tomato Sauce"); 
     }); 

     BorderPane root = new BorderPane(toppingsList); 
     root.setTop(justCheese); 
     BorderPane.setMargin(justCheese, new Insets(5)); 

     Scene scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

あなたがしていること(選択されたアイテムを表す別のリスト)は、ちょっと複雑になります。この時点で、それだけで観察可能な性質を持っているリスト内の項目のための適切なモデルクラスを定義する方が簡単でしょう:

public class Topping { 

    private final String name ; 

    private final BooleanProperty selected = new SimpleBooleanProperty(); 

    public Topping(String name) { 
     this.name = name ; 
    } 

    public BooleanProperty selectedProperty() { 
     return selected ; 
    } 

    public final boolean isSelected() { 
     return selectedProperty().get(); 
    } 

    public final void setSelected(boolean selected) { 
     selectedProperty().set(selected); 
    } 

    public String getName() { 
     return name ; 
    } 

    @Override 
    public String toString() { 
     return getName(); 
    } 
} 

その後、残りのコードは、はるかに簡単です:

ListView<Topping> listView = new ListView<>(); 
List<Topping> toppings = Arrays.asList(
    new Topping("Cheese"), 
    new Topping("Pepperoni") , 
    new Topping("Black Olives")); 
listView.getItems().addAll(toppings); 

listView.setCellFactory(CheckBoxListCell.forListView(Topping::selectedProperty)); 

そして今、あなたはUIのチェックボックスの外に項目を選択することができます。ここ

for (Topping topping : toppings) { 
    topping.setSelected(true); 
} 

このアプローチにSSCCEある:

のequals()メソッドによって、リストに文字列の項目を比較するためにループに使用して
import java.util.Arrays; 
import java.util.List; 

import javafx.application.Application; 
import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.ListView; 
import javafx.scene.control.cell.CheckBoxListCell; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class ListViewWithCheckBoxes extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ListView<Topping> toppingsList = new ListView<>(); 
     Topping cheese = new Topping("Cheese"); 
     Topping tomSauce = new Topping("Tomato Sauce"); 
     Topping pepperoni = new Topping("Pepperoni"); 
     Topping blackOlives = new Topping("Black Olives"); 

     toppingsList.getItems().addAll(cheese, tomSauce, pepperoni, blackOlives); 


     toppingsList.setCellFactory(CheckBoxListCell.forListView(Topping::selectedProperty)); 

     // example of a button that changes what's selected in the list 
     // This selects "Cheese" and "Tomato Sauce" and deselects everything else 

     Button justCheese = new Button("Just a cheese pizza"); 
     List<Topping> cheesePizzaToppings = Arrays.asList(cheese, tomSauce); 

     justCheese.setOnAction(e -> toppingsList.getItems().forEach(
       topping -> topping.setSelected(cheesePizzaToppings.contains(topping)))); 

     BorderPane root = new BorderPane(toppingsList); 
     root.setTop(justCheese); 
     BorderPane.setMargin(justCheese, new Insets(5)); 

     Scene scene = new Scene(root); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static class Topping { 

     private final String name ; 

     private final BooleanProperty selected = new SimpleBooleanProperty(); 

     public Topping(String name) { 
      this.name = name ; 
     } 

     public BooleanProperty selectedProperty() { 
      return selected ; 
     } 

     public final boolean isSelected() { 
      return selectedProperty().get(); 
     } 

     public final void setSelected(boolean selected) { 
      selectedProperty().set(selected); 
     } 

     public String getName() { 
      return name ; 
     } 

     @Override 
     public String toString() { 
      return getName(); 
     } 
    } 


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

これは混乱します。あなたが提案したコードの最初の部分を維持する必要がありますか?そして、私はこれを解決する問題を抱えています、私は実際に2つの同様のリストビューを持っています。私はそれらを同期させておきたい(変更されたとき、他のものも変わる)、あなたのソリューションは事態を非常に複雑にします。 –

+1

@ Joker00いいえ、ここには2つの異なる解決策があります。最初のコードは、追加のコード行を追加するだけで、選択した値を表す余分なリストが変更された場合、チェックボックスが更新されます。 2番目の解決策は、余分なリストを完全に取り除き、アイテムがアイテムのプロパティで選択されているかどうかを保存するだけです。これははるかに使いやすくなるでしょう。同じデータで2つ目のリストビューを維持することと何が関係しているのかはっきりしません。それはあなたが求めているものとは完全に独立しているようです。 –

+0

@ Joker00少し明確化し、2つのソリューションそれぞれの完全な例を追加しました。 –

1

項目が等しい場合は、コードの下に使用して真の観察セット。

+0

それは動作しませんでした。 'observable.set(true);でどの項目をtrueに設定するかをどのように指定しますか? –

+0

"Pepperoni"はselectedAttributesリストに追加されているので、listviewをロードするときはequalメソッドでチェックします(listviewに存在する場合はtrueを選択します)。 –

+0

これは混乱しています。私はリストビューの特定の項目をfalseに設定する場所を理解していません。 –

関連する問題