gpt4 book ai didi

JavaFx CheckBoxTreeItem 选择根项错误

转载 作者:行者123 更新时间:2023-12-02 11:34:01 24 4
gpt4 key购买 nike

我正在尝试开发一个文件复制应用程序。我已经使用文件系统上的当前目录创建了一个复选框树项。

但是当我选择第一个节点(c:/目录)时,需要很长时间。如何轻松快速地选择所有目录?

这是我的第一个 FXML 加载类:

@Override
public void initialize(URL location, ResourceBundle resources) {

TreeView pathTree = new MyFileTreeView().getMyFilePathTree();
vBoxFileTree.getChildren().add(pathTree);
}

这是我的 TreeView 组件:

public class MyFileTreeView {

private TreeView<Path> filePathTree;
private List<Path> rootDirectories;
private Logger logger = Logger.getLogger(MyFileTreeView.class);

public MyFileTreeView() {

rootDirectories = new ArrayList<>();

Iterable<Path> roots = FileSystems.getDefault().getRootDirectories();
for (Path root : roots) {
rootDirectories.add(root);
}
}

public TreeView getMyFilePathTree() {

if (filePathTree == null) {

filePathTree = new TreeView<>(getRootItem());
filePathTree.setPrefHeight(600.0d);
filePathTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
filePathTree.setCellFactory((TreeView<Path> t) -> new TreeCellImpl());
filePathTree.setShowRoot(false);
}

return filePathTree;
}

private TreeItem getRootItem() {

TreeItem rootItem = new TreeItem();

for (Path path : rootDirectories) {
MyFileTreeItem item = new MyFileTreeItem(path);
item.setIndependent(false);
rootItem.getChildren().add(item);
logger.info(path.toString() + " directory has been added to fileTree!");
}

return rootItem;
}
}

这是树项目:

public class MyFileTreeItem extends CheckBoxTreeItem<Path> {

private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;

public MyFileTreeItem(Path path) {
super(path);
}

@Override
public boolean isLeaf() {

if (isFirstTimeLeaf) {

isFirstTimeLeaf = false;
Path path = getValue();
isLeaf = Files.isRegularFile(path);
}
return isLeaf;
}

@Override
public ObservableList<TreeItem<Path>> getChildren() {

if (isFirstTimeChildren) {
isFirstTimeChildren = false;
super.getChildren().setAll(buildChildren(this));
}

return super.getChildren();
}

private ObservableList<TreeItem<Path>> buildChildren(CheckBoxTreeItem<Path> treeItem) {

Path path = treeItem.getValue();
if ((path != null) && (Files.isDirectory(path))) {

try (Stream<Path> pathStream = Files.list(path)) {
return pathStream
.map(p -> new MyFileTreeItem(p))
.collect(Collectors.toCollection(() ->
FXCollections.observableArrayList()));
} catch (IOException e) {
}
}

return FXCollections.emptyObservableList();
}
}

error image

更新:

感谢@fabian,我添加了不确定属性

