1

I have a Problem with JTree and JButton It seems like when entering the Edit modus and hovering over the Buttons on the TreeCells, it Renderes some Part of the Tree inside the Button. Even when Dragging from one Button to another in the Same Row it Renderes the one Button over the other one.

Here a Short Selfexplaining Sample that you can copy paste to See what i mean.

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.EventObject;

import javax.swing.JButton;
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.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellEditor;
import javax.swing.tree.DefaultTreeCellRenderer;


public class MyProblemWithTree {

    public static void main(String...args) {
        JFrame frame = new JFrame("Panel");
        JScrollPane scroll = new JScrollPane();

        DefaultMutableTreeNode node = new DefaultMutableTreeNode("Root");

        DefaultMutableTreeNode nodeChild = new DefaultMutableTreeNode("childcaretaker1");
        nodeChild.add(new DefaultMutableTreeNode("child1"));
        nodeChild.add(new DefaultMutableTreeNode("child2"));

        node.add(nodeChild);


        final JTree tree = new JTree(node);

        tree.setCellRenderer(new MyTreeCellRenderer());
        tree.setEditable(true);
        tree.setCellEditor(new MyTreeCellEditor(tree));

        tree.addMouseMotionListener(new MouseMotionListener() {

            @Override
            public void mouseMoved(MouseEvent e) {
                // TODO Auto-generated method stub
                if (tree.getRowForLocation(e.getX(), e.getY()) != -1)
                {
                    tree.startEditingAtPath(tree.getPathForLocation(e.getX(), e.getY()));
                } 
            }

            @Override
            public void mouseDragged(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }
        });

        scroll.setViewportView(tree);
        frame.add(scroll);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}
class MyTreeCellEditor extends DefaultTreeCellEditor {

    JPanel      leafPanel;
    JLabel      colorIcon;
    PlayButton  play; 
    PauseButton pause;
    JLabel      name; 

    public MyTreeCellEditor(JTree tree) {
        super(tree, (MyTreeCellRenderer)tree.getCellRenderer());
        leafPanel   = new JPanel(new FlowLayout());
        colorIcon   = new JLabel(UIManager.getIcon("OptionPane.informationIcon"));
        play        = new PlayButton();
        pause       = new PauseButton();
        name        = new JLabel();

        play.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("Playbutton klickt");
            }
        });

        leafPanel.add(colorIcon);
        leafPanel.add(name);
        leafPanel.add(pause);
        leafPanel.add(play);
    }


    @Override
    public Component getTreeCellEditorComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row) {

        name.setText((String)((DefaultMutableTreeNode)value).getUserObject());
        pause.setVisible(!leaf);
        return leafPanel;
    }

    @Override
    public boolean isCellEditable(EventObject arg0) {
        return true;
    }
}
class MyTreeCellRenderer extends DefaultTreeCellRenderer {
    private static final long serialVersionUID = 3691823996133806942L;

    JPanel leafPanel;
    JLabel colorIcon;
    PlayButton play; 
    PauseButton pause;
    JLabel name; 

    DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();

    Color backgroundSelectionColor; 
    Color backgroundNonSelectionColor;


    public MyTreeCellRenderer() {
        leafPanel = new JPanel(new FlowLayout());
        colorIcon = new JLabel(UIManager.getIcon("OptionPane.informationIcon"));
        play = new PlayButton();
        pause = new PauseButton();
        name = new JLabel();

        leafPanel.add(colorIcon);
        leafPanel.add(name);
        leafPanel.add(pause);
        leafPanel.add(play);

        backgroundSelectionColor = new Color(200,200,255,50);
        backgroundNonSelectionColor = new Color(0,0,0,0);
    }

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        name.setText((String)((DefaultMutableTreeNode) value).getUserObject());
        if (selected) {
            leafPanel.setBackground(backgroundSelectionColor);
        } else {
            leafPanel.setBackground(backgroundNonSelectionColor);                       
        }
        leafPanel.setEnabled(tree.isEnabled());
        pause.setVisible(!leaf);
        return leafPanel;
    }
}

