JavaFX TableView scrooling

问题描述:

我有我的TableView包含一些数字数据。当我让我们说按钮编辑值时,它将单元格的背景更改为绿色。当没有足够的行来制作表格可滚动时,这很有用。一旦表格变成​​(或从头开始)滚动,它开始变得奇怪。它会更改已编辑项目的背景,但会在您向下滚动时才会看到一个不可见的背景。但是,当我调试时,更改背景的代码只被调用一次。我认为当可滚动销毁并重新创建单元格时,它必须对该tableview做些事情,或者我误解了某些内容,并且我做错了。JavaFX TableView scrooling

例如: 我已经编辑了第二行。 I've edited second row

而当我向下滚动一点,这个人也有不同的背景。 (它们都具有它同时) This one got edited as well

代码: 模型类:

public class Bid { 

    private DoubleProperty value; 
    private BooleanProperty valueChanged; 

    public Bid(double val) { 
    value = new SimpleDoubleProperty(); 
    valueChanged = new SimpleBooleanProperty(); 
    setValue(val); 
    value.addListener((observable, old, newVal) -> { 
     System.out 
      .println(observable.toString() + " changed value from " + old.doubleValue() + " to " + newVal.doubleValue()); 
     valueChanged.setValue(true); 
    }); 
    } 

    public double getValue() { 
    return value.get(); 
    } 

    public void setValue(double value) { 
    this.value.set(value); 
    } 

    public DoubleProperty valueProperty() { 
    return value; 
    } 

    public boolean isValueChanged() { 
    return valueChanged.get(); 
    } 

    public BooleanProperty valueChangedProperty() { 
    return valueChanged; 
    } 

    public void setValueChanged(boolean valueChanged) { 
    this.valueChanged.set(valueChanged); 
    } 

    @Override 
    public String toString() { 
    return "Bid{" + 
     "value=" + value.getValue() + 
     '}'; 
    } 
} 

我的手机(当我encoutered这个问题第一次我认为这是风格去除一部分,但删除它没有帮助):

public class BidCell extends TextFieldTableCell<Bid, Double> { 


    private BooleanProperty newExternalValue; 

    public BidCell() { 
    super(new StringConverter<Double>() { // converter used for conversion from/to string 


     @Override 
     public String toString(Double object) { 
     return object.toString(); 
     } 

     @Override 
     public Double fromString(String string) { 
     return Double.valueOf(string); 
     } 
    }); 

    newExternalValue = new SimpleBooleanProperty(); 

    newExternalValue.addListener((observable, oldValue, newValue) -> 
    { 
     if (newValue) { 
     String old = this.getStyle(); 
     this.setStyle("-fx-background-color: #99ff99"); 
     System.out.println("Color changed"); 
     Thread thread = new Thread(new StyleRemover(this, old, newExternalValue)); 
     thread.setDaemon(true); 
     thread.start(); 
     } 
    }); 
    } 


    @Override 
    public void updateItem(Double item, boolean empty) { 
    super.updateItem(item, empty); 
    if (getTableRow() != null) { 
     if (getTableRow().getItem() != null) { 
     if (item != null && !empty) { 

      Bid b = getTableRow().getItem() instanceof Bid ? ((Bid) getTableRow().getItem()) : null; 
      if (b != null) { 
      if (b.isValueChanged()) { 
       System.out.println("Setting newExternalValue to true for cell" + this); 
       newExternalValue.setValue(true); 
       b.setValueChanged(false); 
      } 
      } 
     } 
     } 
    } 
    } 

    class StyleRemover implements Runnable { 

    private BidCell cell; 
    private String oldStyle; 
    BooleanProperty newExternalValue; 

    public StyleRemover(BidCell cell, String oldStyle, BooleanProperty newExternalValue) { 
     this.cell = cell; 
     this.oldStyle = oldStyle; 
     this.newExternalValue = newExternalValue; 
    } 

    @Override 
    public void run() { 
     try { 
     Thread.sleep(3000); 
     cell.setStyle(oldStyle); 
     newExternalValue.setValue(false); 
     } 
     catch (InterruptedException e) { 
     e.printStackTrace(); 
     } 
    } 
    } 

网:

public class Grid { 

    private TableView<Bid> view; 
    private TableColumn<Bid, Double> bidStringTableColumn; 
    ObservableList<Bid> bids; 

    public TableView<Bid> getView() { 
    return view; 
    } 

    public Grid() { 
    view = new TableView<>(); // create tableview 

    bids = FXCollections.observableArrayList(); // fill data for it 
    bids.addListener((ListChangeListener<Bid>) c -> { 
     c.next(); 
     if (c.wasAdded()) { 
     System.out.println("added new value " + c.getAddedSubList().get(0).toString()); 
     } 
    }); 
    for (double i = 0; i < 10; i += 0.45) { 
     Bid e = new Bid(i); 

     bids.add(e); 
    } 
    view.setItems(bids); 
    view.setEditable(true); 

    bidStringTableColumn = new TableColumn<>("Bid"); // create column with header text "Bid" 
    bidStringTableColumn.setCellValueFactory(param -> param.getValue().valueProperty() 
     .asObject()); // value factory for column, determines which property will fill column 
    bidStringTableColumn.setCellFactory(e -> new BidCell()); 

    view.getColumns().add(bidStringTableColumn); // add column to table 
    } 


    public ObservableList<Bid> getBids() { 
    return bids; 
    } 

编辑:这不只是关于样式,我发现如果我开始编辑该单元格和scrool下来,那一个也处于编辑模式。一种可能的解决方案可能只是以某种方式禁用单元格销毁和重新创建滚动,但我还没有找到一种方法如何做到这一点,我不认为这甚至是可能的。 (我知道它在那里是为了表现,但是性能对我们来说并不重要,不会有数百万行,只有大约100)

+0

嗯......曾有过但重新创建/刷新滚动的细胞不记得其时#但应该固定在fx9(至少) – kleopatra

+0

我的意思是:https://bugs.openjdk.java.net/browse/JDK-8150525 - 不完全确定如果这是相关的,但你的描述听起来很相似 – kleopatra

+0

以及我检查它并试图下载jdk9,但问题仍然存在,也许这不是由这个错误引起的 –

我花了一些时间,但我解决了它。 最重要的就是这句话

“的tableview中和ListView细胞再利用以使源列表的不同的行 的数据。”

这基本上意味着您不能将样式设置为单元格,因为当您滚动时它将用于不同的数据。那是我的错误。

最简单的解决方案是将样式存储在模型(Bid)类中,然后在单元格中从中获取样式。 在小区i制造方法

public void checkStyle() { 
    if (getTableRow().getItem() != null) { 
     Bid bid = (Bid) getTableRow().getItem(); 
     this.setDisabled(bid.isDisabled()); 
     String style = bid.getStyle(); 
     if (!this.getStyle().equals(style) && getItem() == bid.getValue()) 
      this.setStyle(style); 
    } 

我在updateItemupdateIndex调用,并在

newExternalValue.addListener((observable, oldValue, newValue) -> 
    { 
     checkStyle(); 
    });