public class FileTreeItem extends TreeItem<Path> {

private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;

private BooleanProperty selected;
private BooleanProperty indeterminate;

public FileTreeItem(Path path) {
this(path, false, false);
}

protected FileTreeItem(Path path, boolean selected, boolean indeterminate) {

super(path);
this.selected = new SimpleBooleanProperty(selected);
this.indeterminate = new SimpleBooleanProperty(indeterminate);
this.selected.addListener((o, oldValue, newValue) -> {

if (!isLeaf() && !isFirstTimeChildren) {

if (!isIndeterminate()) {
for (TreeItem<Path> ti : getChildren()) {
((FileTreeItem) ti).setSelected(newValue);
}
}

if (isIndeterminate() && newValue) {
setIndeterminate(false);
for (TreeItem<Path> ti : getChildren()) {
((FileTreeItem) ti).setSelected(newValue);
}
}
}

if (!newValue) {

if (getParent() instanceof FileTreeItem) {
FileTreeItem parent = (FileTreeItem) getParent();
parent.setIndeterminate(true);
parent.setSelected(false);
}

} else {

if (getParent() instanceof FileTreeItem) {

boolean allChildSelected = true;
FileTreeItem parent = (FileTreeItem) getParent();
for (TreeItem<Path> child : parent.getChildren()) {
if (!((FileTreeItem) child).isSelected()) {
allChildSelected = false;
break;
}
}

if (allChildSelected && !parent.isSelected()) {
setIndeterminate(false);
parent.setIndeterminate(false);
parent.setSelected(true);
}
}
}
});
}

@Override
public boolean isLeaf() {

if (isFirstTimeLeaf) {
isFirstTimeLeaf = false;
Path path = getValue();
isLeaf = Files.isRegularFile(path);
}
return isLeaf;
}

@Override
public ObservableList<TreeItem<Path>> getChildren() {

if (isFirstTimeChildren) {
isFirstTimeChildren = false;
super.getChildren().setAll(buildChildren(this));
}

return super.getChildren();
}

private List<TreeItem<Path>> buildChildren(FileTreeItem treeItem) {

Path path = treeItem.getValue();
if ((path != null) && (Files.isDirectory(path))) {

final boolean select = treeItem.isSelected();
boolean indeterminate = treeItem.isIndeterminate();

try (Stream<Path> pathStream = Files.list(path)) {

List<TreeItem<Path>> res = new ArrayList<>();
pathStream
.map(p -> new FileTreeItem(p, select, indeterminate))
.forEach(res::add);
return res;
} catch (IOException e) {
}
}

return Collections.emptyList();
}

public boolean isSelected() {
return selected.get();
}

public BooleanProperty selectedProperty() {
return selected;
}

public void setSelected(boolean value) {
selected.set(value);
}

public boolean isIndeterminate() {
return indeterminate.get();
}

public BooleanProperty indeterminateProperty() {
return indeterminate;
}

public void setIndeterminate(boolean indeterminate) {
this.indeterminate.set(indeterminate);
}
}

最佳答案

当您更改 CheckBoxTreeItem 的选定状态时,子项的状态将设置为相同的值。这意味着调用了 getChildren 方法,并且还为所有子项设置了 selected 属性。这样您就可以有效地对目录的所有内容进行深度优先遍历。

因此,您需要直接扩展 TreeItem 并实现所需的属性。您需要确保在更新 selected 属性时,仅当已调用 getChildren 时才迭代子项:

public class FileTreeItem extends TreeItem<Path> {

private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;

private final BooleanProperty selected;
private final BooleanProperty indeterminate;

protected FileTreeItem(Path path, boolean selected) {
super(path);
this.indeterminate = new SimpleBooleanProperty();
this.selected = new SimpleBooleanProperty(selected);
this.selected.addListener((o, oldValue, newValue) -> {
if (!updating) {
if (!isLeaf() && !isFirstTimeChildren) {
// propagate selection to children if they were created yet
for (TreeItem<Path> ti : getChildren()) {
FileTreeItem fti = (FileTreeItem) ti;
fti.setSelected(newValue);
}
}

// update ancestors
TreeItem<Path> parent = getParent();
while ((parent instanceof FileTreeItem)
&& updateAncestorState((FileTreeItem) parent)) {
parent = parent.getParent();
}
}
});
}

/**
* flag preventing circular calls during update.
*/
private boolean updating;

protected static boolean updateAncestorState(FileTreeItem item) {
List<TreeItem<Path>> children = item.getChildren();

boolean hasUnselected = false;
boolean hasSelected = false;
for (Iterator<TreeItem<Path>> it = children.iterator();!(hasSelected && hasUnselected) && it.hasNext();) {
TreeItem<Path> ti = it.next();
FileTreeItem child = (FileTreeItem) ti;
if (child.isSelected()) {
hasSelected = true;
} else {
hasUnselected = true;
if (child.isIndeterminate()) {
hasSelected = true;
}
}
}

item.updating = true;
boolean changed = false;

if (hasUnselected) {
if (item.isSelected() || item.isIndeterminate() != hasSelected) {
changed = true;
item.setSelected(false);
item.setIndeterminate(hasSelected);
}
} else {
if (!item.isSelected()) {
changed = true;
item.setSelected(true);
}
item.setIndeterminate(false);
}
item.updating = false;

return changed;
}

public FileTreeItem(Path path) {
this(path, false);
}

@Override
public boolean isLeaf() {
if (isFirstTimeLeaf) {
isFirstTimeLeaf = false;
Path path = getValue();
isLeaf = Files.isRegularFile(path);
}
return isLeaf;
}

@Override
public ObservableList<TreeItem<Path>> getChildren() {

if (isFirstTimeChildren) {
isFirstTimeChildren = false;
super.getChildren().setAll(buildChildren(this));
}

return super.getChildren();
}

private List<TreeItem<Path>> buildChildren(FileTreeItem treeItem) {
Path path = treeItem.getValue();
if ((path != null) && (Files.isDirectory(path))) {
final boolean select = treeItem.isSelected();
try (Stream<Path> pathStream = Files.list(path)) {
List<TreeItem<Path>> res = new ArrayList<>();
pathStream
.map(p -> new FileTreeItem(p, select))
.forEach(res::add);
return res;
} catch (IOException e) {
}
}

return Collections.emptyList();
}

/* methods for selected & indeterminate properties */
}

