Change The icon of a certain Node in JTree? - java

I have a JTree and nodes of it are driven from DefaultMutableTreeNode. Each node can be verify or not.At first the icon of all nodes are the same but, I am going to change the ICON of the verified nodes when I select them and press the verify button.I want to have the ability to click and write on each node so I can not use JLabel to show icons.
I made the following code but it returns NULLException.
class CustomIconRenderer extends DefaultTreeCellRenderer {
ImageIcon defaultIcon;
ImageIcon specialIcon;
ImageIcon closeIcon;
static DefaultTreeModel model;
static myDefaultMutableTreeNode root;
public CustomIconRenderer()
{
openIcon = new ImageIcon(CustomIconRenderer.class.getResource("icons/question.png"));
closeIcon = new ImageIcon(CustomIconRenderer.class.getResource("icons/Target-New-Logo.jpg"));
setLeafIcon(closeIcon);
}
#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);
Object nodeObj = ((DefaultMutableTreeNode)value).getUserObject();
Check_each_nodes_are_verified_change_the_icon();
return this;
}
}
public class myDefaultMutableTreeNode extends DefaultMutableTreeNode{
private static int id=0;
private int nodeid;
private int verify;
private int depth;
}
Millions Thanks.

The DefaultTreeCellRenderer has setters, allowing to set open icon, closed icon and leaf icon. Inside the overridden getTreeCellRendererComponent, set these icons in your derived renderer class how you want and then return that is returned by super.getTreeCellRendererComponent. As you set for every node before you render, you can easily have some different icon for the particular node.

Related

Get JTree node text inside method getTreeCellRendererComponent from the custom renderer

I am customizing a JTree so some nodes have checkboxes, using santhosh tekuri's work as a base.
So the idea is writing a custom TreeCellRenderer, which in this case extends JPanel and implements TreeCellRenderer, and then at the method getTreeCellRendererComponent I have to decide for each node if it is receiving a checkbox or not.
I have seen some other examples for a typical JTree to customize each node icon, but they relay on converting each node to a JLabel and getting its text, while here it is a JPanel.
This is how my renderer looks like:
public class CheckTreeCellRenderer extends JPanel implements TreeCellRenderer{
private CheckTreeSelectionModel selectionModel;
private TreeCellRenderer delegate;
private TristateCheckBox checkBox;
protected CheckTreeManager.CheckBoxCustomizer checkBoxCustomer;
public CheckTreeCellRenderer(TreeCellRenderer delegate, CheckTreeSelectionModel selectionModel){
this.delegate = delegate;
this.selectionModel = selectionModel;
this.checkBox = new TristateCheckBox("");
this.checkBox.setOpaque(false);
setLayout(new BorderLayout());
setOpaque(false);
}
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus){
Component renderer = delegate.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
// Inside this if clause, those cells which do not require checkbox will be returned
if({CODE_TO_GET_NODE_TEXT}.startsWith("A")){
return renderer;
}
TreePath path = tree.getPathForRow(row);
if(path != null){
if(checkBoxCustomer != null && !checkBoxCustomer.showCheckBox(path)){
return renderer;
}
if(selectionModel.isPathSelected(path, selectionModel.isDigged())){
checkBox.getTristateModel().setState(TristateState.SELECTED);
}
else{
checkBox.getTristateModel().setState(selectionModel.isDigged() && selectionModel.isPartiallySelected(path) ? TristateState.INDETERMINATE : TristateState.DESELECTED);
}
}
removeAll();
add(checkBox, BorderLayout.WEST);
add(renderer, BorderLayout.CENTER);
return this;
}
}
In this case I want to avoid setting a Tristate checkbox for those cells whose texts starts with "A" as an example. But I can't find a way to get the text from the value argument.
In case it helps, this is how I create the JTree:
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
JTree tree = new JTree(root);
// Add nodes to the tree
DefaultMutableTreeNode friends_node = new DefaultMutableTreeNode("Friends");
friends_node.add(new DefaultMutableTreeNode("Anna"));
friends_node.add(new DefaultMutableTreeNode("Amador"));
friends_node.add(new DefaultMutableTreeNode("Jonas"));
friends_node.add(new DefaultMutableTreeNode("Mike"));
friends_node.add(new DefaultMutableTreeNode("Anthony"));
friends_node.add(new DefaultMutableTreeNode("Maya"));
friends_node.add(new DefaultMutableTreeNode("Pepe Vinyuela"));
root.add(friends_node);
tree.setCellRenderer(renderer = new CheckTreeCellRenderer(tree.getCellRenderer(), new CheckTreeSelectionModel(tree.getModel(), dig)));
Any idea?
If you're using String userObject = "Anna"; new DefaultMutableTreeNode(userObject);, then you might be able to use the DefaultMutableTreeNode#getUserObject() method:
#Override public Component getTreeCellRendererComponent(
JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
Component renderer = delegate.getTreeCellRendererComponent(
tree, value, selected, expanded, leaf, row, hasFocus);
if (value instanceof DefaultMutableTreeNode) {
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
// Inside this if clause, those cells which do not require checkbox will be returned
if(userObject instanceof String && ((String) userObject).startsWith("A")){
return renderer;
}
//...

TreeCellRenderer: how to set background color?

I've written a custom TreeCellRenderer in order to change a components appearance. Everything works fine, except that setBackground has no effect. The code is definitely executed as the foreground color always changes correctly. Since selected items are rendered in blue and deselected item in white (without having written that code myself), I assume that my changes are overridden by JTree. So what would be the proper way to change the background color?
This is essentially my code:
JTree tree = new JTree();
tree.setCellRenderer(new MyCellRenderer());
///////
public class MyCellRenderer extends DefaultTreeCellRenderer{
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean isSelected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, hasFocus);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
MyData data = (MyData)node.getUserObject();
if(data.isX()){
c.setForeground(Color.blue);
c.setBackground(Color.gray);
}
return c;
}
}
Try adding a call to c.setOpaque(true).

