This example shows how to filter JTree nodes and highlighting the matched nodes.
Example
Creating JTree
public class TreeExampleMain {
public static void main(String[] args) {
TreeNode projectHierarchyTreeNode =
TradingProjectDataService.instance.getProjectHierarchy();
JTree tree = new JTree(projectHierarchyTreeNode);
JTreeUtil.setTreeExpandedState(tree, true);
TreeFilterDecorator filterDecorator = TreeFilterDecorator.decorate(tree, createUserObjectMatcher());
tree.setCellRenderer(new TradingProjectTreeRenderer(() -> filterDecorator.getFilterField().getText()));
JFrame frame = createFrame();
frame.add(new JScrollPane(tree));
frame.add(filterDecorator.getFilterField(), BorderLayout.NORTH);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static BiPredicate<Object, String> createUserObjectMatcher() {
return (userObject, textToFilter) -> {
if (userObject instanceof ProjectParticipant) {
ProjectParticipant pp = (ProjectParticipant) userObject;
return pp.getName().toLowerCase().contains(textToFilter)
|| pp.getRole().toLowerCase().contains(textToFilter);
} else if (userObject instanceof Project) {
Project project = (Project) userObject;
return project.getName().toLowerCase().contains(textToFilter);
} else {
return userObject.toString().toLowerCase().contains(textToFilter);
}
};
}
private static JFrame createFrame() {
JFrame frame = new JFrame("JTree Filtering example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(500, 400));
return frame;
}
}
Tree filtering decorator
public class TreeFilterDecorator {
private final JTree tree;
private DefaultMutableTreeNode originalRootNode;
private BiPredicate<Object, String> userObjectMatcher;
private JTextField filterField;
public TreeFilterDecorator(JTree tree, BiPredicate<Object, String> userObjectMatcher) {
this.tree = tree;
this.originalRootNode = (DefaultMutableTreeNode) tree.getModel().getRoot();
this.userObjectMatcher = userObjectMatcher;
}
public static TreeFilterDecorator decorate(JTree tree, BiPredicate<Object, String> userObjectMatcher) {
TreeFilterDecorator tfd = new TreeFilterDecorator(tree, userObjectMatcher);
tfd.init();
return tfd;
}
public JTextField getFilterField() {
return filterField;
}
private void init() {
initFilterField();
}
private void initFilterField() {
filterField = new JTextField(15);
filterField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
filterTree();
}
@Override
public void removeUpdate(DocumentEvent e) {
filterTree();
}
@Override
public void changedUpdate(DocumentEvent e) {
filterTree();
}
});
}
private void filterTree() {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
String text = filterField.getText().trim().toLowerCase();
if (text.equals("") && tree.getModel().getRoot() != originalRootNode) {
model.setRoot(originalRootNode);
JTreeUtil.setTreeExpandedState(tree, true);
} else {
DefaultMutableTreeNode newRootNode = matchAndBuildNode(text, originalRootNode);
model.setRoot(newRootNode);
JTreeUtil.setTreeExpandedState(tree, true);
}
}
private DefaultMutableTreeNode matchAndBuildNode(final String text, DefaultMutableTreeNode oldNode) {
if (!oldNode.isRoot() && userObjectMatcher.test(oldNode.getUserObject(), text)) {
return JTreeUtil.copyNode(oldNode);
}
DefaultMutableTreeNode newMatchedNode = oldNode.isRoot() ? new DefaultMutableTreeNode(oldNode
.getUserObject()) : null;
for (DefaultMutableTreeNode childOldNode : JTreeUtil.children(oldNode)) {
DefaultMutableTreeNode newMatchedChildNode = matchAndBuildNode(text, childOldNode);
if (newMatchedChildNode != null) {
if (newMatchedNode == null) {
newMatchedNode = new DefaultMutableTreeNode(oldNode.getUserObject());
}
newMatchedNode.add(newMatchedChildNode);
}
}
return newMatchedNode;
}
}
Tree Renderer
public class TradingProjectTreeRenderer extends DefaultTreeCellRenderer {
private static final String SPAN_FORMAT = "<span style='color:%s;'>%s</span>";
private Supplier<String> filterTextSupplier;
public TradingProjectTreeRenderer(Supplier<String> filterTextSupplier) {
this.filterTextSupplier = filterTextSupplier;
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
Object userObject = node.getUserObject();
if (userObject instanceof ProjectParticipant) {
ProjectParticipant pp = (ProjectParticipant) userObject;
String text = String.format(SPAN_FORMAT, "rgb(0, 0, 150)",
renderFilterMatch(node, pp.getName()));
text += " [" + String.format(SPAN_FORMAT, "rgb(90, 70, 0)",
renderFilterMatch(node, pp.getRole())) + "]";
this.setText("<html>" + text + "</html>");
} else if (userObject instanceof Project) {
Project project = (Project) userObject;
String text = String.format(SPAN_FORMAT, "rgb(0,70,0)",
renderFilterMatch(node, project.getName()));
this.setText("<html>" + text + "</html>");
} else {
String text = String.format(SPAN_FORMAT, "rgb(120,0,0)",
renderFilterMatch(node, userObject.toString()));
this.setText("<html>" + text + "</html>");
}
return this;
}
private String renderFilterMatch(DefaultMutableTreeNode node, String text) {
if (node.isRoot()) {
return text;
}
String textToFilter = filterTextSupplier.get();
return HtmlHighlighter.highlightText(text, textToFilter);
}
}
JTree Util
public class JTreeUtil {
public static void setTreeExpandedState(JTree tree, boolean expanded) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getModel().getRoot();
setNodeExpandedState(tree, node, expanded);
}
public static void setNodeExpandedState(JTree tree, DefaultMutableTreeNode node, boolean expanded) {
for (DefaultMutableTreeNode treeNode : children(node)) {
setNodeExpandedState(tree, treeNode, expanded);
}
if (!expanded && node.isRoot()) {
return;
}
TreePath path = new TreePath(node.getPath());
if (expanded) {
tree.expandPath(path);
} else {
tree.collapsePath(path);
}
}
public static DefaultMutableTreeNode copyNode(DefaultMutableTreeNode oldNode) {
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(oldNode.getUserObject());
for (DefaultMutableTreeNode oldChildNode : JTreeUtil.children(oldNode)) {
DefaultMutableTreeNode newChildNode = new DefaultMutableTreeNode(oldChildNode.getUserObject());
newNode.add(newChildNode);
if (!oldChildNode.isLeaf()) {
copyChildrenTo(oldChildNode, newChildNode);
}
}
return newNode;
}
public static void copyChildrenTo(DefaultMutableTreeNode from, DefaultMutableTreeNode to) {
for (DefaultMutableTreeNode oldChildNode : JTreeUtil.children(from)) {
DefaultMutableTreeNode newChildNode = new DefaultMutableTreeNode(oldChildNode.getUserObject());
to.add(newChildNode);
if (!oldChildNode.isLeaf()) {
copyChildrenTo(oldChildNode, newChildNode);
}
}
}
@SuppressWarnings("unchecked")
public static List<DefaultMutableTreeNode> children(DefaultMutableTreeNode node) {
return Collections.list(node.children());
}
}
Other classes are same as our last examples.
Output
Example ProjectDependencies and Technologies Used:
|
|