JDK-4528436 : Broken focusHandling when using editable ComboBoxes as cellEditor in JTable
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_95
  • CPU: x86
  • Submitted: 2001-11-16
  • Updated: 2001-11-16
  • Resolved: 2001-11-16
Related Reports
Duplicate :  
Relates :  
Relates :  
Description

Name: gm110360			Date: 11/16/2001


java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)


There are several issues (merlin beta3) (use the attached sample
to reproduce):


A: regarding termination of edit

1. when tabbing out of an editing combo (caret blinking in
its JTextField, does accept key input) focus is transferred to
the next component _outside_ the table. In the example that's the
button if the scrollbar is not visible, it's the ScrollBar if visible
(IMO that's another bug: scrollbars should _never_ be focusOwners).

2. same happens when hitting enter


B: regarding starting of edit


The little scheme below shows what happens if you try to
start an edit in a cell with an editable combo (the cell
is the anchor). First column is what to do, second/third columns
are with surrenderFocusOnKeystroke set to off/on, respectively.
Content of these show where the focus is after the user
gesture in column 1:

Input	| surrender off | surrender on
------------------------------------
F2	| combo		| combo
keytype | no effect	| combo
click	| textField	| textfield

Subsequent key types are received by the combo only if the
editor's textfield has the focus, that is only after a
mouseClick. If the combo has the focus (you see the editor
appear, focus seems to be on the button) the textfield does
not get the input. That's clearly unacceptable: at least F2
should put the editor into a state where it is able to accept
subsequent keystrokes.

The reaction to an arbitrary keytype as edit starter at
least has to be defined/documented somewhere. I tend to
treat is similar to a textfield. Again, just showing
the combo without making it accesible for input is unacceptable.

Greetings
Jeanette

Code:

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

import java.awt.event.*;
import java.awt.*;
import java.beans.*;
//import de.kleopatra.support.debugon.*;

/**
 *	Trace focus with editable combo as editor
 */
public class ClickCombo {

	protected JFrame frame ;
	// table vars
	protected final int ROWS = 15;
	protected final int COLUMNS = 3;
	protected DefaultTableModel model;
	protected JTable table;
	
	
	public ClickCombo() {
		frame = new JFrame("ClickCombo");
		frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
		frame.getContentPane().add(buildMainPanel());
		frame.getContentPane().add(buildButtonPanel(),
BorderLayout.SOUTH);
		frame.pack();
	//	frame.setSize(300, 200);
		frame.show();
		installFocusTracer();
	}

//---------------------------tracing focus

  protected void installFocusTracer() {
  	KeyboardFocusManager focusManager = KeyboardFocusManager.
  		getCurrentKeyboardFocusManager();
  	new FocusOwnerTracer(focusManager);
  }
  
  public class FocusOwnerTracer implements PropertyChangeListener {
		public static final String FOCUS_OWNER_PROPERTY = "focusOwner";
		protected KeyboardFocusManager focusManager;
		
		public FocusOwnerTracer(KeyboardFocusManager focusManager) {
			this.focusManager = focusManager;
			startListening();
		}
		
		public void startListening() {
			if (focusManager != null) {
				
focusManager.addPropertyChangeListener(FOCUS_OWNER_PROPERTY, this);
			}
		}
		
		public void stopListening() {
			if (focusManager != null) {
				
focusManager.removePropertyChangeListener(FOCUS_OWNER_PROPERTY, this);
			}
		}
		
		public void propertyChange(PropertyChangeEvent e) {
			Component oldOwner = (Component) e.getOldValue();
			Component newOwner = (Component) e.getNewValue();
			ebug("focusOwner changed: ", "");
			debugClass("  old: ", oldOwner);
			debugClass("  new: ", newOwner);
		}
		
		protected void debugClass(String msg, Object o) {
			ebug(msg, o != null ? o.getClass() : null);
		}
	}

//---------------------------helper
	
	protected void ebug(String text, Object o) {
		System.out.println(text + o);
	}
	
//---------------------------init ui
	 	
	protected JComponent buildMainPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		initTable();
		JScrollPane scroll = new JScrollPane(table);
		panel.add(scroll);
		return panel;
	}
	
	protected void initTable() {
		table = createTable(ROWS, COLUMNS);
		model = (DefaultTableModel) table.getModel();
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		initComboEditor(0, true);
	}

	protected void initComboEditor(int col, boolean editable) {
		String[] list = { "one", "two", "three", "four", "five", "six"
};
		JComboBox box = new JComboBox(list);
		// trying to properly get key input if table surrenders focus
/*		 {
			public void requestFocus() {
				ebug("Combo: request focus ","");
				if (isEditable()) {
					
getEditor().getEditorComponent().requestFocus();
				} else {
					super.requestFocus();
				}
			}
		};
*/
		box.setEditable(editable);
	//	setBoxVerifier((box));
		TableCellEditor editor = new DefaultCellEditor(box);
		setColumnEditorAt(editor, col);
	}

	protected void setColumnEditorAt(TableCellEditor editor, int col) {
		table.getColumnModel().getColumn(col).setCellEditor(editor);
	}
		
	protected JComponent buildButtonPanel() {
		JPanel panel = new JPanel();
		final JButton button = new JButton("surrender off");
		button.setMnemonic('s');
		frame.getRootPane().setDefaultButton(button);
		ActionListener action = new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				boolean surrender =
!table.getSurrendersFocusOnKeystroke();
				table.setSurrendersFocusOnKeystroke(surrender);
				if (surrender) {
					button.setText("surrender on");
				} else {
					button.setText("surrender off");
				}
			}
		};
		button.addActionListener(action);
		panel.add(button);
		return panel;
	}
	
//---------------------------factory methods

	protected JTable createTable(int r, int c) {
		JTable table= new JTable(r, c);
		return table;
	}

//---------------------------Main

	public static void main(String[] args) {
//		LFSwitcher.windowsLF();
		new ClickCombo();
	}
}
(Review ID: 135159) 
======================================================================

Comments
WORK AROUND Name: gm110360 Date: 11/16/2001 Workarounds: A: In the old days a common hack was to comboBox.setNextFocusableComponent(table) to force the focus back into the table. Maybe the equivalent in the new focus architecture does as well (did not try) B: overwrite the combo's requestFocus to force it onto the textfield if editable and setting surrender focus to on does the trick (did not check for side effects) ======================================================================
11-06-2004

EVALUATION The first problem, i.e., tab transfers focus out of table, is coverd by rfe 4307147. The second problem, i.e., JComboBox not editable unless MouseClick, is covered by bug 4109871. ###@###.### 2001-11-16 I have heard from the submitter who says that the first problem is unrelated to RFE 4307147. I have done a quick investigation and I tend to agree. I have therefore opened a new bug, 4684090 to track the first issue. ###@###.### 2002-05-13
13-05-2002