Ha a JTable cellához egy egyedi, JPanel-re épített CellEditor komponenst rendelek, amely tartalmaz egy szerkeszthető szöveges mezőt is, a billentyűzetet használva nem lesz szerkeszthető a szöveges mező, mert alapesetben a JPanel kapja meg a fókuszt, nem pedig a szöveges mező.
A megoldást Sanhtosh Kumar találta meg és írta le blogjában, az eredeti cikk itt érhető el. Hálás köszönet érte! Ez egy nagyon bonyolult probléma volt.
Út a megoldás felé
Kumar először azt vizsgálta, hogy a DefaultTableCellEditor használata esetén a KeyEvent-ek hogyan kerülnek továbbításra a JTextField objektumnak, és a következő stack trace-t rögzítette:
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1082)
at santhosh.CustomEditorDemo$1.insertUpdate(CustomEditorDemo.java:26)
at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:184)
at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:749)
at javax.swing.text.AbstractDocument.insertString(AbstractDocument.java:706)
at javax.swing.text.PlainDocument.insertString(PlainDocument.java:114)
at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:668)
at javax.swing.text.JTextComponent.replaceSelection(JTextComponent.java:1072)
at apple.laf.AquaLookAndFeel$AquaKeyTypedAction.actionPerformed(AquaLookAndFeel.java:1575)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1535)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2470)
at javax.swing.JTable.processKeyBinding(JTable.java:3330)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2516)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2433)
at java.awt.Component.processEvent(Component.java:4975)
at java.awt.Container.processEvent(Container.java:1613)
at java.awt.Component.dispatchEventImpl(Component.java:3681)
at java.awt.Container.dispatchEventImpl(Container.java:1671)
at java.awt.Component.dispatchEvent(Component.java:3543)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1713)
Ami a stack trace-ből kiderült
- A felhasználó a kurzorbillentyűkkel a szerkeszteni kívánt cellára navigál.
- Ilyenkor a fókusz JTable objektumé, ezért ő kapja a bellentyűeseményeket.
- A JTable felülírja a processKeyBinding(...) metódust (lásd a félkövér sort a stack trace-ben)
-
A felülírt processKeyBinding(...) metódus a következő módon befolyásolja a működést:
- Megkérdezi a TableCellEditor-t, hogy a kapott KeyEvent aktiválhatja-e a CellEditor-t.
- Ha igen, akkor aktiválja a CellEditor-t és továbbítja a KeyEvent eseményt az aktuális CellEditor komponensnek.
Az ellesett trükk
A lényeg az események továbbításban rejlik. Kumar a következő képpen írta felül a JTable processKeyBinding(...) metódusát:
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed){
InputMap map = editorComp.getInputMap(condition);
ActionMap am = editorComp.getActionMap();
if(map!=null && am!=null && isEnabled()){
Object binding = map.get(ks);
Action action = (binding==null) ? null : am.get(binding);
if(action!=null){
return SwingUtilities.notifyAction(action, ks, e, editorComp, e.getModifiers());
}
}
return false;
}
A fenti kód megoldotta a problémát: bármely billentyűt leütve a kijelölt táblázatcellába bekerül a begépelt karakter, viszont a cellaszerkesztő még mindig nem kapta meg a fókuszt, ezért még a következő metódust is felülírta:
public void addNotify(){
super.addNotify();
editorComp.requestFocus();
}
Kapcsolódó cikkek
Az eredeti cikk
http://jroller.com/santhosh/entry/keyboard_handling_in_tablecelleditor