JPanel alapú CellEditor esetén a szöveges mező nem kap fókuszt

    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

    1. A felhasználó a kurzorbillentyűkkel a szerkeszteni kívánt cellára navigál.
    2. Ilyenkor a fókusz JTable objektumé, ezért ő kapja a bellentyűeseményeket.
    3. A JTable felülírja a processKeyBinding(...) metódust (lásd a félkövér sort a stack trace-ben)
    4. A felülírt processKeyBinding(...) metódus a következő módon befolyásolja a működést:
      1. Megkérdezi a TableCellEditor-t, hogy a kapott KeyEvent aktiválhatja-e a CellEditor-t.
      2. 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

    Tags: ,