2015-12-16 85 views
1

在下面的測試中,所選列表項應與綠色標記一起出現。它適用於最初選擇的項目。但是,看起來像#updateItem()在另一個項目被選中時不會被調用,這似乎是標記未被正確更新的原因。JavaFX:渲染選定的組合框列表項

public class ComboBoxCellFactoryTest extends Application 
{ 
    public static void main(String[] args) 
    { 
    Application.launch(args); 
    } 

    @Override 
    public void start(Stage stage) 
    { 
    Parent content = createContent(); 
    Scene scene = new Scene(content, 400, 300); 
    stage.setScene(scene);  
    stage.show(); 
    } 

    public Parent createContent() 
    { 
    FlowPane content = new FlowPane(10, 10); 

    ComboBox<String> combo = new ComboBox<String>();  
    combo.setItems(FXCollections.observableArrayList("Item 1", "Item 2", "Item 3", "Item 4")); 
    combo.getSelectionModel().selectLast(); 
    combo.setCellFactory(new Callback<ListView<String>, ListCell<String>>() 
    { 
     @Override 
     public ListCell<String> call(ListView<String> p) 
     { 
     return new ListCell<String>() 
     { 
      private final Rectangle rectangle; 
      { 
      rectangle = new Rectangle(10, 10); 
      } 

      @Override 
      protected void updateItem(String item, boolean empty) 
      { 
      super.updateItem(item, empty); 

      if (empty || item == null) 
      { 
       setText(null); 
       setGraphic(null); 
      } 
      else 
      { 
       boolean selected = combo.getValue().equals(item); 
       rectangle.setFill(selected ? Color.GREENYELLOW : Color.RED); 
       setGraphic(rectangle); 
       setText(item); 
      } 
      } 
     }; 
     } 
    }); 
    content.getChildren().add(combo); 
    return content; 
    }  
} 

回答

1

看起來像我的錯誤。一種解決方法(!沒有正式測試,只是一個快速檢查)可能會註冊一個監聽器與電池的selected屬性和手動強制的updateItem,是這樣的:

{ 
    rectangle = new Rectangle(10, 10); 
    selectedProperty().addListener((c, ov, nv) -> { 
     updateItem(getItem(), getItem() == null); 
    }); 
} 


更新

其實,它似乎比簡單更差bug

  • updateItem(...)沒有指定任何東西。它僅包含導語如可以重寫以允許細胞的完全定製
  • 特別
  • ,它沒有指定它被稱爲 - 唯一的線索是在小區的API文檔[的updateItem句子]在單元中的項目更改爲時被調用。有了這樣的設計意圖,對單元格狀態更改的自動更新(除更改項目之外)的期望將是使用錯誤。
  • 但:在API文檔包含了激勵例子非常相似,這裏的使用(除了它改變文本的填充取決於哥特選擇和項目值的顏色) - 這樣的用例是至少在腦海中時撰寫文檔
  • 激發性示例完全不起作用,在更深層次上比僅在預期時不更新顏色更新顏色:更新顏色時不是預期。貌似細胞自身的屬性不能在調用的updateItem

的看到最後(最差)子彈的時間依賴,運行下面的例子(這是激勵例如包裹成一個簡單的應用程序),選擇一個項目(請注意,文本顏色不會按預期更改爲白色)並逐項滾動:在第二頁周圍的某處有一條不可見的線(又名:文本顏色爲白色)。是因爲isSelected在的updateItem的時間是無關的selectedIndex(顯示在列表下方的標籤)2

工作的開始就錯誤

public class CellUpdateItemAndSelected extends Application { 

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

    @Override 
    public void start(Stage stage) { 
     Parent content = createContent(); 
     Scene scene = new Scene(content, 400, 300); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    public Parent createContent() { 
     Pane content = new VBox(10); 
     ListView<Number> numberList = new ListView<>(createNumberData(20)); 
     // this is the motivating example from cell's api doc 
     numberList.setCellFactory(cf -> { 
      ListCell<Number> cell = new ListCell<Number>() { 

       @Override 
       protected void updateItem(Number item, boolean empty) { 
        super.updateItem(item, empty); 
        setText(item == null ? "" : item.toString()); 
        if (item != null) { 
         double value = item.doubleValue(); 
         setTextFill(isSelected() ? Color.WHITE 
           : value == 0 ? Color.BLACK 
             : value < 0 ? Color.RED : Color.GREEN); 
         if (isSelected()) { 
          LOG.info("selected index/item: " + getIndex() + "/" + item); 
         } 
        } 
       } 

      }; 
      return cell; 
     }); 

     Label selectedLabel = new Label(); 
     selectedLabel.textProperty().bind(numberList.getSelectionModel().selectedIndexProperty().asString()); 
     content.getChildren().addAll(numberList, selectedLabel); 
     return content; 
    } 

    protected ObservableList<Number> createNumberData(int count) { 
     ObservableList<Number> data = FXCollections.observableArrayList(); 
     for (int i = -3; i < count; i++) { 
      data.add(i); 
     } 
     return data; 
    } 

    @SuppressWarnings("unused") 
    private static final Logger LOG = Logger 
      .getLogger(CellUpdateItemAndSelected.class.getName()); 
} 

更新:在補丁核心現在在updateSelected中調用updateItem(...),如

public void updateSelected(boolean selected) { 
    if (selected && isEmpty()) return; 
    setSelected(selected); 
    // fix for JDK-8145588 
    updateItem(getItem(), isEmpty()); 
} 

對於所有其他單元狀態屬性,必須執行相同操作...

+0

解決方法正常工作 - 對這樣一個基本問題感到驚訝。 – wzberger

+1

完成 - 你的報告https://bugs.openjdk.java.net/browse/JDK-8145588 – wzberger

+0

@wzberger uppened優先級 - 交叉手指,它會保持(至少它會引起別人的注意,當有人將再次降低它; - ) – kleopatra