javaswingjtreestrikethroughtreecellrenderer

Strikethrough a node in a JTree


In my project i have a Jtree with custom node (which extends DefaultMutableTreeNode). Each node is associated with a boolean value. When the boolean is False i woul like to strike the texte of my node. So for example :

I tried to create a new Font but i don't find any properties to strike the text and i only managed to add my custom font to the whole tree and not node by node.

I think that i should use the TreeRenderer but i can't find any method to help me strike the node.

Does someone have an idea on i can do it ?


Solution

  • Check out the example below. For keeping it simple, I am just striking through the selected node. You need to, of course, use your own check on the value.

    package snippet;
    
    import java.awt.Component;
    import java.awt.Font;
    import java.awt.font.TextAttribute;
    import java.util.Map;
    
    import javax.swing.JFrame;
    import javax.swing.JTree;
    import javax.swing.SwingUtilities;
    import javax.swing.tree.DefaultTreeCellRenderer;
    
    public class JTreeTest extends JFrame {
        private final class StrikeoutCellRenderer extends DefaultTreeCellRenderer {
            private static final long serialVersionUID = 1L;
    
            @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
                    boolean leaf, int row, boolean hasFocus) {
                Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
                Font font = c.getFont();
                Map attributes = font.getAttributes();
                if(sel)
                    attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
                else
                    attributes.remove(TextAttribute.STRIKETHROUGH);
                Font newFont = new Font(attributes);
                c.setFont(newFont);
                return c;
            }
    
        }
    
        private static final long serialVersionUID = 1L;
    
        public JTreeTest() {
            super(JTreeTest.class.getName());
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            initComponents();
        }
    
        private void initComponents() {
            JTree tree = new JTree();
            tree.setCellRenderer(new StrikeoutCellRenderer());
            add(tree);
            pack();
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override public void run() {
                    JTreeTest t = new JTreeTest();
                    t.setVisible(true);
                }
            });
        }
    }
    

    Note that even if the node doesn't need a strike through, you need to reset the attribute, since a single component is used for painting all the nodes.