TreeCellEditor: must select cell to edit even if ShouldSelectCell return false

∥☆過路亽.° 提交于 2019-12-01 01:46:57

starting an edit on mouseEnter is a valid solution :-)

Your editor, on the other hand is not a valid implementation: it fails on not notifying its listener if the edit is terminated due to internal events (as f.i. clicking on any of the buttons) Below is an example of how-to achieve both your goal and have a valid implementation

a couple of comments:

  • if you want something like a button .. use a button: otherwise users might be confused
  • in your editor, set an action to the buttons as needed
  • do all basic panel config (like adding its children) in the constructor)
  • to start editing/detect which button is clicked, re-dispatch the event received in shouldSelect. Do it in a SwingUtilities.invokeLater to make sure any internally pending events (in the tree) are ready
  • do not change the tree node inside the editor: a) those changes will fail to notify the model b) will be overruled by the tree's default editing termination behaviour. DefaultTreeTable will reset the userObject of the tree with editorValue, that's done in valueForPathChanged: to implement custom behaviour, override that method in the model

in code:

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;
    }
}
bldcoco

Finally, i solved my problem with a MouseMotionListener and the method : myTree.startEditingAtPath(path). A node is now in editing mode when the cursor is over it.

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) {}
        });

However, if someone has a better idea, please let me know.

I think you need to add the mouse listeners inside the treeNodeRenderer itself. It is likely that the mouselistener is only getting added after you enter 'edit mode' and editor is put into the cell.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!