2014-01-05 30 views
8

我有一个ListView与我自己的ListCell<MyObject>实现。通过网络信号,我收到了应该更改的ListCell索引。通过ListView获取ListCell

超过listView.getItems().get(index);访问模型没有问题,但是我想用接收到的索引对listCell进行布局更改,并将索引+1更改为ListCell;

如何通过ListView访问ListCell?

我寻找这样的方法:

listView.getListCell(index); 

回答

4

不幸的是,现在没有API通过索引来获取列表细胞或让所有儿童(listcells)的ListView控件。一种解决方案可以是,在MyObject类中定义一个新的StringProperty specialIndicator。

class MyObject { 

     ....//u r properties 
     private StringProperty specialIndicator; 

当你永远从设置对象的这一specialIndicator财产网络信号得到指数和做的ListView forcerefresh

public void onReceivedNetWorkSignalIndex() { 
listView.getItems().get(indexFromService).setSpecialIndicator("selected"); 
listView.getItems().get(indexFromService+1).setSpecialIndicator("selectedplusone"); 
//force refresh listview (it will trigger cellFactory again so that you can manipulate layout) 
listView.setItems(null); 
listView.setItems(allObjects); 

} 

因为您已经有了自定义对象的ListView,我假设你已经有了定制cellFactory(如果不是你要创建一个),修改自定义电池工厂来处理这个特殊的指标

  listView.setCellFactory(new Callback<ListView<MyObject>, ListCell<MyObject>>() { 
        @Override 
        public ListCell<MyObject> call(ListView<MyObject> myObjectListView) { 
         ListCell<MyObject> cell = new ListCell<MyObject>(){ 
          @Override 
          protected void updateItem(MyObject myObject, boolean b) { 
           super.updateItem(myObject, b); 
           if(myObject != null) { 
            setText(myObject.getName()); 
            if("selected".equalsIgnoreCase(myObject.getSpecialIndicator())) { 
             System.out.println("Setting new CSS/graphics for index retun from service." + myObject.getName()); 
            } else if("selectedplusone".equalsIgnoreCase(myObject.getSpecialIndicator())) { 
             System.out.println("Setting new CSS/Graphics for index+1 returned from service" + myObject.getName()); 
            } 
           myObject.setSpecialIndicator(""); // reset it back to empty 
           } 
          } 
         }; 

         return cell; 
        } 
       }); 

这里是整个示例应用程序,Y你可以查看它(如果上述解释不清楚)。 enter image description here

public class ListViewTest extends Application { 


    @Override 
    public void start(Stage stage) throws Exception { 

     VBox root = new VBox(); 
     final ObservableList<MyObject> allObjects = FXCollections.observableArrayList(new MyObject("object0"), new MyObject("object1"),new MyObject("object2"),new MyObject("object3"),new MyObject("object4")); 
     final ListView<MyObject> listView = new ListView<>(allObjects); 
     listView.setCellFactory(new Callback<ListView<MyObject>, ListCell<MyObject>>() { 
      @Override 
      public ListCell<MyObject> call(ListView<MyObject> myObjectListView) { 
       ListCell<MyObject> cell = new ListCell<MyObject>(){ 
        @Override 
        protected void updateItem(MyObject myObject, boolean b) { 
         super.updateItem(myObject, b); 
         if(myObject != null) { 
          setText(myObject.getName()); 
          if("selected".equalsIgnoreCase(myObject.getSpecialIndicator())) { 
           System.out.println("Setting new CSS/graphics for index retun from service." + myObject.getName()); 
           setText("I am selected Index from Service"); 
          } else if("selectedplusone".equalsIgnoreCase(myObject.getSpecialIndicator())) { 
           System.out.println("Setting new CSS/Graphics for index+1 returned from service" + myObject.getName()); 
           setText("I am selected Index +1 from Service"); 
          } 
          myObject.setSpecialIndicator(""); // reset it back to empty 
         } 
        } 
       }; 

       return cell; 
      } 
     }); 
     Button serviceIndex2 = new Button("ServiceIndex2"); 
     serviceIndex2.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent actionEvent) { 
       int indexFromService =2; 
       listView.getItems().get(indexFromService).setSpecialIndicator("selected"); 
       listView.getItems().get(indexFromService+1).setSpecialIndicator("selectedplusone"); 
       listView.setItems(null); 
       listView.setItems(allObjects); 
      } 
     }); 
     root.getChildren().addAll(listView,serviceIndex2); 
     Scene scene = new Scene(root,500,500); 
     stage.setScene(scene); 
     stage.show(); 

    } 

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

    class MyObject { 

     private StringProperty name; 
     private StringProperty specialIndicator; 

     MyObject(String name) { 
      this.name = new SimpleStringProperty(name); 
      this.specialIndicator = new SimpleStringProperty(); 
     } 

     public String getName() { 
      return name.get(); 
     } 

     public StringProperty nameProperty() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name.set(name); 
     } 

     public String getSpecialIndicator() { 
      return specialIndicator.get(); 
     } 

     public StringProperty specialIndicatorProperty() { 
      return specialIndicator; 
     } 

     public void setSpecialIndicator(String specialIndicator) { 
      this.specialIndicator.set(specialIndicator); 
     } 
    } 
} 
+0