class PlayButton extends JButton{
    private static final long serialVersionUID = 550654173835539853L;

    Dimension size = new Dimension(140,28);

    public PlayButton() {
        setIcon(UIManager.getIcon("OptionPane.informationIcon"));
        setPressedIcon(UIManager.getIcon("OptionPane.errorIcon"));
        setBackground(new Color(0,0,0,0));
        setBorderPainted(false);
        setPreferredSize(size);
        setMaximumSize(size);
        setMinimumSize(size);
    }
}
class PauseButton extends JButton{
    private static final long serialVersionUID = -5877843953696256070L;

    Dimension size = new Dimension(140,28);

    public PauseButton() {
        setIcon(UIManager.getIcon("OptionPane.warningIcon"));
        setPressedIcon(UIManager.getIcon("OptionPane.questionIcon"));
        setBackground(new Color(0,0,0,0));
        setBorderPainted(false);
        setPreferredSize(size);
        setMaximumSize(size);
        setMinimumSize(size);
    }
}

Even when i erase this Part. and i must click a Cell to enter the Edit Modus i still can get the Effect by leaving the Cell witzh the mouse and go back.

        public void mouseMoved(MouseEvent e) {
            // TODO Auto-generated method stub
            if (tree.getRowForLocation(e.getX(), e.getY()) != -1)
            {
                tree.startEditingAtPath(tree.getPathForLocation(e.getX(), e.getY()));
            } 
        }

I spend already 4 days into this JTree Customizing. But it really confuses me, how i could stop the rendering by entering the Button.

Sven
  • 11
  • 4
  • 2
    use UIManager.getIcon("OptionPane.errorIcon / informationIcon / warningIcon / questionIcon"); instead then to edit your question here – mKorbel Jan 11 '13 at 11:42
  • 2
    Also consider a [simpler example](http://stackoverflow.com/a/4170233/230513). – trashgod Jan 11 '13 at 12:09
  • 2
    might be related or not: the editor implementation is invalid - it _must_ notify its listeners on terminating edits for internal reasons – kleopatra Jan 11 '13 at 12:10
  • @trashgod i tried to do it a bit simpler. But it must maintain some of the things that you make noticing the behaviour like unnessessary icons which are no buttons. – Sven Jan 11 '13 at 13:15
  • @kleopatra i tried to adapt your example from [here](http://stackoverflow.com/questions/8119718/treecelleditor-must-select-cell-to-edit-even-if-shouldselectcell-return-false) but it still looks like bevore with those renderin problems. any other idea? – Sven Jan 11 '13 at 14:25
  • @Sven: You should update your example above to show how you used kleopatra's example. – Catalina Island Jan 11 '13 at 22:34

1 Answers1

1

I don't know how to fix this, but it helps to use invokeLater and setRowHeight().

public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            JFrame frame = new JFrame("Panel");
            ...
            tree.setRowHeight(icon.getIconHeight());
            ...
            frame.setVisible(true);
        }
    });
}
Catalina Island
  • 7,027
  • 2
  • 23
  • 42
  • Hi @Catalina Island i tried to surround the code of my main with the invokeLater and setting the height, but it didnt solve the problem. Did you tried it out and it worked? If thats the case, say where my mistake is by doing what i wrote. Hiding things wont solve my problem because it is just simplyfied here. so changing height and width doestn help. i made the buttons on purpose so large that one can see, that it is the cell which is rendered into the button – Sven Jan 11 '13 at 14:23
  • @Sven: `invokeLater` stopped showing "some Part of the Tree inside the Button," and you should probably do it regardless; `setRowHeight` made the icons less clipped on top and bottom. Honestly, I try to avoid buttons in trees, but I might try kleopatra's way. – Catalina Island Jan 11 '13 at 22:30
  • I think i found something, but i cant say it for sure before next week. On another PC the weird rendering didnt appeared. So i might change the used jdk at work and look if that solves the problem. Actual i cant reproduce it at home. – Sven Jan 15 '13 at 17:20