【问题标题】:How to properly use a listener in a cellFactory如何在 cellFactory 中正确使用监听器
【发布时间】:2018-08-25 17:48:52
【问题描述】:

TL;DR:监听器也在其他单元格上被激活。

我有一个 TreeView 包含不同的 TreeItems 代表自定义类的数据。如果基础数据的BooleanProperty 发生更改,则单元格应更改其颜色。如果它再次改变,颜色应该被删除。

我使用监听器,但是当我滚动浏览TreeView 时,某个单元格的更改属性也会更改其他单元格的颜色。运行我的 MWE 并右键单击某些单元格、滚动、再次单击等时,可以重现此行为。只需滚动即可清理 TreeView,以便相关单元格暂时不在视图中。

我可以删除侦听器,但只有在滚动离开并返回单元格后重新出现时,颜色才会改变。

问题是:如何在 cellFactory 中正确使用监听器?

MWE

CellFactoryQuestion.java

package cellfactoryquestion;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class CellFactoryQuestion extends Application {

  /** Custom class used as underlying data of TreeItems */
  class CustomObject {
    String label;
    BooleanProperty state = new SimpleBooleanProperty(false);

    CustomObject(String s) { label = s; }
  }

  /** Cell Factory for CustomObject */
  class CustomTreeCell extends TreeCell<CustomObject>{

    PseudoClass customClass = PseudoClass.getPseudoClass("custom");

    @Override
    protected void updateItem(CustomObject co, boolean empty) {
      super.updateItem(co, empty);

      if (empty || co == null) {
        setText(null);
        setGraphic(null);
        pseudoClassStateChanged(customClass, false);

      } else {
        setText(co.label);
        setGraphic(null);

// BEGIN PROBLEMATIC

        /* define background color of cell according to state */
        pseudoClassStateChanged(customClass, co.state.getValue());
        co.state.addListener((o, ov, nv) -> {
          pseudoClassStateChanged(customClass, nv);
        });

// END PROBLEMATIC

        /* if right click, switch state */
        this.setOnContextMenuRequested(e -> {
          co.state.setValue(co.state.getValue() ^ true);
        });

      }
    }
  }

  @Override
  public void start(Stage primaryStage) {

    /* define TreeView 1/3 */
    TreeView tw = new TreeView();
    TreeItem rootTreeItem = new TreeItem(new CustomObject("Root"));
    rootTreeItem.setExpanded(true);

    /* define TreeView 2/3 */
    for (int c = 0; c != 5; c++) {
      TreeItem ci = new TreeItem(new CustomObject("Cat " + c));
      rootTreeItem.getChildren().add(ci);
      ci.setExpanded(true);
      for (int i = 0; i != 5; i++) {
        TreeItem ii = new TreeItem(new CustomObject("Item " + i));
        ci.getChildren().add(ii);
      }
    }

    /* define TreeView 3/3 */
    tw.setRoot(rootTreeItem);
    tw.setCellFactory(value -> new CustomTreeCell());

    /* define Scene */
    StackPane root = new StackPane();
    root.getChildren().add(tw);
    Scene scene = new Scene(root, 300, 250);
    scene.getStylesheets().add("/styles/Styles.css");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

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

}

样式.css

.tree-cell:custom {
  -fx-background-color: salmon;
}

【问题讨论】:

    标签: java javafx listener cell-formatting


    【解决方案1】:

    问题在于您没有取消注册侦听器。在致电super.updateItem 之前执行此操作。这允许您使用getItem 检索旧项目:

    class CustomTreeCell extends TreeCell<CustomObject>{
    
        private final ChangeListener<Boolean> listener = (o, ov, nv) -> pseudoClassStateChanged(customClass, nv);
    
        PseudoClass customClass = PseudoClass.getPseudoClass("custom");
    
        @Override
        protected void updateItem(CustomObject co, boolean empty) {
            // remove listener from old item
            CustomObject oldItem = getItem();
            if (oldItem != null) {
                oldItem.state.removeListener(listener);
            }
    
            super.updateItem(co, empty);
    
          if (empty || co == null) {
            setText(null);
            setGraphic(null);
            pseudoClassStateChanged(customClass, false);
    
          } else {
            setText(co.label);
            setGraphic(null);
    
            /* define background color of cell according to state */
            pseudoClassStateChanged(customClass, co.state.getValue());
            co.state.addListener(listener);
    
            ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-27
      • 1970-01-01
      • 2010-12-11
      • 2017-12-16
      相关资源
      最近更新 更多