Dynamically Modify a Node JTree Image

I am using CustomCellRenderer to display JTree nodes to display an image using node as shown below: -

class CustomTreeCellRenderer extends DefaultTreeCellRenderer{ 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); JLabel label = (JLabel) this ; label.setIcon( new ImageIcon("white.png") ) ; return this; } } 

My requirement is to change the node image to some external action. I am trying to reload the JTree model, but it does not work as shown below: -

 public void actionPerformed(ActionEvent ae) { DefaultTreeModel model = (DefaultTreeModel) tree.getModel() ; JLabel label = (JLabel) tree.getCellRenderer() ; System.out.println(label.getIcon()); //displaying white.png label.setIcon( new ImageIcon("black.gif") ) ; model.reload() ; } 

Where am I doing wrong ??????

+4
source share
2 answers

Add your icon to the rendering class as a field.

Change the value of this field and redraw the JTree.

 class CustomTreeCellRenderer extends DefaultTreeCellRenderer{ ImageIcon rendererIcon; public void setRendererIcon(ImageIcon myIcon){ this.rendererIcon = myIcon; }; 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); JLabel label = (JLabel) this ; label.setIcon( rendererIcon ) ; return this; } } 

Edit: explanations

In your case, changing the model is not possible. The icon used to display each of the nodes is part of the visualization tool.

The JTree rendering object must not be a JComponent . It must be an object that provides a JComponent when the code calls getTreeCellRendererComponent .

In your case, the listing of getCellRenderer () in JLabel just failed because the default implementation of DefaultTreeCellRenderer is an extension of JLabel .

And, in fact, since your renderer did indeed call setIcon on its own, it is normal that your getIcon methods give you the last icon you put in the rendering.

Full code work:

 import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultTreeCellRenderer; public class TestJTree { private static ImageIcon iconWhite = new ImageIcon("white.jpg"); private static ImageIcon iconBlack = new ImageIcon("black.jpg");; public static void main(String[] args) { TestJTree me = new TestJTree(); me.process(); } private void process() { SwingUtilities.invokeLater(new Runnable() { public void run() { initGui(); } }); } protected void initGui() { JFrame frame = new JFrame("Test JTree"); frame.setContentPane(new JPanel(new BorderLayout())); final JTree tree = new JTree(); frame.getContentPane().add(tree); final CustomTreeCellRenderer renderer = new CustomTreeCellRenderer(); renderer.setRendererIcon(iconWhite); tree.setCellRenderer(renderer); JPanel panelButtons = new JPanel(); JButton buttonWhite = new JButton(""); buttonWhite.setIcon(iconWhite); JButton buttonBlack = new JButton(""); buttonBlack.setIcon(iconBlack); buttonBlack.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { renderer.setRendererIcon(iconBlack); tree.repaint(); } }); panelButtons.add(buttonBlack); panelButtons.add(buttonWhite); frame.getContentPane().add(panelButtons,BorderLayout.SOUTH); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(500,500); frame.setVisible(true); } @SuppressWarnings("serial") private static class CustomTreeCellRenderer extends DefaultTreeCellRenderer{ ImageIcon rendererIcon; public void setRendererIcon(ImageIcon myIcon){ this.rendererIcon = myIcon; }; public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus){ Component ret = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); JLabel label = (JLabel) ret ; label.setIcon( rendererIcon ) ; return ret; } } } 
+1
source

a couple of points:

  • Capturing a renderer from a table in a method of type actionPerformed and changing it is not common practice. It should be noted that rendering is common, so you will affect all cells in the column that uses this rendering
  • even if you install Icon in your instance of the visualizer during actionPerformed , rendering is always available for drawing using the getTreeCellRendererComponent method and that you always set the icon to "white.png", so you can never display "black.gif".

You have the model state setting in the actionPerformed method, and then from getTreeCellRendererComponent you can request your model for the displayed icon.

eg:

 public void actionPerformed(ActionEvent ae) { MyCustomTreeModel model = (MyCustomTreeModel) tree.getModel() ; ... model.setMyState(state); //set the state based on the action } 

in renderer:

 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { MyCustomTreeModel model = (MyCustomTreeModel) tree.getModel(); .... setIcon(model.getMyIconBasedOnTheStateISetInActionPerformed()); return this; } 
+1
source

Source: https://habr.com/ru/post/1300291/


All Articles