TreeView UI控件为我们提供了一种渲染树结构的方法。 树具有包含所有分层值的根节点。
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { TreeItem<String> rootItem = new TreeItem<>("Root"); rootItem.setExpanded(true); TreeItem<String> item = new TreeItem<>("A"); rootItem.getChildren().add(item); item = new TreeItem<>("B"); rootItem.getChildren().add(item); TreeView<String> tree = new TreeView<>(rootItem); StackPane root = new StackPane(); root.getChildren().add(tree); primaryStage.setScene(new Scene(root, 300, 250)); primaryStage.show(); } }
上面的代码生成以下结果。
创建树视图
当创建树视图时,我们通常从构建根的TreeItem对象开始。 然后我们将根添加到树视图,并创建其他树项目对象并将它们添加到根。
我们可以通过setGraphic方法或使用它的构造函数来创建一个图形图标到树项目。 图标的建议大小为16×16。
对根项目调用的setExpanded方法定义树视图项目的初始外观。
以下代码从本地文件系统创建动态树。
import java.io.File; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } private TreeItem<File> createNode(final File f) { return new TreeItem<File>(f) { private boolean isLeaf; private boolean isFirstTimeChildren = true; private boolean isFirstTimeLeaf = true; @Override public ObservableList<TreeItem<File>> getChildren() { if (isFirstTimeChildren) { isFirstTimeChildren = false; super.getChildren().setAll(buildChildren(this)); } return super.getChildren(); } @Override public boolean isLeaf() { if (isFirstTimeLeaf) { isFirstTimeLeaf = false; File f = (File) getValue(); isLeaf = f.isFile(); } return isLeaf; } private ObservableList<TreeItem<File>> buildChildren( TreeItem<File> TreeItem) { File f = TreeItem.getValue(); if (f == null) { return FXCollections.emptyObservableList(); } if (f.isFile()) { return FXCollections.emptyObservableList(); } File[] files = f.listFiles(); if (files != null) { ObservableList<TreeItem<File>> children = FXCollections .observableArrayList(); for (File childFile : files) { children.add(createNode(childFile)); } return children; } return FXCollections.emptyObservableList(); } }; } @Override public void start(Stage stage) { Scene scene = new Scene(new Group(), 300, 300); VBox vbox = new VBox(); TreeItem<File> root = createNode(new File("c:/")); TreeView treeView = new TreeView<File>(root); vbox.getChildren().add(treeView); ((Group) scene.getRoot()).getChildren().add(vbox); stage.setScene(scene); stage.show(); } }
上面的代码生成以下结果。
用户域模型
以下代码显示了如何使用用户域模型数据与TreeView。
创建Employee类以捕获用户域模型,并且代码使用循环将所有员工添加到树视图。
/*
* Copyright (c) 2008, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
List<Employee> employees = Arrays.<Employee>asList(
new Employee("a1", "A"),
new Employee("a2", "A"),
new Employee("e1", "E"));
private final Node rootIcon = new ImageView(new Image(getClass().getResourceAsStream("root.png")));
TreeItem<String> rootNode = new TreeItem<String>("Root",rootIcon);
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
rootNode.setExpanded(true);
for (Employee employee : employees) {
TreeItem<String> empLeaf = new TreeItem<String>(employee.getName());
boolean found = false;
for (TreeItem<String> depNode : rootNode.getChildren()) {
if (depNode.getValue().contentEquals(employee.getDepartment())){
depNode.getChildren().add(empLeaf);
found = true;
break;
}
}
if (!found) {
TreeItem depNode = new TreeItem(employee.getDepartment());
rootNode.getChildren().add(depNode);
depNode.getChildren().add(empLeaf);
}
}
stage.setTitle("Tree View Sample");
VBox box = new VBox();
final Scene scene = new Scene(box, 400, 300);
scene.setFill(Color.LIGHTGRAY);
TreeView<String> treeView = new TreeView<String>(rootNode);
treeView.setShowRoot(true);
treeView.setEditable(true);
box.getChildren().add(treeView);
stage.setScene(scene);
stage.show();
}
public static class Employee {
private final SimpleStringProperty name;
private final SimpleStringProperty department;
private Employee(String name, String department) {
this.name = new SimpleStringProperty(name);
this.department = new SimpleStringProperty(department);
}
public String getName() {
return name.get();
}
public void setName(String fName) {
name.set(fName);
}
public String getDepartment() {
return department.get();
}
public void setDepartment(String fName) {
department.set(fName);
}
}
}
新树项目按需
/* * Copyright (c) 2008, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.util.Arrays; import java.util.List; import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.event.ActionEvent; import javafx.scene.Scene; import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; import javafx.scene.control.TextField; import javafx.scene.control.TreeCell; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { List<Employee> employees = Arrays.<Employee>asList( new Employee("Jacob Smith", "Accounts Department"), new Employee("Judy Mayer", "IT Support"), new Employee("Gregory Smith", "IT Support")); TreeItem<String> rootNode = new TreeItem<>("MyCompany Human Resources"); public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { rootNode.setExpanded(true); for (Employee employee : employees) { TreeItem<String> empLeaf = new TreeItem<>(employee.getName()); boolean found = false; for (TreeItem<String> depNode : rootNode.getChildren()) { if (depNode.getValue().contentEquals(employee.getDepartment())){ depNode.getChildren().add(empLeaf); found = true; break; } } if (!found) { TreeItem depNode = new TreeItem(employee.getDepartment()); rootNode.getChildren().add(depNode); depNode.getChildren().add(empLeaf); } } stage.setTitle("Tree View Sample"); VBox box = new VBox(); final Scene scene = new Scene(box, 400, 300); scene.setFill(Color.LIGHTGRAY); TreeView<String> treeView = new TreeView<>(rootNode); treeView.setEditable(true); treeView.setCellFactory((TreeView<String> p) -> new TextFieldTreeCellImpl()); box.getChildren().add(treeView); stage.setScene(scene); stage.show(); } private final class TextFieldTreeCellImpl extends TreeCell<String> { private TextField textField; private final ContextMenu addMenu = new ContextMenu(); public TextFieldTreeCellImpl() { MenuItem addMenuItem = new MenuItem("Add Employee"); addMenu.getItems().add(addMenuItem); addMenuItem.setOnAction((ActionEvent t) -> { TreeItem newEmployee = new TreeItem<>("New Employee"); getTreeItem().getChildren().add(newEmployee); }); } @Override public void startEdit() { super.startEdit(); if (textField == null) { createTextField(); } setText(null); setGraphic(textField); textField.selectAll(); } @Override public void cancelEdit() { super.cancelEdit(); setText((String) getItem()); setGraphic(getTreeItem().getGraphic()); } @Override public void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); } else { if (isEditing()) { if (textField != null) { textField.setText(getString()); } setText(null); setGraphic(textField); } else { setText(getString()); setGraphic(getTreeItem().getGraphic()); if ( !getTreeItem().isLeaf()&&getTreeItem().getParent()!= null ){ setContextMenu(addMenu); } } } } private void createTextField() { textField = new TextField(getString()); textField.setOnKeyReleased((KeyEvent t) -> { if (t.getCode() == KeyCode.ENTER) { commitEdit(textField.getText()); } else if (t.getCode() == KeyCode.ESCAPE) { cancelEdit(); } }); } private String getString() { return getItem() == null ? "" : getItem().toString(); } } public static class Employee { private final SimpleStringProperty name; private final SimpleStringProperty department; private Employee(String name, String department) { this.name = new SimpleStringProperty(name); this.department = new SimpleStringProperty(department); } public String getName() { return name.get(); } public void setName(String fName) { name.set(fName); } public String getDepartment() { return department.get(); } public void setDepartment(String fName) { department.set(fName); } } }
上面的代码生成以下结果。
单元工厂
单元工厂可以向TreeView中的单个TreeItem添加具有特殊功能的TreeCell。
/* * Copyright (c) 2008, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.util.Arrays; import java.util.List; import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.scene.Scene; import javafx.scene.control.TextField; import javafx.scene.control.TreeCell; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { List<Employee> employees = Arrays.<Employee> asList(new Employee( "Jacob Smith", "Accounts Department"), new Employee("Isabella Johnson", "Accounts Department"), new Employee("Mike Graham", "IT Support"), new Employee("Judy Mayer", "IT Support"), new Employee("Gregory Smith", "IT Support")); TreeItem<String> rootNode; public static void main(String[] args) { Application.launch(args); } public Main() { this.rootNode = new TreeItem<>("MyCompany Human Resources"); } @Override public void start(Stage stage) { rootNode.setExpanded(true); for (Employee employee : employees) { TreeItem<String> empLeaf = new TreeItem<>(employee.getName()); boolean found = false; for (TreeItem<String> depNode : rootNode.getChildren()) { if (depNode.getValue().contentEquals(employee.getDepartment())) { depNode.getChildren().add(empLeaf); found = true; break; } } if (!found) { TreeItem<String> depNode = new TreeItem<>(employee.getDepartment()); rootNode.getChildren().add(depNode); depNode.getChildren().add(empLeaf); } } stage.setTitle("Tree View Sample"); VBox box = new VBox(); final Scene scene = new Scene(box, 400, 300); scene.setFill(Color.LIGHTGRAY); TreeView<String> treeView = new TreeView<>(rootNode); treeView.setEditable(true); treeView .setCellFactory((TreeView<String> p) -> new TextFieldTreeCellImpl()); box.getChildren().add(treeView); stage.setScene(scene); stage.show(); } private final class TextFieldTreeCellImpl extends TreeCell<String> { private TextField textField; public TextFieldTreeCellImpl() { } @Override public void startEdit() { super.startEdit(); if (textField == null) { createTextField(); } setText(null); setGraphic(textField); textField.selectAll(); } @Override public void cancelEdit() { super.cancelEdit(); setText((String) getItem()); setGraphic(getTreeItem().getGraphic()); } @Override public void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); } else { if (isEditing()) { if (textField != null) { textField.setText(getString()); } setText(null); setGraphic(textField); } else { setText(getString()); setGraphic(getTreeItem().getGraphic()); } } } private void createTextField() { textField = new TextField(getString()); textField.setOnKeyReleased((KeyEvent t) -> { if (t.getCode() == KeyCode.ENTER) { commitEdit(textField.getText()); } else if (t.getCode() == KeyCode.ESCAPE) { cancelEdit(); } }); } private String getString() { return getItem() == null ? "" : getItem().toString(); } } public static class Employee { private final SimpleStringProperty name; private final SimpleStringProperty department; private Employee(String name, String department) { this.name = new SimpleStringProperty(name); this.department = new SimpleStringProperty(department); } public String getName() { return name.get(); } public void setName(String fName) { name.set(fName); } public String getDepartment() { return department.get(); } public void setDepartment(String fName) { department.set(fName); } } }
上面的代码生成以下结果。
树单元编辑
我们可以使用以下树单元编辑器。
- CheckBoxTreeCell
- ChoiceBoxTreeCell
- ComboBoxTreeCell
- TextFieldTreeCell
有些类扩展了TreeCell实现来渲染单元格内的特定控件。
下面的代码创建一个带有复选框树项目的树视图。
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.CheckBoxTreeItem; import javafx.scene.control.TreeView; import javafx.scene.control.cell.CheckBoxTreeCell; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<>("A"); rootItem.setExpanded(true); TreeView tree = new TreeView(rootItem); tree.setEditable(true); tree.setCellFactory(CheckBoxTreeCell.forTreeView()); CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<>("a"); rootItem.getChildren().add(checkBoxTreeItem); checkBoxTreeItem = new CheckBoxTreeItem<>("b"); rootItem.getChildren().add(checkBoxTreeItem); tree.setRoot(rootItem); StackPane root = new StackPane(); root.getChildren().add(tree); primaryStage.setScene(new Scene(root, 300, 250)); primaryStage.show(); } }
上面的代码生成以下结果。