TreeCellEditor:即使ShouldSelectCell返回false,也必须选择要编辑的单元格

时间:2011-11-14 09:45:39

标签: java swing editor jtree

我需要为我的JTree使用自定义单元格渲染器在每个单元格上添加一些JLabel。然后允许用户单击这些标签,而无需先选择单元格。

所以,我创建了一个Renderer,它返回一个包含DefaultTreeCellRenderer和2个JLabel的JPanel。

    public class TreeNodeRenderer extends DefaultTreeCellRenderer implements TreeCellRenderer
    {
        private JPanel panel1 = new JPanel();
        private JLabel delete = new JLabel("");
        private JLabel upload = new JLabel("");

        public Component getTreeCellRendererComponent(JTree tree, 
                            Object value,
                boolean selected, boolean expanded, boolean leaf, int row,
                boolean hasFocus) 
        {   
            //
            // DELETE label
            //
            delete.setName("delete");
            delete.setIcon(new ImageIcon("Data/trash.png"));

            //
            // UPLOAD label
            //
            upload.setName("upload");
            upload.setIcon(new ImageIcon("Data/app_up.png"));


            DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
            Color backgroundSelectionColor = defaultRenderer.getBackgroundSelectionColor();
            Color backgroundNonSelectionColor = defaultRenderer.getBackgroundNonSelectionColor();

            if(selected)
                panel1.setBackground(backgroundSelectionColor);
            else
                panel1.setBackground(backgroundNonSelectionColor);


            component = (DefaultTreeCellRenderer) super.getTreeCellRendererComponent(tree,
                    value, selected, expanded, leaf, row, hasFocus);

            panel1.add(component);
            panel1.add(delete);
            panel1.add(upload);

            return panel1;
        }
    }

然后我创建了编辑器,允许用户通过MouseListener点击这些标签。除了用户必须在点击标签之前选择单元格外,一切运行良好。 我试图用“ShouldSelectCell”方法返回“false”,但它不起作用。

有人知道为什么吗?

编辑:

public class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor
{
    private TreeNodeRenderer renderer;

    public TreeNodeEditor(TreeNodeRenderer treeRenderer)
    {
        this.renderer = treeRenderer;

    //change the cursor when it's over a label  renderer.getDeleteButton().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    renderer.getUploadButton().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));       renderer.getDownloadButton().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

                 //add labels' mouse listeners 
        addLabelMouseListener(renderer.getDeleteButton());
        addLabelMouseListener(renderer.getUploadButton());
    }

    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row)
    {
        ...

        return renderer.getTreeCellRendererComponent(
                tree, value, isSelected,
                expanded, leaf, row, true);
    }

    public boolean isCellEditable(EventObject anEvent) 
    {
        return true;
    }

    public boolean shouldSelectCell(EventObject anEvent) 
    {
        return false;
    }


    public boolean stopCellEditing() 
    {
        return super.stopCellEditing();
    }

    public void cancelCellEditing() 
    {
        super.cancelCellEditing();
    }

    public void addCellEditorListener(CellEditorListener l)
    {
        super.addCellEditorListener(l);
    }

    public void removeCellEditorListener(CellEditorListener l) 
    {
        super.removeCellEditorListener(l);
    }

    public Object getCellEditorValue() 
    {
        return null;
    }
}

编辑 - 这是一个SSCCE:

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventObject;

import javax.swing.AbstractCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.CellEditorListener;
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;



public class EditJTreeCell extends JFrame
{
    /**
     * 
     */
    private static final long serialVersionUID = 4745146614430249610L;

    private JTree tree;
    private DefaultTreeModel treeModel;
    private DefaultMutableTreeNode root;

    public EditJTreeCell()
    {
        super("Sample");
        root = new DefaultMutableTreeNode("Root folder");
        treeModel = new DefaultTreeModel(root);
        tree = new JTree(treeModel);

        TreeNodeRenderer renderer = new TreeNodeRenderer();
        tree.setCellRenderer(renderer);
        tree.setCellEditor(new TreeNodeEditor());
        tree.setEditable(true);

        //tree creation
        DefaultMutableTreeNode folder = new DefaultMutableTreeNode("folder1");
        DefaultMutableTreeNode file = new DefaultMutableTreeNode("file1");
        folder.add(file);
        file = new DefaultMutableTreeNode("file2");
        folder.add(file);
        root.add(folder);
        folder = new DefaultMutableTreeNode("folder2");
        file = new DefaultMutableTreeNode("file1");
        folder.add(file);
        file = new DefaultMutableTreeNode("file2");
        folder.add(file);
        file = new DefaultMutableTreeNode("file3");
        folder.add(file);
        root.add(folder);

        this.setSize(400, 800);
        this.add(tree);
        this.setVisible(true);
    }

