2012. március 9., péntek

Billentyűkezelés JFrame-ben

Biztos sok Java-s programozótársam gondolkodott már azon, hogy lehetne Swing-es JFrame ablakban lekezelni a billentyűket, ha a KeyListener-es megoldás nem működik. Mert van olyan, hogy az nem működik: például a form-hoz hiába adod hozzá, nem csinál semmit, pláne ha van legalább egy gombod vagy beviteli meződ - mert akkor azok valamelyike lesz fókuszban és kapja el a billentyűleütés eseményét. Játékot ezzel nem lehet írni.

Létezik azonban egy globális billentyűzetkezelő mechanizmus, amihez hozzá lehet adni egy saját osztályt, aminek a metódusa szépen meghívódik minden billentyűzet esemény bekövetkezésekor, amíg a program fut, bármelyik objektum vagy form is legyen fókuszban. A KeyEventDispatcher interfészt kell megvalósítani, majd átadni az objektumot a KeyboardFocusManagernek.

Én minden ablakomba tettem egy saját dispatcher-t, de mivel ezek globálisan kapják el a billentyűeseményeket, írtam a metódusukba egy elágazást, hogy csak akkor kezelje le az eseményt, ha az adott ablak van fókuszban.

Példa:
public class MyWindow extends JFrame implements KeyEventDispatcher {

    public MyWindow() {
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new MyKeyEventDispatcher());  
    }

    @Override
    private boolean dispatchKeyEvent(KeyEvent e) {     
        if (!MyWindow.this.isFocused()) return false;

        if (e.getID() == KeyEvent.KEY_PRESSED) { // lenyomva
            if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                //...
            } // else if ...
        } else if (e.getID() == KeyEvent.KEY_RELEASED) { // felengedve
            // ...
        } else if (e.getID() == KeyEvent.KEY_TYPED) { // gépelve (?)
            // ...
        }
        return false;
    }
}
A RELEASE és TYPE ágakkal én nem nagyon foglalkoztam, nem is igazán tudom mi a különbség a TYPE és a PRESS között, ennek kikísérletezését rátok bízom.