JavaFX TableView 滚动

大卫 S。

我的 TableView 包含一些数字数据。当我说通过按钮编辑值时,它会将单元格的背景更改为绿色。当没有足够的行使表格可滚动时,这很有效。一旦表格变为(或从一开始)可滚动,它就会开始变得奇怪。它会更改已编辑项目的背景,但在向下滚动之前不可见。但是,当我调试时,更改背景的代码只调用一次。我认为当可滚动破坏和重新创建单元格时,它必须对那个 tableview 做一些事情,或者也许我误解了一些东西并且我做错了。

示例:我已经编辑了第二行。 我已经编辑了第二行

当我向下滚动一点时,这个也有不同的背景。(他们都在同一时间)这个也被编辑了

代码: 模型类:

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() +
        '}';
  }
}

我的单元格(当我第一次遇到这个问题时,我认为这是样式删除部分,但删除它无济于事):

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;
  }

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

大卫 S。

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

“tableview 和 listview 单元格被重用以呈现源列表的不同行数据。”

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

最简单的解决方案是将样式存储在模型 ( Bid ) 类中,然后在单元格中从那里获取它。在单元格中我做了方法

 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);
    }

这是我在打电话updateItem,并updateIndex和在

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章