JTree set background of node to non-opaque

Please have a look at the SSCCE. How can I make the non-selected tree nodes' background transparent. At the moment the background of non-selected nodes is white. My cell renderer, however, should paint it non-opaque if it is not selected (and green when selected...what it does). In the end I want non-selected nodes to be just text without background, since the area which is red in the SSCCE has a gradient fill in my application.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
public class SimpleTree extends JFrame
{
public static void main(final String[] args)
{
new SimpleTree();
}
public SimpleTree()
{
super("Creating a Simple JTree");
final Container content = this.getContentPane();
content.setBackground(Color.RED);
final Object[] hierarchy = { "javax.swing", "javax.swing.border", "javax.swing.colorchooser", "javax.swing.event", "javax.swing.filechooser", new Object[] { "javax.swing.plaf", "javax.swing.plaf.basic", "javax.swing.plaf.metal", "javax.swing.plaf.multi" }, "javax.swing.table",
new Object[] { "javax.swing.text", new Object[] { "javax.swing.text.html", "javax.swing.text.html.parser" }, "javax.swing.text.rtf" }, "javax.swing.tree", "javax.swing.undo" };
final DefaultMutableTreeNode root = this.processHierarchy(hierarchy);
final JTree tree = new JTree(root);
tree.setOpaque(false);
tree.setCellRenderer(new MyCellRenderer());
final JScrollPane scroller = new JScrollPane(tree);
scroller.getViewport().setOpaque(false);
scroller.setOpaque(false);
content.add(scroller, BorderLayout.CENTER);
this.setSize(275, 300);
this.setVisible(true);
}
/**
* Small routine that will make node out of the first entry in the array,
* then make nodes out of subsequent entries and make them child nodes of
* the first one. The process is repeated recursively for entries that are
* arrays.
*/
private DefaultMutableTreeNode processHierarchy(final Object[] hierarchy)
{
final DefaultMutableTreeNode node = new DefaultMutableTreeNode(hierarchy[0]);
DefaultMutableTreeNode child;
for (int i = 1; i < hierarchy.length; i++)
{
final Object nodeSpecifier = hierarchy[i];
if (nodeSpecifier instanceof Object[]) // Ie node with children
child = this.processHierarchy((Object[]) nodeSpecifier);
else
child = new DefaultMutableTreeNode(nodeSpecifier); // Ie Leaf
node.add(child);
}
return (node);
}
public class MyCellRenderer extends DefaultTreeCellRenderer
{
#Override
public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus)
{
final Component ret = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
final DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (value));
this.setText(value.toString());
if (sel)
{
this.setOpaque(true);
this.setBackground(Color.GREEN);
}
else
{
this.setOpaque(false);
this.setBackground(null);
}
return ret;
}
}
}
You should override getBackgroundNonSelectionColor,getBackgroundSelectionColor and getBackground of DefaultTreeCellRenderer and return appropriate values like so:
public class MyCellRenderer extends DefaultTreeCellRenderer {
#Override
public Color getBackgroundNonSelectionColor() {
return (null);
}
#Override
public Color getBackgroundSelectionColor() {
return Color.GREEN;
}
#Override
public Color getBackground() {
return (null);
}
#Override
public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) {
final Component ret = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
final DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (value));
this.setText(value.toString());
return ret;
}
}
which will produce:
Other suggestions:
Create and manipulate Swing components on Event Dispatch Thread.
Dont extend JFrame unnecessarily rather create an instance and use that.
Dont call setSize on JFrame rather use a correct LayoutManager and/or override getPreferredSize() and call pack() on JFrame before setting it visible but after adding all components.
Remember to call JFrame#setDefaultCloseOperation with either DISPOSE_ON_CLOSE or EXIT_ON_CLOSE (DISPOSE_XXX is usually preferred unless using Timers as this will allow main(String[] args) to continue its execution after Gui has been closed).
To avoid background refilling, just put UIManager.put("Tree.rendererFillBackground", false); before new SimpleTree(); or after super("Creating a Simple JTree");.