    public static void main(String[] args) 
    {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        new EditJTreeCell();
    }
}

class TreeNodeRenderer extends DefaultTreeCellRenderer implements TreeCellRenderer
{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private JPanel panel1 = new JPanel();
    private JLabel delete = new JLabel("DELETE");
    private JLabel upload = new JLabel("UPLOAD");

    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean selected, boolean expanded, boolean leaf, int row,
            boolean hasFocus) 
    {   
        //
        // DELETE label
        //
        delete.setName("delete");
        delete.setIcon(new ImageIcon("trash.png"));
        //addLabelMouseListener(delete);
        //
        // UPLOAD label
        //
        upload.setName("upload");
        upload.setIcon(new ImageIcon("app_up.png"));
        //addLabelMouseListener(upload);


        DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
        Color backgroundSelectionColor = defaultRenderer.getBackgroundSelectionColor();
        Color backgroundNonSelectionColor = defaultRenderer.getBackgroundNonSelectionColor();

        DefaultTreeCellRenderer component = (DefaultTreeCellRenderer) super.getTreeCellRendererComponent(tree,
                value, selected, expanded, leaf, row, hasFocus);

        if(selected)
        {   
            panel1.setBackground(backgroundSelectionColor);
        }
        else
        {
            panel1.setBackground(backgroundNonSelectionColor);
        }

        panel1.add(component);
        panel1.add(delete);
        panel1.add(upload);

        return panel1;
    }
}

class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor
{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private JLabel button1;
    private JLabel button2;
    private JPanel panel1;
    private DefaultMutableTreeNode node = null;
    private DefaultTreeCellRenderer defaultRenderer;


    public TreeNodeEditor()
    {
        super();
        panel1 = new JPanel();
        defaultRenderer = new DefaultTreeCellRenderer();
        button1 = new JLabel("DELETE");
        button1.setOpaque(true);
        button1.setIcon(new ImageIcon("trash.png"));
        button1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        button1.addMouseListener(new MouseListener() 
        {
            public void mouseClicked(MouseEvent arg0) {
                System.out.println("Delete clicked");
            }
            public void mouseEntered(MouseEvent arg0) {}
            public void mouseExited(MouseEvent arg0) {}
            public void mousePressed(MouseEvent arg0) {}
            public void mouseReleased(MouseEvent arg0) {}

        });
        button2 = new JLabel("UPLOAD");
        button2.setOpaque(true);
        button2.setIcon(new ImageIcon("app_up.png"));
        button2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        button2.addMouseListener(new MouseListener() 
        {
            public void mouseClicked(MouseEvent arg0) {
                System.out.println("Upload clicked");
            }
            public void mouseEntered(MouseEvent arg0) {}
            public void mouseExited(MouseEvent arg0) {}
            public void mousePressed(MouseEvent arg0) {}
            public void mouseReleased(MouseEvent arg0) {}

        });
    }


    public Component getTreeCellEditorComponent(JTree tree, Object value, 
            boolean isSelected, boolean expanded, boolean leaf, int row)
    {
        //in order to do some actions on a node
        if(value instanceof DefaultMutableTreeNode)
        {
            node = (DefaultMutableTreeNode) value;
        }


         defaultRenderer.getTreeCellRendererComponent(tree,
                    value, isSelected, expanded, leaf, row, true);

        panel1.add(defaultRenderer);
        panel1.add(button1);
        panel1.add(button2);
        return panel1;
    }

    public boolean isCellEditable(EventObject anEvent) 
    {
        return true;
    }

    public boolean shouldSelectCell(EventObject anEvent) 
    {
        return false;
    }


    public boolean stopCellEditing() 
    {
        return super.stopCellEditing();
    }

    public void cancelCellEditing() 
    {
        super.cancelCellEditing();
    }

    public void addCellEditorListener(CellEditorListener l)
    {
        super.addCellEditorListener(l);
    }

    public void removeCellEditorListener(CellEditorListener l) 
    {
        super.removeCellEditorListener(l);
    }

    public Object getCellEditorValue() 
    {
        return null;
    }
}

3 个答案:

