How can I get the text of selected item in a JTree?
From Java tutorial website on JTree:
//Where the tree is initialized:
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
//Listen for when the selection changes.
tree.addTreeSelectionListener(this);
public void valueChanged(TreeSelectionEvent e) {
//Returns the last path element of the selection.
//This method is useful only when the selection model allows a single selection.
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
if (node == null)
//Nothing is selected.
return;
Object nodeInfo = node.getUserObject();
if (node.isLeaf()) {
BookInfo book = (BookInfo) nodeInfo;
displayURL(book.bookURL);
} else {
displayURL(helpURL);
}
}
DefaultMutableTreeNode selectedElement
=(DefaultMutableTreeNode)tree.getSelectionPath().getLastPathComponent();
.....
System.out.println(selectedElement.getUserObject());
//For multiple selection you can use
TreePath[] treePaths = tree.getSelectionModel().getSelectionPaths();
for (TreePath treePath : treePaths) {
DefaultMutableTreeNode selectedElement = (DefaultMutableTreeNode)treePath.getLastPathComponent();
Object userObject = selectedElement.getUserObject(); //Do what you want with selected element's user object
}
DefaultMutableTreeNode newchild=new DefaultMutableTreeNode(textField.getText());
DefaultMutableTreeNode SelectedNode= (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
DefaultTreeModel treemodel=(DefaultTreeModel) tree.getModel();
JOptionPane.showMessageDialog(null, SelectedNode.getUserObject().toString());
if(SelectedNode!=null)
treemodel.insertNodeInto(newchild, SelectedNode, SelectedNode.getChildCount());
Related
I have a jtree with green leaf nodes and reds leaf nodes by implementing a custom CellRenderer.
i am doing this to expand the entire jtree:
expAll.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < jTree1.getRowCount(); i++) {
jTree1.expandRow(i);
}
}
});
but How to create a action to programatically expand my jtree to only leaf nodes that have Red cells?
Thanks here is the final code:
expFail.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Exand the root node
jTree1.expandRow(0);
//Getting the jtree row from the root containing my red and green leaf node
DefaultMutableTreeNode dirNode = (DefaultMutableTreeNode) jTree1.getPathForRow(2).getLastPathComponent();
Enumeration enumDir = dirNode.preorderEnumeration();
while (enumDir.hasMoreElements()) {
//Walking through all nodes of dirNode
DefaultMutableTreeNode enumDirNode = (DefaultMutableTreeNode) enumDir.nextElement();
//If node is leaf and is red (returned by isFailed()) expand to the previous node of this leaf node
if (enumDirNode.isLeaf() && !((LeafNodeObject) enumDirNode.getUserObject()).isFailed()) {
jTree1.expandPath(new javax.swing.tree.TreePath(enumDirNode.getPreviousNode().getPath()));
}
}
}
});
For learning purpose, i would like to build a tree view dynamically from an Enum, where i've defined tree item with their relationship.
MenuContext Enum
public enum MenuContext {
APP, // Tree menu of application
DIALOG; // Tree menu on dialog
}
TreeItems Enum
public enum TreeItems {
AM_ROOT(MenuContext.APP, null, ""),
NODE_1(MenuContext.APP, AM_ROOT, "Menu node 1"),
NODE_2(MenuContext.APP, AM_ROOT, "Menu node 2"),
NODE_2_1(MenuContext.APP, NODE_2, "Menu node 2.1"),
NODE_2_2(MenuContext.APP, NODE_2, "Menu node 2.2"),
NODE_2_3(MenuContext.APP, NODE_2, "Menu node 2.3"),
NODE_2_4(MenuContext.APP, NODE_2, "Menu node 2.4"),
NODE_3(MenuContext.APP, AM_ROOT, "Menu node 3"),
NODE_4(MenuContext.APP, AM_ROOT, "Menu node 4"),
DM_ROOT(MenuContext.DIALOG, null, ""),
DM_NODE_1(MenuContext.DIALOG, DM_ROOT, "Dialog menu node 1"),
DM_NODE_2(MenuContext.DIALOG, DM_ROOT, "Dialog menu node 2"),
DM_NODE_2_1(MenuContext.DIALOG, DM_NODE_2, "Dialog menu node 2.1"),
DM_NODE_2_2(MenuContext.DIALOG, DM_NODE_2, "Dialog menu node 2.2"),
DM_NODE_2_3(MenuContext.DIALOG, DM_NODE_2, "Dialog menu node 2.3"),
DM_NODE_2_4(MenuContext.DIALOG, DM_NODE_2, "Dialog menu node 2.4"),
DM_NODE_3(MenuContext.DIALOG, DM_ROOT, "Dialog menu node 3");
// Necessary code to get values of single enum item
}
With this structure i've tried to create the tree dynamically following the answer on Answer - fill javaFX treeView dynamically, i've seen the question and answer is referred to database for storing tree information.
So my question is how can i adapt, the building algorithm to an Enum source for data, because when i try to build tree dynamically with code proposed and that answer i can get tree items list one after another and not grouped by parent.
After numerous try and failure, i've found a way to build the tree view dynamically from a collection of objects, grouped by their parent, using this methods.
private TreeView<String> buildTree(MenuContext mC) {
List<TreeItems> roots = buildParents(mC);
EnumMap<TreeItems, TreeItem<String>> values = buildTreeValues(mC);
TreeView<String> tree = new TreeView<>();
TreeItem<String> root = null;
int rootsSize = roots.size();
// Build node w or w/o children in reverse order
for (int i = rootsSize - 1; i > 0; --i) {
EnumMap<TreeItems, TreeItem<String>> nodeChildren = getNodeChildren(roots.get(i),values);
for (Entry<TreeItems, TreeItem<String>> entry : nodeChildren.entrySet()) {
values.get(roots.get(i)).getChildren().add(entry.getValue());
values.remove(entry.getKey());
}
}
// Populate tree model
for (Entry<TreeItems, TreeItem<String>> entry : values.entrySet()) {
if (entry.getKey().getParent() == null) {
root = entry.getValue();
} else {
if (root == null) {
root = entry.getValue();
} else {
root.getChildren().add(entry.getValue());
}
}
}
tree.setRoot(root);
tree.setShowRoot(false);
return tree;
}
private EnumMap<TreeItems, TreeItem<String>> buildTreeValues(MenuContext mC) {
EnumMap<TreeItems, TreeItem<String>> treeValues = new EnumMap<>(TreeItems.class);
for (TreeItems tI : TreeItems.values()) {
if (tI.getMenuContext().equals(mC)) {
treeValues.put(tI, new TreeItem<>(tI.getLabel()));
}
}
return treeValues;
}
private List<TreeItems> buildParents(MenuContext mC) {
List<TreeItems> parents = new ArrayList<>();
for (TreeItems tI : TreeItems.values()) {
if (tI.getMenuContext().equals(mC) && !parents.contains(tI.getParent())) {
parents.add(tI.getParent());
}
}
return parents;
}
private EnumMap<TreeItems, TreeItem<String>> getNodeChildren(TreeItems root,
EnumMap<TreeItems, TreeItem<String>> values) {
EnumMap<TreeItems, TreeItem<String>> cNodes = new EnumMap<>(TreeItems.class);
for (Entry<TreeItems, TreeItem<String>> entry : values.entrySet()) {
TreeItems parentKey = entry.getKey().getParent();
if (parentKey != null && root.equals(parentKey)) {
cNodes.put(entry.getKey(), entry.getValue());
}
}
return cNodes;
}
I've tested the implementation, manually with an enum that have three level nesting, and generated tree display the values grouped correctly, by their parent.
I want to set for each node in my JTree a different icon, actually I'm loading each node from a data base, with a "while", I set each icon like a root, leaf or parent. Like this:
All my declarations are global:
private ResultSet myResultSet;
protected DefaultTreeModel treeModel;
private DefaultMutableTreeNode rootNode,childNode,parent1,parent2;
And this is the code where I set my nodes:
myResultSet=rtnNodes(); /*Method that returns a RS with my nodes*/
while(myResultSet.next()){
switch(myResultSet.getInt(1)){ /*The first column is the type of node: root, parent, leaf...*/
case 0: treeModel = new DefaultTreeModel((rootNode=new DefaultMutableTreeNode(myResultSet.getString(2)))); break; /*root node*/
case 1: case 4: parent1 = parent2 = makeNode(rootNode); break; /*parent node*/
case 2: makeNode(parent2); break; /*leaf node*/
case 3: parent2 = makeNode(parent1); break; /*sub patern node*/
} /*makeNode is the method where I create the nodes*/
}
The method makeNode is this:
public DefaultMutableTreeNode makeNode(DefaultMutableTreeNode parent){
//The second column in the RS is the name of the node
treeModel.insertNodeInto((childNode=new DefaultMutableTreeNode(myResultSet.getString(2))),parent,parent.getChildCount());
return childNode;
}
After to fill the treemodel with my nodes, I set the model to my JTree:
myJTree.setModel(treeModel);
myJTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
But the problem is. when I try to set the icons. I create a subclass called myTreeRenderer, and I use this:
myJTree.setCellRenderer(new treeRenderer());
But it doesn't set the icons as I want, the subclass is:
private ImageIcon root,parent,leaf;
public myTreeRenderer() {
root=setIcons(2); /*setIcons is a method that I dont publish in this post, that helps me to set the path of the icons*/
parent=setIcons(3);
leaf=setIcons(4);
}
#Override
public Component getTreeCellRendererComponent(JTree tree,Object value,boolean selected,boolean expanded,boolean leaf,int row,boolean hasFocus){
super.getTreeCellRendererComponent(tree,value,selected,expanded,leaf,row,hasFocus);
DefaultMutableTreeNode nodo = (DefaultMutableTreeNode)value;
TreeNode t = nodo.getParent();
if(t!=null){
setIcon(root);
}
return this;
}
How I can set the icon for each node without using his name? The code of the subclass, as is, set all the nodes with the same icon, and each time I selected a node in the jtree, the getTreeCellRendererComponent runs, I donĀ“t want this.
You can change default UI values for icons of JTree nodes without any custom renderer:
URL resource = logaff.class.getResource(IMAGE);
Icon icon = new ImageIcon(resource);
UIManager.put("Tree.closedIcon", icon);
UIManager.put("Tree.openIcon", icon);
UIManager.put("Tree.leafIcon", icon);
or use something like next:
#Override
public Component getTreeCellRendererComponent(JTree tree,
Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected,expanded, leaf, row, hasFocus);
DefaultMutableTreeNode nodo = (DefaultMutableTreeNode) value;
if (tree.getModel().getRoot().equals(nodo)) {
setIcon(root);
} else if (nodo.getChildCount() > 0) {
setIcon(parent);
} else {
setIcon(leaf);
}
return this;
}
Also read about rendering mechanism.
You can use it, a shorter way. "tree" is my JTree component.
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree.getCellRenderer();
Icon closedIcon = new ImageIcon("closed.png");
Icon openIcon = new ImageIcon("open.png");
Icon leafIcon = new ImageIcon("leaf.png");
renderer.setClosedIcon(closedIcon);
renderer.setOpenIcon(openIcon);
renderer.setLeafIcon(leafIcon);
I rendered a check box node tree.
The renderer renders the parent nodes with a (check box + folder like icon ) and the leaf nodes as (Only check box) .
I have rendered it and now i want to make it editable . (i.e) when i click it , the check boxes must be checked and unchecked .
I tried writing an editor . But i am not clear as to how to write it . Please guide me as to how to accomplish this .
Many thanks in advance .
I have built the tree from a Vector . The vector is called NamedVector and it contains Parent node objects . The parent node object holds the leaf nodes . The leaf nodes are of type CheckBoxNode.
public class CheckBoxNodeRenderer implements TreeCellRenderer{
NonLeafRenderer nonLeafRenderer = new NonLeafRenderer();
protected JCheckBox check;
protected JLabel label;
public JPanel panel;
CheckBoxNode checkNode;
public JCheckBox getLeafRenderer()
{
return leafRenderer;
}
public CheckBoxNodeRenderer()
{
panel = new JPanel();
panel.setLayout(new BorderLayout());
check = new JCheckBox();
label = new JLabel();
Font fontValue;
fontValue = UIManager.getFont("Tree.font");
if (fontValue != null) {
leafRenderer.setFont(fontValue);
}
Boolean booleanValue = (Boolean) UIManager
.get("Tree.drawsFocusBorderAroundIcon");
leafRenderer.setFocusPainted((booleanValue != null)
&& (booleanValue.booleanValue()));
selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
selectionForeground = UIManager.getColor("Tree.selectionForeground");
selectionBackground = UIManager.getColor("Tree.selectionBackground");
textForeground = UIManager.getColor("Tree.textForeground");
textBackground = UIManager.getColor("Tree.textBackground");
}
///////////////////
/**
* Approach by returning a panel .
*/
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean isSelected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
String stringValue = tree.convertValueToText(value, isSelected,
expanded, leaf, row, hasFocus);
panel.setEnabled(true);
if(leaf){
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
checkNode = (CheckBoxNode)node.getUserObject();
check.setSelected(checkNode.isSelected());
label.setFont(tree.getFont());
label.setText(value.toString());
label.setIcon(null);
panel.removeAll();
panel.add(check,BorderLayout.WEST);
panel.add(label);
panel.setVisible(true);
}
}
else if(!leaf){
if ((value != null) && (value instanceof DefaultMutableTreeNode) ) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
Object parent = (Object)node.getUserObject();
System.err.println(parent.toString());
NamedVector parentNode = (NamedVector) parent;
check.setSelected(parentNode.isSelected());
label.setFont(tree.getFont());
label.setText(parentNode.toString());
label.setIcon(UIManager.getIcon("Tree.openIcon"));
panel.removeAll();
panel.add(check,BorderLayout.WEST);
panel.add(label);
panel.setVisible(true);
}
}
return panel;
}
The issue is that you're not listening for the events. In your getTreeCellRendererComponent method, create a listener and then make sure to tell the tree model that you've changed a node via the nodeChanged method. The following should work (you might have to make some variables final to use them in the inner class though):
check.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent ev) {
checkNode.setSelected(check.isSelected());
DefaultTreeModel dtm = (DefaultTreeModel)tree.getModel();
dtm.nodeChanged(node);
}
});
I am using MouseAdapter to check for double clicks on JTree nodes. I want to have some different action depending on the level of the node selected. How can I check the level of node ? Here is the code for the listener:
private MouseAdapter getMouseAdapter(JTree jtree) {
final JTree tree = jtree;
return new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
if (selPath != null) {
if (e.getClickCount() == 2) {
String selectedNode = selPath.getLastPathComponent().toString();
// >>>>> check on which level of the tree this node is
}
}
}};
}
You can check the length of the path from selPath to the tree root by first calling the getPath() method of selPath and computing its length.
Object[] array = selPath.getPath();
int depth = array.length;
TreePath path = tree.getSelectionPath();
int level = path.getPathCount();
See the TreePath manual page.