views:

419

answers:

2

Hi,

regarding to earlier question How to stop editing with DefaultCellEditor when a separate JBtton is pressed and Sun Bug 4724980: JTable: Add API to control what happens to edits when table loses focus.:

With

jtable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

i get my CellEditor to stop editing when table loses focus. And with JButtons I get what I want : the stopCellEditing() is called for my TableCellEditor before the button press action is processed. But if I got a JTree and change selection there, the TreeSelectionListener:valueChanged is called before stopCellEditing()..

Does anybody have some idea how to get this stopCellEditing() being called first or should I just make up some work-around for the issue?

br, Touko

+1  A: 

Hello,

JTree does not have similar client property in Swing. But JXTree, a derived class from JTree, in SwingX does: invokeStopEditing.

If you can't use SwingX, you can always look at the source code of JXTree and see how this StopEditing mecanism works: JXTree SwingX 1.0 API Documentation and Javadoc (go to Source tab)

Specially, starting from line 974, a listener is created to monitor "permanentFocusOwner" property change on the KeyboardFocusManager etc...

najmeddine
A: 

I am not quite sure I understand your question with regards to the TreeSelectionListener and how it relates to the timing stopCellEditing() method being called. Are you creating a custom TreeCellEditor? If so, some more info on the setup of this editor would be useful.

However, you also referenced an earlier item which pertained to cell editing on a JTable, its loss of focus to an outside component, and the affect of this on the editing cell. I have taken that as a hint that you would like a similiar solution for JTree...


As noted, JTree does not implement the handling of the property for "terminateEditOnFocusLost" out of the box. This doesn't mean that you can do it yourself.

Looking at the code for JTable, it is pretty straight forward. A class is put together whose only job is to identify if the JTree still has focus when there is a focus change, and if not, it calls stopEditing() and if that fails it calls cancelEditing(). Here it is, adapted for a tree:

class CellEditorRemover implements PropertyChangeListener {
    KeyboardFocusManager focusManager;
    public CellEditorRemover(KeyboardFocusManager fm) {
        this.focusManager = fm;
    }

    public void propertyChange(PropertyChangeEvent ev) {
        if (!tree.isEditing() || 
          tree.getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) 
        {
          return;
        }

        Component c = focusManager.getPermanentFocusOwner();
        while (c != null) {
            if (c == tree) { // focus remains inside the tree
                return;
            } else if ((c instanceof Window)
                        || (c instanceof Applet && c.getParent() == null)) 
            {
                if (c == SwingUtilities.getRoot(tree)) {
                    if (!tree.getCellEditor().stopCellEditing()) {
                        tree.getCellEditor().cancelCellEditing();
                    }
                }
                break;
            }
            c = c.getParent();
        }
    }
}

You will note that your tree has to be accessible somehow to this class. There are a couple setup calls to perform to make this work:

tree.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
KeyboardFocusManager fm = 
                KeyboardFocusManager.getCurrentKeyboardFocusManager();
editorRemover = new CellEditorRemover(fm);
fm.addPropertyChangeListener("permanentFocusOwner", editorRemover);

This should have the added benefit of making your JTree behave the same way that your JTable behaves when you press a JButton.

akf