List selection is not happening in swing

HI, I've a JLIST and assigned it a cellRenderer. but i was not able select element in list. Actually it is selected but visually we can not see that it is selected means i was not able to see which item is selected in list.
Screen shot of my list:
and what is expected is
The second screen shot is without CellRenderer. But when i add CellRenderer i was not able to see the selected item in list.
is it normal behaviour that when you add CellRenderer to list.
what am i doing wrong ???
EDIT:-
this is my CellRenderer class:
public class ContactsRender extends JLabel implements ListCellRenderer {
private static final long serialVersionUID = 1L;
ImageIcon img;
public ContactsRender(){
setOpaque(true);
setIconTextGap(12);
setBackground(Color.WHITE);
setForeground(Color.black);
}
#Override
public Component getListCellRendererComponent(JList list,
Object value, int index, boolean isSelected,
boolean cellHasFocus) {
if(value != null){
User user = (User) value;
String pres = user.getPresence().toLowerCase();
if(pres.contains("unavailable")){
img = new ImageIcon("res/offline.jpg");
} else {
img = new ImageIcon("res/online.jpg");
}
setText(user.getName());
setIcon(img);
return this;
}
return null;
}
You implemented your cell renderer incorrectly. The renderer is responsible for setting the renderer background to the selection color.
Read the JList API and follow the link to the Swing tutorial on "How to Use Lists" where you will find working examples that use a JList. You will also find a section on writing a renderer and an example.
Edit: Also, I just noticed you are reading your icon in the renderer code. You should never do this. The icon should only be read once when the renderer is created and then you cache the Icon. Every time a cell needs to be repainted the renderer is called so it is not efficient to keep reading the icon.
On your cell renderer, you have to implement the case for isSelected is true. For your ListCellRenderer :
Component getListCellRendererComponent(JList<? extends E> list,
E value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
if (!isSelected) doThis(index);
else doThatForSelectedItem(index);
}

java swing - add color to my JTree node

I have a created a following renderer which renders the JTree with checkboxes and I want to add different color and icon to different nodes. How do I do it? Please help me. Thank you in advance.
class CheckTreeCellRenderer extends JPanel implements TreeCellRenderer {
private CheckTreeSelectionModel selectionModel;
private TreeCellRenderer delegate;
private TristateCheckBox checkBox = new TristateCheckBox("",null,true);
public static final State NOT_SELECTED = new State();
public static final State SELECTED = new State();
public static final State DONT_CARE = new State();
public CheckTreeCellRenderer(TreeCellRenderer delegate, CheckTreeSelectionModel selectionModel) {
this.delegate = delegate;
this.selectionModel = selectionModel;
setLayout(new BorderLayout());
setOpaque(false);
checkBox.setState(Boolean.TRUE);
revalidate();
checkBox.setOpaque(false);
}
public Component getTreeCellRendererComponent
(JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
Component renderer = delegate.getTreeCellRendererComponent
(tree, value, selected, expanded, leaf, row, hasFocus);
TreePath path = tree.getPathForRow(row);
if(path!=null){
if(selectionModel.isPathSelected(path, true)) {
checkBox.setState(Boolean.TRUE);
}
else {
checkBox.setState
(selectionModel.isPartiallySelected(path) ? null : Boolean.FALSE);
}
}
setBackground(Color.pink);
removeAll();
add(checkBox, BorderLayout.WEST);
add(renderer, BorderLayout.CENTER);
return this;
}
}
The best place to learn about TreeCellRenderers is from the tutorial (at the bottom of the page).
Instead of adding renderer to BorderLayout.CENTER, you can just add a different icon of whatever color you like.
In order for your setBackground(Color.PINK) to have any visible effect, you should change the setOpaque(false) to setOpaque(true) in your constructor. That said, I second #John's suggestion that you read up on renderers in the Sun tutorials.

Categories