javafx如何禁用checkboxTreeItem中的一个项目?

时间:2014-11-25 07:57:29

标签: java javafx treeview treeviewitem

  

我是JavaFX的新手,我在复选框树视图中遇到了问题。
我想在根值** 序列号中禁用一个项目,但根据JavaFX文档,似乎不可能。

     

我已停用点击效果 cbTreeViewdisable(treeItems,3)
  有没有办法使任何一个值变灰(或设置一个id),以便用户知道它被禁用。

private TreeView<String> cbTreeView;    
@Override
public void start(Stage primaryStage) {
 StackPane root = new StackPane();
 cbTreeView = new TreeView();
 CheckboxTreeItem<String> rootItem = new CheckboxTreeItem("Serial No.");
 final CheckboxTreeItem[] treeItems = new CheckboxTreeItem[6];
 for (int i = 0; i < 6; i++) {
   treeItems[i] = new CheckboxTreeItem(""+i+"");
   rootItem.getChildren().addAll(treeItems[i]);  
 }

 root.setExpanded(true);
 CheckboxTreeItem rootItem2 = new CheckboxTreeItem("child1");
 final CheckboxTreeItem[] treeItems2 = new CheckboxTreeItem[6];

 for (int i = 0; i < 6; i++) {
   treeItems2[i] = new CheckboxTreeItem(""+i+"");
   rootItem2.getChildren().addAll(treeItems2[i]);  
 }

 cbTreeView.setRoot(rootItem);
 cbTreeView.setCellFactory(CheckboxTreeCell.<String>forTreeView());
 rootItem.getChildren().set(2,rootItem2);
 cbTreeViewdisable(treeItems, 3);
 //rest of code imports css and draws stage which is not relevant to my question
 }

 private void cbTreeViewdisable(final CheckboxTreeItem[] treeItems, final int id) {
    treeItems[id].setIndependent(Boolean.TRUE);
    treeItems[id].setValue(treeItems[id].getValue().toString()+" Note: you can't select this!)");
    treeItems[id].selectedProperty().addListener(new ChangeListener<Boolean>() {

    @Override
    public void changed(ObservableValue<? extends Boolean> observable, 
        Boolean oldvalue, Boolean newvalue) {
        Platform.runLater(new Runnable() {
        @Override
        public void run() {
            treeItems[id].setSelected(Boolean.FALSE);       
   } 

4 个答案:

答案 0 :(得分:1)

我想出了扩展CheckBoxTreeItem类的想法。在那里,我添加了缺失的禁用属性:

import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.CheckBoxTreeItem;


public class CheckBoxTreeItemExt<T> extends CheckBoxTreeItem<T>
{
    public SimpleBooleanProperty disabledProperty = new SimpleBooleanProperty(false);

    public CheckBoxTreeItemExt(T t)
    {
        super(t);
    }

    public boolean isDisabled()
    {
        return disabledProperty.get();
    }

    public void setDisabled(boolean disabled)
    {
        disabledProperty.set(disabled);
    }
}

然后我创建了一个侦听新的disabledProperty的CheckBoxTreeCell:

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TreeItem;
import javafx.scene.control.cell.CheckBoxTreeCell;


public class CheckBoxTreeCellExt<T> extends CheckBoxTreeCell<T> implements ChangeListener<Boolean>
{
    protected SimpleBooleanProperty linkedDisabledProperty;

    @Override
    public void updateItem(T item, boolean empty)
    {
        super.updateItem(item, empty);

        if(item != null)
        {
            TreeItem<T> treeItem = treeItemProperty().getValue();
            if(treeItem != null)
            {
                if(treeItem instanceof CheckBoxTreeItemExt<?>)
                {
                    CheckBoxTreeItemExt<T> checkItem = (CheckBoxTreeItemExt<T>)treeItem;
                    if(checkItem != null)
                    {                               
                        if(linkedDisabledProperty != null)
                        {
                            linkedDisabledProperty.removeListener(this);
                            linkedDisabledProperty = null;
                        }

                        linkedDisabledProperty = checkItem.disabledProperty;                        
                        linkedDisabledProperty.addListener(this);

                        setDisable(linkedDisabledProperty.get());
                    }
                }
            }           
        }
    }

    @Override
    public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldVal, Boolean newVal)
    {       
        setDisable(newVal);
    }
}

最后我们选择CheckBoxTreeCellFactory:

import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.util.Callback;

public class CheckBoxTreeCellFactoryExt<T> implements Callback<TreeView<T>, TreeCell<T>>
{
    @Override
    public TreeCell<T> call(TreeView<T> tv)
    {
        return new CheckBoxTreeCellExt<T>();
    }
}

答案 1 :(得分:1)

  

具有可绑定布尔值的扩展TreeItem类

   import javafx.beans.property.SimpleBooleanProperty;
   import javafx.scene.control.TreeItem;

    public class TreeItemDeactivatable<T> extends TreeItem<T> {
        private SimpleBooleanProperty disabledProperty = new SimpleBooleanProperty(false);

        public TreeItemDeactivatable() {
            super();
        }

        public TreeItemDeactivatable(T t) {
            super(t);
        }

        public SimpleBooleanProperty disabledProperty() {
            return disabledProperty;
        }

        public boolean isDisabled() {
            return disabledProperty.get();
        }

        public void setDisabled(boolean disabled) {
            disabledProperty.set(disabled);
        }
    }
  

在CellFactory中覆盖call()并放置

    @Override
    public TreeCell<T> call(TreeView<T> treeView) {
    TreeCell<T> cell = (TreeCell<T>) new TextFieldTreeCellImpl();

        final PseudoClass clippedStylePseudoClass = PseudoClass.getPseudoClass("clipped");

        cell.treeItemProperty().addListener((ov, oldTreeItem, newTreeItem) -> {
            if (newTreeItem != null && newTreeItem instanceof TreeItemDeactivatable) {
                TreeItemDeactivatable<T> tid = (TreeItemDeactivatable<T>) newTreeItem;
                 tid.setDisabled(false);
                 cell.disableProperty().unbind();
                 cell.disableProperty().bind(tid.disabledProperty());

cell.pseudoClassStateChanged(clippedStylePseudoClass,cell.isDisabled());
            }
        });
}
  

在CSS设置中使用PseudoClass

.tree-view .tree-cell:clipped {
    -fx-background-color:   color-clipped;
}
  

“ cell.pseudoClassStateChanged()”行只是在您需要独立样式的情况下,否则您也可以使用默认的伪类

.tree-view .tree-cell:disabled {}
  

我如何在控制器中控制禁用状态

@FXML
    private void handleCut() {
        Object selection = getFocusedSelectedItem();

        if (selection != null) {
            this.clipboard.add(selection);

             if (selection instanceof NodeDataModel) {
                NodeDataModel toPaste = (NodeDataModel) selection;
                TreeItemDeactivatable<NodeDataModel> tid = toPaste.getTreeItem();
                tid.setDisabled(true);
            }
        }
    }

答案 2 :(得分:0)

允许禁用树的单个项目的一种方法是将其单元格禁用属性绑定到您可以在运行时修改的外部属性。为此,当我们设置单元工厂时,我们可以将此绑定添加到单元实现中。但是我们需要一个引用,所以为了简单起见,我们将使用项的值(这需要唯一的值)。

让我们使用这个pojo:

class Wrap {

    public Wrap(String name){
        this.name.set(name);
        this.disabled.set(false);
    }

    private final StringProperty name = new SimpleStringProperty();

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

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

    public StringProperty nameProperty() {
        return name;
    }
    private final BooleanProperty disabled = new SimpleBooleanProperty();

    public boolean isDisabled() {
        return disabled.get();
    }

    public void setDisabled(boolean value) {
        disabled.set(value);
    }

    public BooleanProperty disabledProperty() {
        return disabled;
    }
}

所以我们可以为树视图上的所有项目创建一个集合:

private TreeView<String> cbTreeView; 
private final List<Wrap> disableList = new ArrayList<>();

@Override
public void start(Stage primaryStage) {
    cbTreeView = new TreeView();

    CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem("Serial No.");
    final List<CheckBoxTreeItem<String>> treeItems = new ArrayList<>(6);
    for (int i = 0; i < 6; i++) {
        CheckBoxTreeItem<String> item = new CheckBoxTreeItem("0"+i+"");
        item.setIndependent(true);
        treeItems.add(item);  
        disableList.add(new Wrap("0"+i+""));
    }
    rootItem.getChildren().addAll(treeItems);

    rootItem.setExpanded(true);
    rootItem.setIndependent(true);
    CheckBoxTreeItem<String> rootItem2 = new CheckBoxTreeItem("child1");
    final List<CheckBoxTreeItem<String>> treeItems2 = new ArrayList<>(6);
    for (int i = 0; i < 6; i++) {
        CheckBoxTreeItem<String> item = new CheckBoxTreeItem("1"+i+"");
        item.setIndependent(true);
        treeItems2.add(item); 
        disableList.add(new Wrap("1"+i+""));
    }
    rootItem2.getChildren().addAll(treeItems2);
    rootItem2.setIndependent(true);
    rootItem.getChildren().set(2,rootItem2);

    cbTreeView.setRoot(rootItem);

现在我们创建单元工厂,并在设置项目的值时提供绑定:

    cbTreeView.setCellFactory((TreeView<String> item) -> {

        final CheckBoxTreeCell<String> cell = new CheckBoxTreeCell<>();

        cell.itemProperty().addListener((obs,s,s1)->{
            cell.disableProperty().unbind();
            if(s1!=null && !s1.isEmpty()){
                Wrap wrap=disableList.stream()
                        .filter(w->w.getName().equals(s1))
                        .findFirst().orElse(null);
                if(wrap!=null){
                    cell.disableProperty().bind(wrap.disabledProperty());
                }
            }
        });
        return cell;
    });

最后,我们展示舞台,并禁用一些随机项:

    Scene scene=new Scene(cbTreeView);
    primaryStage.setScene(scene);
    primaryStage.show();

    // disable by name
    disableList.stream()
            .filter(w->w.getName().equals("03"))
            .findFirst().ifPresent(w->w.setDisabled(true));
    // disable by order
    disableList.get(7).setDisabled(true);

}

TreeView with disabled items

答案 3 :(得分:0)

非常感谢@Pereda。如果将root设置为独立,则它很有用。由于我正在使用Java 7,我替换了代码

Wrap wrap=disableList.stream()
                    .filter(w->w.getName().equals(s1))
                    .findFirst().orElse(null);
            if(wrap!=null){
                cell.disableProperty().bind(wrap.disabledProperty());
            }

用这个

for (int i = 0; i < disabledList.size();i++) {
    if (disabledList.get(i).getName().equals(s1)) {
        cell.disabledProperty.bind(disabledList.get(i).disabledProperty());
    }
}

但是如果root 设置为独立,我点击root,禁用的孩子也会得到一个不正确的勾号。那么这种情况下的解决方案是什么?