答案 0 :(得分:5)

开始编辑mouseEnter是一个有效的解决方案: - )

另一方面,你的编辑器不是一个有效的实现:如果编辑因内部事件而终止(如点击任何按钮,则无法通知其监听器)下面是如何操作的示例实现目标并拥有有效的实施

几条评论:

  • 如果你想要一个像按钮这样的东西..使用一个按钮:否则用户可能会感到困惑
  • 在编辑器中
  • ,根据需要为按钮设置操作
  • 在构造函数中执行所有基本面板配置(如添加其子项)
  • 开始编辑/检测单击了哪个按钮,重新调度在shouldSelect中收到的事件。在SwingUtilities.invokeLater中执行此操作以确保任何内部挂起的事件(在树中)已准备就绪
  • 不要更改编辑器中的树节点:a)这些更改将无法通知模型b)将被树的默认编辑终止行为否决。 DefaultTreeTable将使用editorValue重置树的userObject,这是在valueForPathChanged中完成的:实现自定义行为,在模型中覆盖该方法

代码:

static class TreeNodeEditor extends AbstractCellEditor implements TreeCellEditor {
    private static final long serialVersionUID = 1L;
    private JButton button1;
    private JButton button2;
    private JPanel panel1;
    // JW: do not modify the node inside the editor 
    //        private DefaultMutableTreeNode node = null;
    private DefaultTreeCellRenderer defaultRenderer;

    private Object editorValue;

    public TreeNodeEditor() {
        super();
        panel1 = new JPanel();
        defaultRenderer = new DefaultTreeCellRenderer();
        button1 = new JButton("DELETE");
        button1.setOpaque(true);
        button1.setIcon(new ImageIcon("trash.png"));
        button1.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        button2 = new JButton("UPLOAD");
        button2.setOpaque(true);
        button2.setIcon(new ImageIcon("app_up.png"));
        button2.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        button2.setAction(createAction("upload", "UPLOAD"));
        button1.setAction(createAction("delete", "DELETE"));
        panel1.add(defaultRenderer);
        panel1.add(button1);
        panel1.add(button2);
    }

    private Action createAction(final String actionCommand, String display) {
        Action action = new AbstractAction(display) {

            @Override
            public void actionPerformed(ActionEvent e) {
                stopEditing(actionCommand);
            }

        };
        return action;

    }
    /**
     * @param actionCommand
     */
    protected void stopEditing(String actionCommand) {
        editorValue = actionCommand;
        stopCellEditing();
    }

    @Override
    public Component getTreeCellEditorComponent(JTree tree, Object value,
            boolean isSelected, boolean expanded, boolean leaf, int row) {
        // in order to do some actions on a node
        //            if (value instanceof DefaultMutableTreeNode) {
        //                node = (DefaultMutableTreeNode) value;
        //            }

        defaultRenderer.getTreeCellRendererComponent(tree, value,
                isSelected, expanded, leaf, row, true);

        return panel1;
    }

    /**
     * 
     */
    private void reset() {
        editorValue = null;
    }

    /**
     * At this point in time the component is added to the tree (not documented!) but
     * tree's internal cleanup might not yet be ready
     */ 
    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        reset();
        if (anEvent instanceof MouseEvent) {
            redirect((MouseEvent) anEvent);
        }
        return false;
    }

    private void redirect(final MouseEvent anEvent) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                MouseEvent ev = SwingUtilities.convertMouseEvent(anEvent.getComponent(), anEvent, panel1);
                panel1.dispatchEvent(ev);

            }
        });
    }

    @Override
    public Object getCellEditorValue() {
        return editorValue;
    }
}

答案 1 :(得分:1)

最后,我使用MouseMotionListener和方法myTree.startEditingAtPath(path)解决了我的问题。当光标在节点上时,节点现在处于编辑模式。

tree.addMouseMotionListener(new MouseMotionListener() {
            public void mouseMoved(MouseEvent e) 
            {
                if (tree.getRowForLocation(e.getX(), e.getY()) != -1)
                {
                    tree.startEditingAtPath(tree.getPathForLocation(e.getX(), e.getY()));
                }               
            }
            public void mouseDragged(MouseEvent e) {}
        });

但是,如果有人有更好的想法,请告诉我。

答案 2 :(得分:0)

我认为你需要在treeNodeRenderer本身中添加鼠标监听器。只有在您进入“编辑模式”并且编辑器被放入单元格后才会添加鼠标滑块。