非常感谢你,你帮了我很多!但有什么令人失望的,这是不可能与存在的API ...;) –

+0

应该可以只使用侦听器和/或绑定在单元实现;不应该有任何需要做丑陋的“力量更新”。例如,你可以添加一个监听器到像'Bindings.valueAt(listView.getItems(),indexProperty()。subtract(1))'(或类似的东西):这将观察当前索引列表中的项目 - 1,如果有任何更改(包括索引),将会更新。如果需要,可以将该Binding表达式与Bindings.select结合使用以获取对象内的属性。 –

0

这里有一个比较简单的方法,即只有一个“选择”索引。在这里我创建一个属性来保存选定的索引,单元格工厂只是观察它,以及单元格的项目属性和索引属性,并通过绑定设置文本。如果需要,你可以做类似的设置图形。

import java.util.concurrent.Callable; 

import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class ListViewStyleAroundSelection extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     final ListView<String> listView = new ListView<>(); 
     for (int i=1; i<=20; i++) { 
      listView.getItems().add("Item "+i); 
     } 
     final HBox controls = new HBox(5); 
     final Button button = new Button("Set selection"); 
     final TextField indexField = new TextField(); 

     final IntegerProperty selectionIndex = new SimpleIntegerProperty(); 
     button.setOnAction(new EventHandler<ActionEvent>() { 

      @Override 
      public void handle(ActionEvent event) { 
       try { 
        selectionIndex.set(Integer.parseInt(indexField.getText())); 
       } catch (NumberFormatException nfe) { 
        indexField.setText(""); 
       } 
      } 

     }); 

     controls.getChildren().addAll(new Label("Enter selection index:"), indexField, button); 
     final BorderPane root = new BorderPane(); 
     root.setCenter(listView); 
     root.setBottom(controls); 

     listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { 

      @Override 
      public ListCell<String> call(ListView<String> lv) { 
       final ListCell<String> cell = new ListCell<>(); 
       cell.textProperty().bind(Bindings.createStringBinding(new Callable<String>() { 

        @Override 
        public String call() throws Exception { 
         if (cell.getItem() == null) { 
          return null ; 
         } else { 
          switch (cell.getIndex() - selectionIndex.get()) { 
           case -1: return cell.getItem() + " (selected item below)"; 
           case 0: return cell.getItem() + " (selected)"; 
           case 1: return cell.getItem() + " (selected item above)"; 
           default: return cell.getItem(); 
          } 
         } 
        } 

       }, cell.itemProperty(), cell.indexProperty(), selectionIndex)); 
       return cell; 
      } 

     }); 

     final Scene scene = new Scene(root, 600, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

这是一个稍微复杂的版本。这里我有一个自定义数据类型,其中包含一个布尔属性。该更新将指定项的布尔属性设置为true。单元格工厂创建一个单元格,并观察当前项目和之前项目的选定属性。然后,像以前一样,它使用绑定来更新单元格的文本。

import java.util.concurrent.Callable; 

import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.binding.BooleanBinding; 
import javafx.beans.binding.IntegerBinding; 
import javafx.beans.binding.ObjectBinding; 
import javafx.beans.binding.StringBinding; 
import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.ListCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class ListViewStyleAroundSelection extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     final ListView<MyDataType> listView = new ListView<>(); 
     for (int i=0; i<=20; i++) { 
      listView.getItems().add(new MyDataType("Item "+i, false)); 
     } 
     final HBox controls = new HBox(5); 
     controls.setPadding(new Insets(5)); 
     final Button button = new Button("Set selection"); 
     final TextField indexField = new TextField(); 

     button.setOnAction(new EventHandler<ActionEvent>() { 

      @Override 
      public void handle(ActionEvent event) { 
       try { 
        int index = Integer.parseInt(indexField.getText()); 
        if (index >= 0 && index < listView.getItems().size()) { 
         final MyDataType item = listView.getItems().get(index); 
         item.setSelected(! item.isSelected()); 
        } 
       } catch (NumberFormatException nfe) { 
        indexField.setText(""); 
       } 
      } 

     }); 

     controls.getChildren().addAll(new Label("Enter selection index:"), indexField, button); 
     final BorderPane root = new BorderPane(); 
     root.setCenter(listView); 
     root.setBottom(controls); 

     listView.setCellFactory(new Callback<ListView<MyDataType>, ListCell<MyDataType>>() { 

      @Override 
      public ListCell<MyDataType> call(ListView<MyDataType> lv) { 
       final ListCell<MyDataType> cell = new ListCell<>(); 
       final IntegerBinding previousIndex = cell.indexProperty().subtract(1); 
       final ObjectBinding<MyDataType> previousItem = Bindings.valueAt(listView.getItems(), previousIndex); 
       final BooleanBinding previousItemSelected = Bindings.selectBoolean(previousItem, "selected"); 
       final StringBinding thisItemName = Bindings.selectString(cell.itemProperty(), "name"); 
       final BooleanBinding thisItemSelected = Bindings.selectBoolean(cell.itemProperty(), "selected"); 
       cell.textProperty().bind(Bindings.createStringBinding(new Callable<String>() { 

        @Override 
        public String call() throws Exception { 
         if (cell.getItem() == null) { 
          return null ; 
         } else { 
          String value = cell.getItem().getName(); 
          if (thisItemSelected.get()) { 
           value = value + " (selected) " ; 
          } else if (previousItemSelected.get()) { 
           value = value + " (selected item is above)"; 
          } 
          return value ; 
         } 
        } 

       }, thisItemName, thisItemSelected, previousItemSelected)); 
       return cell; 
      } 

     }); 

     final Scene scene = new Scene(root, 600, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static class MyDataType { 
     private final BooleanProperty selected ; 
     private final StringProperty name ; 
     public MyDataType(String name, boolean selected) { 
      this.name = new SimpleStringProperty(this, "name", name); 
      this.selected = new SimpleBooleanProperty(this, "selected", selected); 
     } 
     public final String getName() { 
      return name.get(); 
     } 
     public final void setName(String name) { 
      this.name.set(name); 
     } 
     public final StringProperty nameProperty() { 
      return name ; 
     } 
     public final boolean isSelected() { 
      return selected.get(); 
     } 
     public final void setSelected(boolean selected) { 
      this.selected.set(selected); 
     } 
     public final BooleanProperty selectedProperty() { 
      return selected; 
     } 
    } 

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