does anybody have a sample code for a tree with check boxes and text fields?
Because now I have a code for check box (only) based tree. I tried to implement also text fields in the tree (with Jlabels). But I get stucked and I am really confused. I can't get any further and I hoped that you can help me.
The issue is. I cant modify the text of JTextFields. The modification doesnt get saved. And I do not know how to add a JLabel in the same line of the JTextField
Root
|
|- Node 1
| - [-] Activate simulation
| - [100] Iterations
|- Node 2
| - [x] Activate simulation
| - [2000] Iterations
package view;
import javax.swing.BoxLayout;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JTextField;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.event.DocumentListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.EventObject;
import java.util.Vector;
import javax.swing.AbstractCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.DocumentEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
public class test {
private Document dom;
private void parseXmlFile(String xmlpath){
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
dom = db.parse(xmlpath);
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
}catch(SAXException se) {
se.printStackTrace();
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
public static void main(String args[]) {
JFrame frame = new JFrame("CheckBox Tree");
CheckBoxNode accessibilityOptions[] = {
new CheckBoxNode(
"Move system caret with focus/selection changes", false),
new CheckBoxNode("Always expand alt text for images", true) };
CheckBoxNode browsingOptions[] = {
new CheckBoxNode("Notify when downloads complete", true),
new CheckBoxNode("Disable script debugging", true),
new CheckBoxNode("Use AutoComplete", true),
new CheckBoxNode("Browse in a new process", false)
};
TextBoxNode loloptions[] =
{
new TextBoxNode("oha", "lol"),
new TextBoxNode("oha1", "lol"),
new TextBoxNode("oha2", "lol")
};
Vector accessVector = new NamedVector("Accessibility",
accessibilityOptions);
Vector browseVector = new NamedVector("Browsing", browsingOptions);
Vector browse1Vector = new NamedVector("Browsing", browsingOptions);
Vector browse2Vector = new NamedVector("textboxnodes", loloptions);
Object lolNodes[] = {browse1Vector, browseVector, browse2Vector};
Vector lolvec = new NamedVector("Overking", lolNodes);
Object rootNodes[] = { accessVector, lolvec};
lolvec.add(new CheckBoxNode("oh",false));
Vector rootVector = new NamedVector("Root", rootNodes);
JTree tree = new JTree(rootVector);
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
tree.setCellRenderer(renderer);
tree.setCellEditor(new CheckBoxNodeEditor(tree));
tree.setEditable(true);
for (int i = 0; i < tree.getRowCount(); i++) {
tree.expandRow(i);
}
JScrollPane scrollPane = new JScrollPane(tree);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
}
class CheckBoxNodeRenderer implements TreeCellRenderer {
private JCheckBox leafRenderer = new JCheckBox();
private JTextField leafRendererAlt = new JTextField();
private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
Color selectionBorderColor, selectionForeground, selectionBackground,
textForeground, textBackground;
protected Object getLeafRenderer() {
if(leafRenderer.getText().length() > 0)
return leafRenderer;
else
return leafRendererAlt;
}
public CheckBoxNodeRenderer() {
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");
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
Component returnValue;
if (leaf) {
String stringValue = tree.convertValueToText(value, selected,
expanded, leaf, row, false);
if(stringValue.contains("TextBoxNode"))
{
leafRenderer = new JCheckBox();
leafRendererAlt.setText(stringValue);
//leafRendererAlt.setValue(value);
leafRendererAlt.setEnabled(tree.isEnabled());
if (selected) {
leafRendererAlt.setForeground(selectionForeground);
leafRendererAlt.setBackground(selectionBackground);
} else {
leafRendererAlt.setForeground(textForeground);
leafRendererAlt.setBackground(textBackground);
}
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value)
.getUserObject();
if (userObject instanceof TextBoxNode) {
TextBoxNode node = (TextBoxNode) userObject;
leafRendererAlt.setText(node.getText());
}
}
returnValue = leafRendererAlt;
}
else
{
leafRendererAlt = new JTextField();
leafRenderer.setText(stringValue);
leafRenderer.setSelected(false);
leafRenderer.setEnabled(tree.isEnabled());
if (selected) {
leafRenderer.setForeground(selectionForeground);
leafRenderer.setBackground(selectionBackground);
} else {
leafRenderer.setForeground(textForeground);
leafRenderer.setBackground(textBackground);
}
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value)
.getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
leafRenderer.setText(node.getText());
leafRenderer.setSelected(node.isSelected());
}
}
returnValue = leafRenderer;
}
} else {
returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree,
value, selected, expanded, leaf, row, hasFocus);
}
return returnValue;
}
}
class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
ChangeEvent changeEvent = null;
JTree tree;
public CheckBoxNodeEditor(JTree tree) {
this.tree = tree;
}
public Object getCellEditorValue() {
JCheckBox checkbox;
JTextField textfield;
CheckBoxNode checkBoxNode;
TextBoxNode txtBoxNode;
if(renderer.getLeafRenderer() instanceof JCheckBox)
{
checkbox = (JCheckBox) renderer.getLeafRenderer();
checkBoxNode = new CheckBoxNode(checkbox.getText(),
checkbox.isSelected());
return checkBoxNode;
}
else
{
textfield = (JTextField) renderer.getLeafRenderer();
String txt = textfield.getText();
txtBoxNode = new TextBoxNode(txt, txt);
return txtBoxNode;
}
}
public boolean isCellEditable(EventObject event) {
boolean returnValue = false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
TreePath path = tree.getPathForLocation(mouseEvent.getX(),
mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
if((userObject instanceof TextBoxNode) || (userObject instanceof CheckBoxNode))
returnValue = treeNode.isLeaf();
}
}
}
return returnValue;
}
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = renderer.getTreeCellRendererComponent(tree, value,
true, expanded, leaf, row, true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
DocumentListener doclistener = new DocumentListener(){
public void changedUpdate(DocumentEvent e) {
System.out.print(e);
}
#Override
public void insertUpdate(DocumentEvent arg0) {
// TODO Auto-generated method stub
javax.swing.text.Document test = arg0.getDocument();
System.out.print(arg0);
fireEditingStopped();
}
#Override
public void removeUpdate(DocumentEvent arg0) {
// TODO Auto-generated method stub
System.out.print(arg0);
}
};
if (editor instanceof JCheckBox) {
((JCheckBox) editor).addItemListener(itemListener);
}
else if (editor instanceof JTextField)
{
((JTextField) editor).getDocument().addDocumentListener(doclistener);
}
return editor;
}
}
class CheckBoxNode {
String text;
boolean selected;
public CheckBoxNode(String text, boolean selected) {
this.text = text;
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean newValue) {
selected = newValue;
}
public String getText() {
return text;
}
public void setText(String newValue) {
text = newValue;
}
public String toString() {
return getClass().getName() + "[" + text + "/" + selected + "]";
}
}
class TextBoxNode{
String text;
String value;
public TextBoxNode(String text, String value) {
this.text = text;
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String newvalue) {
value = newvalue;
}
public String getText() {
return text;
}
public void setText(String newValue) {
text = newValue;
}
public String toString() {
return getClass().getName() + "[" + text + "/" + value + "]";
}
}
class NamedVector extends Vector {
String name;
public NamedVector(String name) {
this.name = name;
}
public NamedVector(String name, Object elements[]) {
this.name = name;
for (int i = 0, n = elements.length; i < n; i++) {
add(elements[i]);
}
}
public String toString() {
return "[" + name + "]";
}
}
The issue is. I cant modify the text of JTextFields. And I do not know how to add a JLabel in the same line of the JTextField
I hope you can help me.
In principle you should cleanly separate the renderer and the editor. In your case, they are closely tied together (in fact, the editor returns the JTextField instance of the renderer)... A renderer is not supposed to be editable. I doubt in your case that the editor is ever called.
I see two possible solutions:
Heavily refactor your code, to separate rendering and editing (e.g. rendering with JLabel and editing with JTextField -- or simply using a DefaultTreeCellEditor -- example here). Let the tree determine when the edit starts, when to call the editor, when to cancel an edit, etc...
Or you can by-pass the standard editing mechanism (as you are already doing more or less): Completely remove the TreeCellEditor from your code and let the renderer do all the work. Add appropriate listeners to your JTextField and JCheckBox inside the renderer, and update the model when changes are made. (Note that one drawback is that you'll have a primitive editing mechanism: e.g. the edit is not cancelled if user presses ESC).
As to:
And I do not know how to add a JLabel in the same line of the JTextField
Just let your renderer return a JPanel to which you add the JTextField and the JLabel.
Related
I'm trying to build a JTree with TestObjectCheckBoxNode leafs where each leaf holds a TestObject, everything appears to work except when I check the box in the leaf it is changing the node from a TestObjectCheckBoxNode to the CheckBoxNode superclass. I know this is happening in the TreeCellEditor implementation, specifically CheckBoxNodeEditor:getCellEditorValue(), because it is creating the updated TreeCellRenderer from the UI of that node.
CheckBoxNode checkBoxNode =
new CheckBoxNode(checkBoxPanel.label.getText(),
checkBoxPanel.checkBox.isSelected());
return checkBoxNode;
I'm at a complete loss for how would I do this in a way where I have access to the TestObject for the selected node in CheckBoxNodeEditor, so I could do something like this:
TestObjectCheckBoxNode testObjectCheckBoxNode =
new TestObjectCheckBoxNode(testObject,
checkBoxPanel.checkBox.isSelected());
return testObjectCheckBoxNode;
Here is the complete code below:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.font.TextAttribute;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventObject;
import java.util.Vector;
import javax.swing.AbstractCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
public class JCheckBoxTreeTest
{
private TestObjectCheckBoxTree tree;
public static void main(String... s)
{
new JCheckBoxTreeTest();
}
public JCheckBoxTreeTest()
{
JFrame frame = new JFrame("JCheckBoxTreeTest Tree");
Vector rootVector = new Category("Root", new Object[]
{
new Category("POI",
new TestObjectCheckBoxNode[] {
new TestObjectCheckBoxNode(new TestObject("TestObject 1"),true),
new TestObjectCheckBoxNode(new TestObject("TestObject 2"),true),
}),
});
tree = new TestObjectCheckBoxTree(rootVector);
tree.addTreeSelectionListener(new TreeSelectionListener()
{
public void valueChanged(TreeSelectionEvent e)
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
if (node == null) return;
Object userObject = ((DefaultMutableTreeNode) node).getUserObject();
System.err.println("node: " + node.toString());
System.err.println("userObject: " + userObject.toString());
}
});
tree.expandAll();
JScrollPane scrollPane = new JScrollPane(tree);
frame.getContentPane().add(scrollPane, BorderLayout.NORTH);
frame.setSize(360, 600);
frame.setVisible(true);
}
class TestObject
{
String name;
public TestObject(String inStr)
{
name = inStr;
}
}
public class CheckBoxNode
{
String text;
boolean selected;
public CheckBoxNode(String text, boolean selected)
{
this.text = text;
this.selected = selected;
}
public boolean isSelected() { return selected; }
public void setSelected(boolean newValue) { selected = newValue; }
public String getText() { return text; }
public void setText(String newValue) { text = newValue; }
public String toString() { return getClass().getName() + "[" + text + "/" + selected + "]"; }
}
public class TestObjectCheckBoxNode extends CheckBoxNode
{
TestObject testObject;
public TestObjectCheckBoxNode(TestObject testObject, boolean selected)
{
super(testObject.name, selected);
this.testObject = testObject;
}
}
public class CheckBoxTree extends JTree
{
public CheckBoxTree(Vector rootVector)
{
super(rootVector);
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
setCellRenderer(renderer);
setCellEditor(new CheckBoxNodeEditor());
setEditable(true);
}
public void expandAll()
{
expandAll(this, new TreePath(((DefaultMutableTreeNode)this.treeModel.getRoot()).getPath()), true);
}
private void expandAll(JTree tree, TreePath path, boolean expand) {
TreeNode node = (TreeNode) path.getLastPathComponent();
if (node.getChildCount() >= 0) {
Enumeration<? extends TreeNode> enumeration = node.children();
while (enumeration.hasMoreElements()) {
TreeNode treeNode = enumeration.nextElement();
TreePath treePath = path.pathByAddingChild(treeNode);
expandAll(tree, treePath, expand);
}
}
if (expand) {
tree.expandPath(path);
} else {
tree.collapsePath(path);
}
}
}
class CheckBoxPanel extends JPanel
{
public JCheckBox checkBox;
public JLabel label;
public CheckBoxPanel()
{
super();
checkBox = new JCheckBox();
label = new JLabel();
checkBox.setBorder(new EmptyBorder(0, 0, 0, 0));
add(checkBox);
add(label);
}
}
class CheckBoxNodeRenderer implements TreeCellRenderer
{
private CheckBoxPanel leafRenderer = new CheckBoxPanel();
private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
Color selectionBorderColor, selectionForeground, selectionBackground,
textForeground, textBackground;
protected CheckBoxPanel getLeafRenderer() {
return leafRenderer;
}
public CheckBoxNodeRenderer() {
Font fontValue;
fontValue = UIManager.getFont("Tree.font");
if (fontValue != null)
{
leafRenderer.checkBox.setFont(fontValue);
leafRenderer.label.setFont(fontValue);
//set the nonLeaf text to bold
nonLeafRenderer.setFont(fontValue.deriveFont(Collections.singletonMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD)));
}
Boolean booleanValue = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon");
leafRenderer.checkBox.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");
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus)
{
Component returnValue;
if (leaf)
{
String stringValue = tree.convertValueToText(value, selected,
expanded, leaf, row, false);
leafRenderer.checkBox.setSelected(false);
leafRenderer.label.setText(stringValue);
leafRenderer.setEnabled(tree.isEnabled());
if (selected) {
leafRenderer.setForeground(selectionForeground);
leafRenderer.setBackground(selectionBackground);
} else {
leafRenderer.setForeground(textForeground);
leafRenderer.setBackground(textBackground);
}
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value)
.getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
leafRenderer.checkBox.setSelected(node.isSelected());
leafRenderer.label.setText(node.getText());
}
}
returnValue = leafRenderer;
}
else
{
returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
}
return returnValue;
}
}
class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
TestObject testObject;
ChangeEvent changeEvent = null;
public Object getCellEditorValue()
{
CheckBoxPanel checkBoxPanel = renderer.getLeafRenderer();
if (testObject != null)
{
return new TestObjectCheckBoxNode(testObject, checkBoxPanel.checkBox.isSelected());
}
else
{
return new CheckBoxNode(checkBoxPanel.label.getText(), checkBoxPanel.checkBox.isSelected());
}
}
public boolean isCellEditable(EventObject event) {
boolean returnValue = false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
JTree tree = (JTree)event.getSource();
TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
returnValue = ((treeNode.isLeaf()) && (userObject instanceof CheckBoxNode));
}
}
}
return returnValue;
}
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row) {
Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
if (userObject instanceof TestObjectCheckBoxNode)
{
testObject = ((TestObjectCheckBoxNode)userObject).testObject;
}
else
{
testObject = null;
}
Component editor = renderer.getTreeCellRendererComponent(tree, value,
true, expanded, leaf, row, true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
if (editor instanceof CheckBoxPanel)
{
((CheckBoxPanel) editor).checkBox.addItemListener(itemListener);
}
return editor;
}
}
class Category extends Vector
{
String name;
public Category(String name)
{
this.name = name;
}
public Category(String name, Object elements[])
{
this.name = name;
for (int i = 0, n = elements.length; i < n; i++)
{
add(elements[i]);
}
}
public String toString()
{
return "[" + name + "]";
}
}
class TestObjectCheckBoxTree extends CheckBoxTree
{
public TestObjectCheckBoxTree(Vector rootVector)
{
super(rootVector);
}
}
}
When editing the tree node Swing calls CheckBoxNodeEditor.getTreeCellEditorComponent() with the current node as the value parameter. Later when you stop editing the node it calls CheckBoxNodeEditor.getCellEditorValue().
What you need to do: if the value in getTreeCellEditorComponent() is a TestObjectCheckBoxNode then store its testObject field into an instance field of the CheckBoxNodeEditor.
Later when getCellEditorValue() is called you can either return a TestObjectCheckBoxNode if the testObject was stored, otherwise return a ChechBoxNode.
The code could look like this (shortened) example:
class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
TestObject testObject;
public Object getCellEditorValue() {
CheckBoxPanel checkBoxPanel = renderer.getLeafRenderer();
if (testObject != null) {
return new TestObjectCheckBoxNode(testObject, checkBoxPanel.checkBox.isSelected());
} else {
return new CheckBoxNode(checkBoxPanel.label.getText(), checkBoxPanel.checkBox.isSelected());
}
}
public Component getTreeCellEditorComponent(
JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row
) {
Object realValue = ((DefaultMutableTreeNode) value).getUserObject();
if (realValue instanceof TestObjectCheckBoxNode n) {
testObject = n.testObject;
} else {
testObject = null;
}
// remaining code from your getTreeCellEditorComponent method
}
// other code removed for brevity
}
If you can't use the new pattern matching instanceof operator (because you don't use Java 16 or later) the if statement at the beginning of getTreeCellEditorComponent would need to be written as
public Component getTreeCellEditorComponent(
JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row
) {
Object realValue = ((DefaultMutableTreeNode) value).getUserObject();
if (realValue instanceof TestObjectCheckBoxNode) {
TestObjectCheckBoxNode n = (TestObjectCheckBoxNode) value;
testObject = n.testObject;
} else {
testObject = null;
}
// remaining code from your getTreeCellEditorComponent method
}
Why is the value in getTreeCellEditorComponent a DefaultMutableTreeNode?
The explanation is that JTree exclusively works with TreeNode instances. If you create a JTree with a Vector, a Hashtable or an Object[] it wraps the values that these contain in JTree.DynamicUtilTreeNode instances and sets your objects as userObject property on them.
The JTree.DynamicUtilTreeNode extends from DefaultMutableTreeNode.
Below is my code that displays images in a JList. I want to edit the description by each of the images shown in the JList. I don't know how to do it & need help. Thanks...
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Serializable;
public class DesignPicture2 {
private static String imageName;
static ArrayList<String> imgName = new ArrayList<String>();
public static void main(String[] args) throws Exception {
DesignPicture2 mm = new DesignPicture2();
mm.getImageName("C:\\Images 2 display");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("Image panel");
frame.setSize(800, 500);
//frame.setLocationByPlatform(true);
frame.setLocation(600, 300);
JList imageList = createImageList();
frame.getContentPane().add(new JScrollPane(imageList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JList createImageList() {
JList imageList = new JList(createModel("C:\\Images 2 display"));
imageList.setCellRenderer(new ImageCellRenderer());
imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
imageList.setVisibleRowCount(0);
imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imageList.setFixedCellWidth(240);
imageList.setFixedCellHeight(120);
// imageList.setDragEnabled(false);
//imageList.setDropMode(DropMode.INSERT);
imageList.setTransferHandler(new ImageTransferHandler(imageList));
return imageList;
}
private static DefaultListModel createModel(String path) {
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultListModel model = new DefaultListModel();
int count = 0;
for (int i = 0; i < listOfFiles.length - 1; i++) {
System.out.println("check path: " + listOfFiles[i]);
imageName = imgName.get(i).toString();
String name = listOfFiles[i].toString();
//load only JPEGS
if (name.endsWith("jpg")) {
try {
ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
model.add(count, ii);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return model;
}
static class ImageTransferHandler extends TransferHandler {
private static final DataFlavor DATA_FLAVOUR = new DataFlavor(ColorIcon.class, "Images");
private final JList previewList;
private boolean inDrag;
ImageTransferHandler(JList previewList) {
this.previewList = previewList;
}
public int getSourceActions(JComponent c) {
return TransferHandler.MOVE;
}
protected Transferable createTransferable(JComponent c) {
inDrag = true;
return new Transferable() {
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DATA_FLAVOUR};
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DATA_FLAVOUR);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return previewList.getSelectedValue();
}
};
}
public boolean canImport(TransferSupport support) {
if (!inDrag || !support.isDataFlavorSupported(DATA_FLAVOUR)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
if (dl.getIndex() == -1) {
return false;
} else {
return true;
}
}
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
Transferable transferable = support.getTransferable();
try {
Object draggedImage = transferable.getTransferData(DATA_FLAVOUR);
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
DefaultListModel model = (DefaultListModel) previewList.getModel();
int dropIndex = dl.getIndex();
if (model.indexOf(draggedImage) < dropIndex) {
dropIndex--;
}
model.removeElement(draggedImage);
model.add(dropIndex, draggedImage);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
protected void exportDone(JComponent source, Transferable data, int action) {
super.exportDone(source, data, action);
inDrag = false;
}
}
static class ImageCellRenderer extends JPanel implements ListCellRenderer {
int count = 0;
DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
JLabel imageLabel = new JLabel();
JLabel descriptionLabel = new JLabel();
ImageCellRenderer() {
setLayout(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
imageLabel.setBorder(emptyBorder);
descriptionLabel.setBorder(emptyBorder);
add(imageLabel, BorderLayout.AFTER_LINE_ENDS);
add(descriptionLabel, BorderLayout.SOUTH);
// imageLabel.setText(imgName.get(0).toString());
}
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
setBorder(defaultListCellRenderer.getBorder());
setBackground(defaultListCellRenderer.getBackground());
imageLabel.setIcon((Icon) value);
if (count > imgName.size() - 1) {
count = 0;
} else {
descriptionLabel.setText(imgName.get(count).toString());
}
return this;
}
}
public void getImageName(String path) {
int c = 0;
final File dir = new File(path);
// array of supported extensions (use a List if you prefer)
final String[] EXTENSIONS = new String[]{
"jpg", "gif", "png", "bmp" // and other formats you need
// filter to identify images based on their extensions
};
final FilenameFilter IMAGE_FILTER = new FilenameFilter() {
#Override
public boolean accept(final File dir, final String name) {
for (final String ext : EXTENSIONS) {
if (name.endsWith("." + ext)) {
return (true);
}
}
return (false);
}
};
if (dir.isDirectory()) { // make sure it's a directory
for (final File f : dir.listFiles(IMAGE_FILTER)) {
BufferedImage img = null;
c++;
try {
img = ImageIO.read(f);
// you probably want something more involved here
// to display in your UI
System.out.println("image: " + f.getName());
imgName.add(f.getName().toString());
} catch (final IOException e) {
// handle errors here
System.out.println("Error!");
}
}
System.out.println("C: " + c);
} else {
System.out.println("Invalid Directory!");
}
}
static class ColorIcon implements Icon, Serializable {
private Color color;
ColorIcon(Color color) {
this.color = color;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
g.fillRect(x, y, getIconWidth(), getIconHeight());
}
public int getIconWidth() {
return 200;
}
public int getIconHeight() {
return 100;
}
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
return color.equals(((ColorIcon) o).color);
}
}
}
When I run the above code, it show the image in proper way, but the description of each image is fixed and I don't know how to change it. Hope anyone can help me.
I agree with trashgod (+1 to his suggestion), a JTable will be a simpler solution, here's why...
JList doesn't support editability, so you'd need to create it...
So, first, we'd need some kind of ListModel that provided some additional functionality, in particular, the ability to set the value at a particular index...
import javax.swing.ListModel;
public interface MutableListModel<E> extends ListModel<E> {
public void setElementAt(E value, int index);
public boolean isCellEditable(int index);
}
Next, we'd need some kind editor, in this case, following standard Swing API conventions, this asks for some kind of base interface
import java.awt.Component;
import javax.swing.CellEditor;
import javax.swing.JList;
public interface ListCellEditor<E> extends CellEditor {
public Component getListCellEditorComponent(
JList<E> list,
E value,
boolean isSelected,
int index);
public void applyEditorValue(E value);
}
Now, we need to create ourselves a custom JList capable of actually performing all the required functionality of editing a cell value...
Things like...
Recognising a "start editing" event
Determine if the cell can be edited
Managing the editing process, preparing and showing the editor, knowing when the editor has stopped or canceled and clean up appropriately...
Handling selection changes while editing is in progress
Handling component focus change (which I've not done cause that's an awesome amount of fun in itself...)
For example...
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JList;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class EditableList<E> extends JList<E> {
private ListCellEditor<E> editor;
private int editingCell = -1;
private Component editorComponent;
private CellEditorHandler handler;
public EditableList(MutableListModel<E> model) {
this();
setModel(model);
}
public EditableList() {
InputMap im = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "editorCell");
ActionMap am = getActionMap();
am.put("editorCell", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Edit baby");
int cell = getSelectedIndex();
editCellAt(cell);
}
});
addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (isEditing()) {
if (!stopCellEditing()) {
cancelCellEditing();
}
}
}
});
}
public boolean isEditing() {
return editorComponent != null;
}
public void cancelCellEditing() {
getEditor().cancelCellEditing();
}
public boolean stopCellEditing() {
return getEditor().stopCellEditing();
}
public CellEditorHandler getCellEditorHandler() {
if (handler == null) {
handler = new CellEditorHandler();
}
return handler;
}
public void setEditor(ListCellEditor<E> value) {
if (value != editor) {
ListCellEditor old = editor;
editor = value;
firePropertyChange("editor", old, editor);
}
}
public ListCellEditor<E> getEditor() {
return editor;
}
public boolean isCellEditable(int cell) {
boolean isEditable = false;
ListModel model = getModel();
if (model instanceof MutableListModel) {
MutableListModel mcm = (MutableListModel) model;
isEditable = mcm.isCellEditable(cell);
}
return isEditable;
}
protected void editCellAt(int index) {
if (isCellEditable(index)) {
ListCellEditor<E> editor = getEditor();
if (editor != null) {
Rectangle cellBounds = getCellBounds(index, index);
E value = getModel().getElementAt(index);
boolean selected = isSelectedIndex(index);
editingCell = index;
editor.addCellEditorListener(getCellEditorHandler());
editorComponent = editor.getListCellEditorComponent(this, value, selected, index);
editorComponent.setBounds(cellBounds);
ensureIndexIsVisible(index);
add(editorComponent);
revalidate();
}
}
}
public int getEditingCell() {
return editingCell;
}
protected void editingHasStopped(ListCellEditor editor) {
editingCell = -1;
if (editorComponent != null) {
remove(editorComponent);
}
if (editor != null) {
editor.removeCellEditorListener(getCellEditorHandler());
}
}
public class CellEditorHandler implements CellEditorListener {
#Override
public void editingStopped(ChangeEvent e) {
E value = getModel().getElementAt(getEditingCell());
getEditor().applyEditorValue(value);
((MutableListModel) getModel()).setElementAt(value, getEditingCell());
editingHasStopped((ListCellEditor)e.getSource());
}
#Override
public void editingCanceled(ChangeEvent e) {
editingHasStopped((ListCellEditor)e.getSource());
}
}
}
Now, having done all that, you will need change the way you've structured your program, instead of using a List and ListModel to manage the descriptions and images separately, you should probably merge the concept into a single, manageable object, for example...
public class ImagePreview {
private String name;
private ImageIcon image;
public ImagePreview(String name, ImageIcon image) {
this.name = name;
this.image = image;
}
public String getDescription() {
return name;
}
public ImageIcon getImage() {
return image;
}
protected void setDescription(String description) {
this.name = description;
}
}
Even if you choose to use a JTable instead, you'll find this easier to manage...
Now we need some way to render and edit these values, to this end, I choose to start with a base component which could display the image and text...
public class ImagePreviewPane extends JPanel {
private JLabel imageLabel = new JLabel();
private JLabel descriptionLabel = new JLabel();
public ImagePreviewPane() {
setLayout(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
imageLabel.setBorder(emptyBorder);
descriptionLabel.setBorder(emptyBorder);
add(imageLabel, BorderLayout.CENTER);
add(descriptionLabel, BorderLayout.SOUTH);
}
protected JLabel getDescriptionLabel() {
return descriptionLabel;
}
protected JLabel getImageLabel() {
return imageLabel;
}
public void setImage(ImageIcon icon) {
imageLabel.setIcon(icon);
}
public void setDescription(String text) {
descriptionLabel.setText(text);
}
}
Create an extended version that could handle editing...
public static class ImagePreviewEditorPane extends ImagePreviewPane {
private JTextField editor;
public ImagePreviewEditorPane() {
super();
editor = new JTextField();
remove(getDescriptionLabel());
add(editor, BorderLayout.SOUTH);
}
#Override
public void setDescription(String text) {
editor.setText(text);
}
public String getDescription() {
return editor.getText();
}
public void setImagePreview(ImagePreview preview) {
setImage(preview.getImage());
setDescription(preview.getDescription());
}
#Override
public void addNotify() {
super.addNotify();
editor.requestFocusInWindow();
}
}
This is done to try and make it easier to modify the components later...
Next, a ListCellRenderer
public class ImageCellRenderer extends ImagePreviewPane implements ListCellRenderer {
public ImageCellRenderer() {
}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(this, getUI(), "List.dropCellBackground");
fg = DefaultLookup.getColor(this, getUI(), "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
setBackground(bg == null ? list.getSelectionBackground() : bg);
setForeground(fg == null ? list.getSelectionForeground() : fg);
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
if (value instanceof ImagePreview) {
ImagePreview ip = (ImagePreview) value;
setImage(ip.getImage());
setDescription(ip.getDescription());
} else {
setImage(null);
setDescription("??");
}
setEnabled(list.isEnabled());
setFont(list.getFont());
return this;
}
}
And editor...
public class ImagePreviewListCellEditor extends AbstactListCellEditor<ImagePreview> {
private ImagePreviewEditorPane previewPane;
public ImagePreviewListCellEditor() {
previewPane = new ImagePreviewEditorPane();
InputMap im = previewPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "accept");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
ActionMap am = previewPane.getActionMap();
am.put("accept", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
am.put("cancel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
cancelCellEditing();
}
});
}
public void applyEditorValue(ImagePreview preview) {
preview.setDescription(previewPane.getDescription());
}
#Override
public Component getListCellEditorComponent(JList<ImagePreview> list, ImagePreview value, boolean isSelected, int index) {
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellBackground");
fg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
previewPane.setBackground(bg == null ? list.getSelectionBackground() : bg);
previewPane.setForeground(fg == null ? list.getSelectionForeground() : fg);
} else {
previewPane.setBackground(list.getBackground());
previewPane.setForeground(list.getForeground());
}
if (value instanceof ImagePreview) {
ImagePreview preview = (ImagePreview)value;
previewPane.setImagePreview(preview);
} else {
previewPane.setImagePreview(null);
}
return previewPane;
}
}
And finally, putting it altogether...
public class DesignPicture2 {
public static void main(String[] args) throws Exception {
DesignPicture2 mm = new DesignPicture2();
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("Image panel");
frame.setSize(800, 500);
frame.setLocation(600, 300);
JList imageList = createImageList();
frame.getContentPane().add(new JScrollPane(imageList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JList createImageList() {
EditableList<ImagePreview> imageList = new EditableList(createModel("..."));
imageList.setEditor(new ImagePreviewListCellEditor());
imageList.setCellRenderer(new ImageCellRenderer());
imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
imageList.setVisibleRowCount(0);
imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imageList.setFixedCellWidth(240);
imageList.setFixedCellHeight(120);
return imageList;
}
private static MutableListModel<ImagePreview> createModel(String path) {
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultMutableListModel<ImagePreview> model = new DefaultMutableListModel<>();
int count = 0;
for (int i = 0; i < listOfFiles.length - 1; i++) {
System.out.println("check path: " + listOfFiles[i]);
String name = listOfFiles[i].toString();
if (name.endsWith("jpg")) {
try {
ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
model.addElement(new ImagePreview(name, ii));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return model;
}
}
JList does not support the notion of a cell editor. Instead, use a two-column JTable. Some important points:
Your model's isCellEditable() implementation should return true for the description column in order to make it editable.
Your model's implementation of getColumnClass() can let the default renderer display your image by returning ImageIcon or Icon .
I have a problem with adding new nodes to an existing tree. My tree is based on the CheckBoxNodeTreeSample you can see in the link:
http://www.java2s.com/Code/Java/Swing-JFC/CheckBoxNodeTreeSample.htm
I'm simply trying to add a new node by doing the 'standard' thing:
DefaultTreeModel model = (DefaultTreeModel) this.view.getResultTree().getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("newNode");
root.add(newNode);
model.reload(root);
This works fine, a new node is added, but the difference from the other existing nodes is that I can't click the checkbox, it's not clickable. I tried to print the path of the new node and an existing node, it looks like this:
newNode
Model.CheckBoxNode[Person,..../true]
I been trying to solve this for some time now, but I can't see how to solve this.. Some help would be appreciated! :)
Should i try to add vectors like this? and might this be why the standard solution doesn't work? Been trying this, but the model doesn't like vectors, objects or anything like that.. Casting isn't working either. This is the initialization of the tree, and how they use vectors and checkboxnodes :
CheckBoxNode accessibilityOptions[] = {
new CheckBoxNode(
"Move system caret with focus/selection changes", false),
new CheckBoxNode("Always expand alt text for images", true) };
CheckBoxNode browsingOptions[] = {
new CheckBoxNode("Notify when downloads complete", true),
new CheckBoxNode("Disable script debugging", true),
new CheckBoxNode("Use AutoComplete", true),
new CheckBoxNode("Browse in a new process", false) };
Vector accessVector = new NamedVector("Accessibility",
accessibilityOptions);
Vector browseVector = new NamedVector("Browsing", browsingOptions);
Object rootNodes[] = { accessVector, browseVector };
Vector rootVector = new NamedVector("Root", rootNodes);
JTree tree = new JTree(rootVector);
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
tree.setCellRenderer(renderer);
tree.setCellEditor(new CheckBoxNodeEditor(tree));
tree.setEditable(true);
Just in case if you didn't find any proper answer, here is a post I asked and answered how to build checkbox tree:
LINK
It might help you
I made an SSCCE. There is a button you can click to add a new node, with a checkbox but it's not clickable. I'm not creating a jcheckbox anywhere, so don't really understand where I should put an extra listener, and don't understand why it doesn't use getTreeCellEditorComponent() in the editor?
I also tried a slightly different approach where I use model.insertNodeInto(), but still I can't click the checkbox. I believe that I should be able to create a checkboxNode instead of a DefaultMutableTreeNode, but the JTree model doesn't want that, therefore trying to cast it to a DefaultMutableTreeNode.. Anyways, thanks for your help so far!
UPDATE:Because the new node is not of type CheckBoxNode. Therefore listeners doesn't work on the nodes. So now I'm looking for solutions to create a CheckBoxNode[], add it to a Vector, and then add that as a node (it that is possible!). That's how the author made the JTree, so I guess something like that could be the answer!
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import java.util.Vector;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
public class CheckBoxNodeTreeSample {
private static JTree tree;
public static void main(String args[]) {
JFrame frame = new JFrame("CheckBox Tree");
CheckBoxNode accessibilityOptions[] = {
new CheckBoxNode(
"Move system caret with focus/selection changes", false),
new CheckBoxNode("Always expand alt text for images", true) };
CheckBoxNode browsingOptions[] = {
new CheckBoxNode("Notify when downloads complete", true),
new CheckBoxNode("Disable script debugging", true),
new CheckBoxNode("Use AutoComplete", true),
new CheckBoxNode("Browse in a new process", false) };
Vector accessVector = new NamedVector("Accessibility",
accessibilityOptions);
Vector browseVector = new NamedVector("Browsing", browsingOptions);
Object rootNodes[] = { accessVector, browseVector };
Vector rootVector = new NamedVector("Root", rootNodes);
tree = new JTree(rootVector);
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
tree.setCellRenderer(renderer);
tree.setCellEditor(new CheckBoxNodeEditor(tree));
tree.setEditable(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.getContentPane().add(scrollPane, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
JButton button = new JButton("new node");
buttonPanel.add(button);
frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New node");
root.add(newNode);
model.reload();
}
});
frame.setSize(300, 450);
frame.setVisible(true);
}
}
class CheckBoxNodeRenderer implements TreeCellRenderer {
private JCheckBox leafRenderer = new JCheckBox();
private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
Color selectionBorderColor, selectionForeground, selectionBackground,
textForeground, textBackground;
protected JCheckBox getLeafRenderer() {
return leafRenderer;
}
public CheckBoxNodeRenderer() {
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");
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
Component returnValue;
if (leaf) {
String stringValue = tree.convertValueToText(value, selected,
expanded, leaf, row, false);
leafRenderer.setText(stringValue);
leafRenderer.setSelected(false);
leafRenderer.setEnabled(tree.isEnabled());
if (selected) {
leafRenderer.setForeground(selectionForeground);
leafRenderer.setBackground(selectionBackground);
} else {
leafRenderer.setForeground(textForeground);
leafRenderer.setBackground(textBackground);
}
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value)
.getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
leafRenderer.setText(node.getText());
leafRenderer.setSelected(node.isSelected());
}
}
returnValue = leafRenderer;
} else {
returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree,
value, selected, expanded, leaf, row, hasFocus);
}
return returnValue;
}
}
class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
ChangeEvent changeEvent = null;
JTree tree;
public CheckBoxNodeEditor(JTree tree) {
this.tree = tree;
}
public Object getCellEditorValue() {
JCheckBox checkbox = renderer.getLeafRenderer();
CheckBoxNode checkBoxNode = new CheckBoxNode(checkbox.getText(),
checkbox.isSelected());
return checkBoxNode;
}
public boolean isCellEditable(EventObject event) {
boolean returnValue = false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
TreePath path = tree.getPathForLocation(mouseEvent.getX(),
mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
returnValue = ((treeNode.isLeaf()) && (userObject instanceof CheckBoxNode));
}
}
}
return returnValue;
}
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = renderer.getTreeCellRendererComponent(tree, value,
true, expanded, leaf, row, true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
if (editor instanceof JCheckBox) {
((JCheckBox) editor).addItemListener(itemListener);
}
return editor;
}
}
class CheckBoxNode {
String text;
boolean selected;
public CheckBoxNode(String text, boolean selected) {
this.text = text;
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean newValue) {
selected = newValue;
}
public String getText() {
return text;
}
public void setText(String newValue) {
text = newValue;
}
public String toString() {
return getClass().getName() + "[" + text + "/" + selected + "]";
}
}
class NamedVector extends Vector {
String name;
public NamedVector(String name) {
this.name = name;
}
public NamedVector(String name, Object elements[]) {
this.name = name;
for (int i = 0, n = elements.length; i < n; i++) {
add(elements[i]);
}
}
public String toString() {
return "[" + name + "]";
}
}
A JTree uses TreeCellRenderer and TreeCellEditor to display three custom nodes:
a single JCheckBox
a single JButton
a JPanel composed by any action Component (here is a JCheckBox on North and a JButton on South)
screenshot: http://i.imgur.com/9j6B2ji.png
There is no problem with such a tree if you use Java Runtime Environment 6.
Besides using Java Runtime Environment 7, my problem occurs when I click on the JButton inside the JPanel node. The 'click' animation for JButton is not rendered the first time you click in JPanel (and after each time the node with JPanel stops being edited). The first node JCheckBox and the second node JButton are working perfectly with jre6 and jre7 either.
I would like to make it work exactly like before in jre6, is there a workaround?
Note: it's not a problem on making a button perform your code.
import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
class TreeNodeModel{
public boolean isJCheckBox = false;
public boolean isJButton = false;
public boolean isJPanel = false;
public Component userObject = null;
public TreeNodeModel(String name){
if( name.equals("JCheckBox") ){
isJCheckBox = true;
}else if( name.equals("JButton") ){
isJButton = true;
}else if( name.equals("JPanel") ){
isJPanel = true;
}
}
}
class CustomTreeCellRenderer implements TreeCellRenderer{
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component returnValue = null;
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof TreeNodeModel) {
TreeNodeModel node = (TreeNodeModel) userObject;
if(node.isJButton){
returnValue = new JButton("Ok");
}else if(node.isJCheckBox){
returnValue = new JCheckBox("Ok");
}else{
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JButton("Problem"), BorderLayout.SOUTH);
panel.add(new JCheckBox("Problem"), BorderLayout.NORTH);
returnValue = panel;
}
}
}
if(returnValue == null)
returnValue = new DefaultTreeCellRenderer().getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
return returnValue;
}
}
class CustomTreeCellEditor extends AbstractCellEditor implements TreeCellEditor {
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
Component returnValue = null;
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof TreeNodeModel) {
TreeNodeModel node = (TreeNodeModel) userObject;
if(node.isJButton){
returnValue = new JButton("Ok");
}else if(node.isJCheckBox){
returnValue = new JCheckBox("Ok");
}else{
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JButton("Problem"), BorderLayout.SOUTH);
panel.add(new JCheckBox("Problem"), BorderLayout.NORTH);
returnValue = panel;
}
}
}
return returnValue;
}
#Override
public Object getCellEditorValue() { return null; }
}
public class MyTestRendererEditor extends JFrame {
public MyTestRendererEditor() {
DefaultMutableTreeNode node = new DefaultMutableTreeNode("root");
node.add(new DefaultMutableTreeNode(new TreeNodeModel("JCheckBox")));
node.add(new DefaultMutableTreeNode(new TreeNodeModel("JButton")));
node.add(new DefaultMutableTreeNode(new TreeNodeModel("JPanel")));
final JTree tree = new JTree(new DefaultTreeModel(node));
tree.setCellRenderer(new CustomTreeCellRenderer());
tree.setCellEditor(new CustomTreeCellEditor());
tree.setEditable(true);
getContentPane().add(new JScrollPane(tree));
pack();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MyTestRendererEditor();
}
});
}
}
I have been trying to implement a CheckBox Node Tree, where the parent nodes also have checkbox.
I have been able to achieve the structure .
But when i try to implement the CellEditor , i am not able to check the leaf nodes .The parent nodes are checkable , but not the leaf nodes. Please give me some guidance .
/**
*CheckBoxNodeRenderer.java
*/
public class CheckBoxNodeRenderer implements TreeCellRenderer{
public JCheckBox getLeafRenderer()
{
return leafRenderer;
}
public CheckBoxNodeRenderer()
{
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");
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus)
{
Component returnValue;
if (leaf) {
String stringValue = tree.convertValueToText(value, selected,
expanded, leaf, row, false);
if (selected) {
leafRenderer.setForeground(selectionForeground);
leafRenderer.setBackground(selectionBackground);
} else {
leafRenderer.setForeground(textForeground);
leafRenderer.setBackground(textBackground);
}
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value)
.getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
leafRenderer.setText(node.getText());
leafRenderer.setSelected(node.isSelected());
}
}
returnValue = leafRenderer;
} else {
leafRenderer.setText(value.toString());
leafRenderer.setSelected(selected);
returnValue = leafRenderer;
}
return returnValue;
}
public JCheckBox leafRenderer = new JCheckBox();
private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
Color selectionBorderColor, selectionForeground, selectionBackground,
textForeground, textBackground;
}
The code below is the checkBoxNodeEditor.java
/**
*CheckBoxNodeEditor.java
*/
public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
public CheckBoxNodeEditor(JTree tree) {
this.tree = tree;
}
/**
* Checkbox node editor for node selection
*/
public Object getCellEditorValue() {
GenerateCube.nodeselection();
return GenerateCube.selectNode;
}
/**
* Cell Editable
*/
public boolean isCellEditable(EventObject event) {
boolean returnValue = false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
path = tree.getPathForLocation(mouseEvent.getX(),
mouseEvent.getY());
model = (DefaultTreeModel) (tree.getModel());
if (path != null) {
if(path.getChildCount > 0) {
Object node = path.getPathComponent(0);
}
else{
Object node = path.getLastPathComponent();
}
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
returnValue = ((treeNode.isLeaf()) && (userObject instanceof CheckBoxNode));
}
}
}
return returnValue;
}
/**
* getting Tree Cell Editor Component
*/
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = GenerateCube.renderer.getTreeCellRendererComponent(tree, value,
true, expanded, leaf, row, true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
} };
if (editor instanceof JCheckBox) {
((JCheckBox) editor).addItemListener(itemListener);
}
return editor;
}
static int n;
public static JTree tree;
static DefaultTreeModel model ;
ChangeEvent changeEvent = null;
public static TreePath path ;
public static String parentstring;
public static DefaultMutableTreeNode nNode;
public static MutableTreeNode node;
String nodeName;
}
maybe this code can help you with TreeCellEditor/Renderer
import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import java.util.Vector;
import javax.swing.*;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
//import org.pushingpixels.substance.api.skin.SubstanceOfficeSilver2007LookAndFeel;
public class CheckBoxNodeTreeSample {
public static void main(String args[]) {
JFrame frame = new JFrame("CheckBox Tree");
//setLookAndFeel();
CheckBoxNode accessibilityOptions[] = {new CheckBoxNode(
"Move system caret with focus/selection changes", false),
new CheckBoxNode("Always expand alt text for images", true)};
CheckBoxNode browsingOptions[] = {
new CheckBoxNode("Notify when downloads complete", true),
new CheckBoxNode("Disable script debugging", true),
new CheckBoxNode("Use AutoComplete", true),
new CheckBoxNode("Browse in a new process", false)};
Vector accessVector = new NamedVector("Accessibility",
accessibilityOptions);
Vector browseVector = new NamedVector("Browsing", browsingOptions);
Object rootNodes[] = {accessVector, browseVector};
Vector rootVector = new NamedVector("Root", rootNodes);
JTree tree = new JTree(rootVector);
CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
tree.setCellRenderer(renderer);
tree.setCellEditor(new CheckBoxNodeEditor(tree));
tree.setEditable(true);
JScrollPane scrollPane = new JScrollPane(tree);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
}
private static void setLookAndFeel() {
/*SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
//UIManager.setLookAndFeel(new SubstanceAutumnLookAndFeel());
UIManager.setLookAndFeel(new SubstanceOfficeSilver2007LookAndFeel());
} catch (UnsupportedLookAndFeelException e) {
throw new RuntimeException(e);
}
}
});*/
}
}
class CheckBoxNodeRenderer implements TreeCellRenderer {
private JCheckBox leafRenderer = new JCheckBox();
private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
private Color selectionBorderColor, selectionForeground, selectionBackground,
textForeground, textBackground;
protected JCheckBox getLeafRenderer() {
return leafRenderer;
}
public CheckBoxNodeRenderer() {
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");
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
Component returnValue;
if (leaf) {
String stringValue = tree.convertValueToText(value, selected,
expanded, leaf, row, false);
leafRenderer.setText(stringValue);
leafRenderer.setSelected(false);
leafRenderer.setEnabled(tree.isEnabled());
if (selected) {
leafRenderer.setForeground(selectionForeground);
leafRenderer.setBackground(selectionBackground);
} else {
leafRenderer.setForeground(textForeground);
leafRenderer.setBackground(textBackground);
}
if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof CheckBoxNode) {
CheckBoxNode node = (CheckBoxNode) userObject;
leafRenderer.setText(node.getText());
leafRenderer.setSelected(node.isSelected());
}
}
returnValue = leafRenderer;
} else {
returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree,
value, selected, expanded, leaf, row, hasFocus);
}
return returnValue;
}
}
private class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
private CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
private ChangeEvent changeEvent = null;
private JTree tree;
public CheckBoxNodeEditor(JTree tree) {
this.tree = tree;
}
public Object getCellEditorValue() {
JCheckBox checkbox = renderer.getLeafRenderer();
CheckBoxNode checkBoxNode = new CheckBoxNode(checkbox.getText(),
checkbox.isSelected());
return checkBoxNode;
}
#Override
public boolean isCellEditable(EventObject event) {
boolean returnValue = false;
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
TreePath path = tree.getPathForLocation(mouseEvent.getX(),
mouseEvent.getY());
if (path != null) {
Object node = path.getLastPathComponent();
if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
Object userObject = treeNode.getUserObject();
returnValue = ((treeNode.isLeaf()) && (userObject instanceof CheckBoxNode));
}
}
}
return returnValue;
}
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row) {
Component editor = renderer.getTreeCellRendererComponent(tree, value,
true, expanded, leaf, row, true);
// editor always selected / focused
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent itemEvent) {
if (stopCellEditing()) {
fireEditingStopped();
}
}
};
if (editor instanceof JCheckBox) {
((JCheckBox) editor).addItemListener(itemListener);
}
return editor;
}
}
class CheckBoxNode {
private String text;
private boolean selected;
public CheckBoxNode(String text, boolean selected) {
this.text = text;
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean newValue) {
selected = newValue;
}
public String getText() {
return text;
}
public void setText(String newValue) {
text = newValue;
}
#Override
public String toString() {
return getClass().getName() + "[" + text + "/" + selected + "]";
}
}
class NamedVector extends Vector {
private String name;
public NamedVector(String name) {
this.name = name;
}
public NamedVector(String name, Object elements[]) {
this.name = name;
for (int i = 0, n = elements.length; i < n; i++) {
add(elements[i]);
}
}
#Override
public String toString() {
return "[" + name + "]";
}
}