编辑

显示不确定属性需要您实现自己的TreeCell:

public class FileItemCheckBoxTreeCell extends TreeCell<Path> {

private BooleanProperty oldSelectedProperty;
private BooleanProperty oldIndeterminateProperty;

private final CheckBox checkBox;
private final StringConverter<TreeItem<Path>> converter;

public FileItemCheckBoxTreeCell(StringConverter<TreeItem<Path>> converter) {
if (converter == null) {
throw new IllegalArgumentException();
}
this.converter = converter;
this.checkBox = new CheckBox();
}

@Override
protected void updateItem(Path item, boolean empty) {
// clear old binding
if (oldSelectedProperty != null) {
checkBox.selectedProperty().unbindBidirectional(oldSelectedProperty);
checkBox.indeterminateProperty().unbindBidirectional(oldIndeterminateProperty);
oldSelectedProperty = null;
oldIndeterminateProperty = null;
}
checkBox.indeterminateProperty().unbind();

super.updateItem(item, empty);

if (empty) {
setGraphic(null);
setText("");
} else {
TreeItem<Path> treeItem = getTreeItem();
setText(converter.toString(treeItem));
if (treeItem instanceof FileTreeItem) {
setGraphic(checkBox);
FileTreeItem fti = (FileTreeItem) treeItem;

oldSelectedProperty = fti.selectedProperty();
oldIndeterminateProperty = fti.indeterminateProperty();

checkBox.selectedProperty().bindBidirectional(oldSelectedProperty);
checkBox.indeterminateProperty().bindBidirectional(oldIndeterminateProperty);
} else {
setGraphic(null);
}
}
}

public static Callback<TreeView<Path>, TreeCell<Path>> forTreeView(StringConverter<TreeItem<Path>> converter) {
if (converter == null) {
throw new IllegalArgumentException();
}
return tv -> new FileItemCheckBoxTreeCell(converter);
}

}
public TreeView getMyFilePathTree() {

if (filePathTree == null) {

filePathTree = new TreeView<>(getRootItem());
filePathTree.setPrefHeight(600.0d);
filePathTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

// tell cell factory to use the selected property for checkbox
filePathTree.setCellFactory(FileItemCheckBoxTreeCell.forTreeView(new StringConverter<TreeItem<Path>>() {

@Override
public String toString(TreeItem<Path> object) {
if (object == null) {
return "";
}
Path p = object.getValue();
if (p == null) {
return "";
}
p = p.getFileName();
return p == null ? object.getValue().toString() : p.toString();
}

@Override
public TreeItem<Path> fromString(String string) {
throw new UnsupportedOperationException();
}

}));
filePathTree.setShowRoot(false);
}

return filePathTree;
}

关于JavaFx CheckBoxTreeItem<Path> 选择根项错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49086335/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com