[[:oktatas:programozás:java|< Java]] ====== Java eseménykezelés ====== * **Szerző:** Sallai András * Copyright (c) 2011, Sallai András * Szerkesztve: 2011, 2013, 2014, 2015, 2019 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC BY-SA 4.0]] * Web: https://szit.hu ===== Bevezetés ===== A Java grafikus felületein többféle esemény, többféle módon kezelhető. Az eseménykezeléshez használhatunk interfészeket és/vagy osztályokat. Az osztályokat használhatjuk "névtelenül". ===== Eseménykezelés példa ===== A következő példában ablak eseményeire reagálunk. Két eseménykezelőt használunk; egyik a **WindowsListener**, a másik az **ActionListener**. A WindowListener és az ActionListener is egy interfész, amit a implementálunk a Esemeny osztályunkon. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Esemeny extends JFrame implements WindowListener, ActionListener { JTextField edit; JButton gomb; private int szamlalo = 0; public static void main(String[] args) { esemeny ablak = new esemeny("Az első ablakom"); ablak.setSize(350,100); ablak.setVisible(true); } public Esemeny(String title) { super(title); setLayout(new FlowLayout()); edit = new JTextField(20); gomb = new JButton("Kattints ide"); add(gomb); add(edit); addWindowListener(this); gomb.addActionListener(this); } public void actionPerformed(ActionEvent e) { szamlalo++; edit.setText("A gomb le lett nyomva " + szamlalo + " -szer"); } public void windowClosing(WindowEvent e) { dispose(); System.exit(0); } public void windowOpened(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowClosed(WindowEvent e) {} } A nyelv megköveteli egy interfaceben deklarált függvények definiálását használatkor. Ezért a következő függvényeket akkor is le kell írnunk, ha nem használjuk azokat: public void windowOpened(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} public void windowClosed(WindowEvent e) {} Ilyenkor a függvény törzsét üresem hagyom, csak egy {} karakterek szerepelnek. ===== Eseményfigyelők ===== Számtalan eseménykezelő áll rendelkezésünkre a java.awt és a javax.swing csomagban is. ==== AWT ==== ^ Eseményfigyelő ^ Figyelő metódus ^ Regisztrálva a következő komponenseknél ^ | ActionListener | actionPerformed() | AbstractButton, Button, ButtonModel, ComboBoxEditor, JComboBox, JFileChooser, JTextField, List, MenuItem, TextField, Timer | | AdjustmentListener | adjustmentValueChanged() | Adjustable, JScrollBar, Scrollbar | | ComponentListener | componentHidden(), componentMoved(), componentResized(), componentShown() | Component | | ContainerListener | componentAdded(), componentRemoved() | Container | | FocusListener | focusGained(), focusLost() | Component | | ItemListener | itemStateChanged() | AbstractButton, ButtonModel, Checkbox, CheckboxMenuItem, Choice, ItemSelectable, JComboBox, List | | KeyListener | keyPressed(), keyReleased(), keyTyped() | Component | | MouseListener | mouseClicked(), mouseEntered(), mouseExited(), mousePressed(), mouseReleased() | Component | | MouseMotionListener | mouseDragged(), mouseMoved() | Component | | TextListener | textValueChanged() | TextComponent | | WindowListener | windowActivated(), windowClosed(), windowClosing(), windowDeactivated(), windowDeiconified(), windowIconified(), windowOpened() | Window | ==== Swing ==== ^ Eseményfigyelő ^ Figyelő metódus ^ Regisztrálva a következő komponenseknél ^ | AncestorListener | ancestorAdded(), ancestorMoved(), ancestorRemoved() | Action, JComponent | | CaretListener | caretUpdate() | JTextComponent | | CellEditorListener | editingCanceled(), editingStopped() | CellEditor, | | ChangeListener | stateChanged() | AbstractButton, BoundedRangeModel, ButtonModel, JProgressBar, JSlider, JTabbedPane, JViewport, MenuSelectionManager, SingleSelectionModel | | HyperlinkListener | hyperlinkUpdate() | JEditorPane | | InternalFrameListener | internalFrame- Activated (), internalFrameClosed(), internalFrameClosing()internalFrame- Deactivated(), internalFrame- Deiconified(), internalFrame- Iconified()internalFrameOpened() | | | ListDataListener | contentsChanged(), intervalAdded(), intervalRemoved() | AbstractListModel, ListModel | | ListSelectionListener | valueChanged() | JList, ListSelectionModel | | MenuDragMouseListener | menuDragMouseDragged(), menuDragMouseEntered(), menuDragMouseExited(), menuDragMouseReleased() | JMenuItem | | MenuKeyListener | menuKeyPressed(), menuKeyReleased(), menuKeyTyped() | JMenuItem | | MenuListener | menuCanceled(), menuDeselected(), menuSelected() | JMenu | | PopupMenuListener | popupMenuCanceled(), | JPopupMenu | | | popupMenuWillBecome- | | | | Invisible(), | | | | popupMenuWillBecome- | | | | Visible() | | | TreeExpansionListener | treeCollapsed(), treeExpanded() | JTree | | TreeSelectionListener | valueChanged() | JTree | | TreeWillExpandListener | treeWillCollapse(), treeWillExpand() | JTree | | java.beans.PropertyChangeListener | propertyChange() | Action, JComponent, UIDefaults, UIManager | | java.beans.VetoableChangeListener | vetoableChange() | JComponent | ===== Billentyűzet figyelése ===== Háromféle esemény figyelhetünk: * keyType - karakterként azonosítható billentyű lett leütve * keyPressed - egy billentyűt lenyomtak * keyReleased - egy billentyűt felengedtek Többek között, a kurzormozgatók és a funkcióbillentyűk nem váltanak ki keyType eseményt. A keyPressed és a keyReleased esemény esetén a KeyEvent változóból a billentyűkódja olvasható ki. A keyType esemény esetén az billentyűhöz tartozó karakter lekérdezhető. A következő példában a keyType eseményt kezeljük, majd reagálunk az "a" és a "b" billentyűk leütésére. import java.awt.event.*; import javax.swing.*; class Program extends JFrame implements KeyListener { JFrame ablak; JButton gomb; public static void main(String args[]) { new Program(); } Program() { gomb = new JButton("Teszt"); add(gomb); setBounds(0,20,100,50); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addKeyListener(this); setFocusable(true); //Szükséges a lenyomott billentyű figyeléséhez setVisible(true); } public void keyTyped(KeyEvent e) { char i = e.getKeyChar(); String str = Character.toString(i); if(i == 'a') gomb.setText("a"); if(i == 'b') gomb.setText("b"); } public void keyReleased(KeyEvent e) {} public void keyPressed(KeyEvent e) {} } Vegyük észre, hogy engedélyezni kell az ablakon a fókuszt, ahhoz, hogy billentyűleütéseket tudjunk figyelni. Újabb példa: import java.awt.Frame; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; class Program extends Frame { Program() { addKeyListener(new BillentyuKezeles()); addWindowListener(new AblakKezeles()); setSize(400, 300); setVisible(true); } class BillentyuKezeles implements KeyListener { public void keyPressed(KeyEvent e) { switch(e.getKeyCode()) { case KeyEvent.VK_A : setTitle("a"); break; case KeyEvent.VK_B : setTitle("b"); break; case KeyEvent.VK_C : setTitle("c"); break; case KeyEvent.VK_1 : setTitle("1"); break; case KeyEvent.VK_2 : setTitle("2"); break; } } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } } class AblakKezeles extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } public static void main(String[] args) { new Program(); } } ==== A KeyEvent osztály mezői ==== A KeyEvent osztályban több állandó van definiálva, amelyek megkönnyítik a billentyűkódok vizsgálatát. Az alább táblázatokban a teljesség igénye nélkül találunk néhány állandót. ^ Funkcióbillentyűk ^^ | VK_F1 | VK_F2 | ^ Kurzormozgatók ^^^^^^^^^ | VK_HOME | VK_END | VK_INSERT | VK_LEFT | VK_RIGHT | VK_UP | VK_PAGE_DOWN | VK_PAGE_UP | VK_DOWN | ^ Váltók ^^ | VK_TAB | VK_SHIFT | VK_META | VK_ALT | ^ Numerikus ^^^ | VK_NUMPAD1 | VK_NUMPAD2 | stb.... | ^ Számok ^^^ | VK_1 | VK_2 | stb....| ^ Egyéb ^^^ | VK_SPACE | VK_PAUSE | VK_DELETE | A kontroll billentyű (Ctrl) figyelésére is lehetőségünk van. A KeyEvent objektumon a getExtendedKeyCode() metódus tájékoztat a kontrollbillentyű lenyomásáról. import javax.swing.JFrame; import javax.swing.JPanel; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; import java.awt.Color; class Program01 extends JFrame { JPanel panel; Program01() { addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { OnKeyPressed(e); } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} }); panel = new JPanel(); panel.setBounds(10, 300, 100, 30); panel.setBackground(Color.green); add(panel); setLayout(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500, 400); setVisible(true); } private void OnKeyPressed(KeyEvent e) { System.out.println(e.getExtendedKeyCode()); if(e.getKeyCode() == KeyEvent.VK_ENTER) { System.out.println("Enter"); } if(e.getKeyCode() == KeyEvent.VK_RIGHT) { System.out.println("Jobbra"); } if(e.getKeyCode() == KeyEvent.VK_LEFT) { System.out.println("Balra"); } System.out.println(e.getKeyCode()); } public static void main(String args[]) { new Program01(); } } Egy panel mozgatása, jobbra, balra (indítás Enter): import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.Color; import java.awt.event.KeyListener; import java.awt.event.KeyEvent; import java.awt.Point; class Program01 extends JFrame { JPanel panel; Timer timer; enum TDirection {left, right} TDirection direction = TDirection.left; Program01() { timer = new Timer (10, new ActionListener() { public void actionPerformed(ActionEvent e) { MehetIdozitoActionEvent(e); } }); addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { OnKeyPressed(e); } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} }); panel = new JPanel(); panel.setBounds(10, 300, 100, 30); panel.setBackground(Color.green); add(panel); setLayout(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500, 400); setVisible(true); } private void MehetIdozitoActionEvent(ActionEvent e) { int x = panel.getX(); int y = panel.getY(); if(direction == TDirection.left) { if(x>0) x = x - 3; } else { int width = getWidth(); int a = width - panel.getWidth(); if(x ==== X-dik példa ==== import javax.swing.JFrame; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; class Program02 extends JFrame { Program02() { setFocusable(true); addKeyListener(new TAdapter()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 300); setVisible(true); } public static void main(String args[]) { new Program02(); } public static void balra() { System.out.println("balra"); } class TAdapter extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { int keycode = e.getKeyCode(); if (keycode == 'p' || keycode == 'P') { System.out.println("Kis p vagy nagy P"); } switch (keycode) { case KeyEvent.VK_LEFT: balra(); break; case KeyEvent.VK_RIGHT: System.out.println("jobbra"); break; case KeyEvent.VK_DOWN: System.out.println("le"); break; case KeyEvent.VK_UP: System.out.println("fel"); break; case KeyEvent.VK_SPACE: System.out.println("Szóköz"); break; case KeyEvent.VK_A : System.out.println("a"); break; } } } } ==== Karakter lekérdezése ==== public void keyTyped(KeyEvent event) { System.out.println(event.getKeyChar()); } ===== Húzás ===== A MouseMotionAdapter lehetővé teszi egy komponens húzását. A következő példában egy szöveget húzgálhatunk az ablakon. import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseEvent; import java.awt.Component; public class Program01 extends JFrame { JPanel panel = new JPanel(); JLabel cimke = new JLabel(); Program01() { cimke.setText("Jóska"); cimke.setLocation(100, 10); cimke.setSize(50, 15); cimke.addMouseMotionListener(new Cimke_Dragged()); panel.add(cimke); add(panel); panel.setLayout(null); setSize(400, 300); setVisible(true); } public void rePaint() { repaint(); } class Cimke_Dragged extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { Component c = e.getComponent(); c.setLocation( c.getX()+e.getX(), c.getY()+e.getY()); rePaint(); } } public static void main(String args[]) { new Program01(); } } ===== ActionCommand ===== Az akcióparancsok az események kezelésének egy újabb módja. A következő példában az ActionListener interfész mellett használjuk az akcióparancsot. import javax.swing.JFrame; import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.FlowLayout; class Program01 extends JFrame implements ActionListener { JButton okButton = new JButton("Ok"); JButton cancelButton = new JButton("Mégsem"); String OK_COMMAND = "ok"; String CANCEL_COMMAND = "cancel"; Program01() { okButton.addActionListener(this); okButton.setActionCommand(OK_COMMAND); cancelButton.addActionListener(this); cancelButton.setActionCommand(CANCEL_COMMAND); add(okButton); add(cancelButton); setLayout(new FlowLayout()); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 300); setVisible(true); } public static void main(String args[]) { new Program01(); } public void actionPerformed(ActionEvent e){ if(e.getActionCommand().equals(OK_COMMAND)){ setTitle("Ok"); }else if(e.getActionCommand().equals(CANCEL_COMMAND)){ setTitle("Nem jó"); } } } ===== Ablakesemények kezelése ===== A grafikus felületen megjelenő ablakok az operációs rendszer alapértelmezett akcióit váltják ki az egyes eseményekre. Ha szeretnénk ebbe beleszólni, akkor a WindowListenerre van szükségünk. import javax.swing.JFrame; import java.awt.event.WindowListener; import java.awt.event.WindowEvent; class Program01 extends JFrame { Program01() { addWindowListener(new WindowListener(){ public void windowDeactivated(WindowEvent event) {} public void windowActivated(WindowEvent event) {} public void windowDeiconified(WindowEvent event) {} public void windowIconified(WindowEvent event) {} public void windowClosed(WindowEvent event) {} public void windowClosing(WindowEvent event) {} public void windowOpened(WindowEvent event) {} }); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 300); centerWindow(this); setVisible(true); } public static void centerWindow(java.awt.Window frame) { java.awt.Dimension dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2); int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2); frame.setLocation(x, y); } public static void main(String[] args) { new Program01(); } } A példában persze egyik metódus sincs megvalósítva. Válasszuk ki a kívánt eseményt és a {} között írjuk meg a metódus törzsét. Például: public void windowClosing(WindowEvent event) { System.exit(0); } ===== Action ===== Eseménykezelés az Action és AbstractAction osztályokkal. import javax.swing.JFrame; import javax.swing.Action; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import java.awt.event.ActionEvent; import javax.swing.JButton; class Program01 extends JFrame { Action leftAction = new LeftAction("Felirat"); JButton btnTest = new JButton(leftAction); Program01() { add(btnTest); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 300); centerWindow(this); setVisible(true); } public static void centerWindow(java.awt.Window frame) { java.awt.Dimension dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); int x = (int)((dimension.getWidth() - frame.getWidth()) / 2); int y = (int)((dimension.getHeight() - frame.getHeight()) / 2); frame.setLocation(x, y); } public static void main(String[]args) { new Program01(); } class LeftAction extends AbstractAction { public LeftAction(String text) { super(text); } public void actionPerformed(ActionEvent e) { setTitle("vmi"); } } } ===== Gombok tömbben ===== import javax.swing.JFrame; import javax.swing.JButton; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; class Gombok extends JFrame implements ActionListener { JButton[] gombok = new JButton[64]; GridLayout gridLayout = new GridLayout(8, 8); public Gombok() { Integer i = 0; for(JButton gomb : gombok) { gomb = new JButton(); gomb.addActionListener(this); i++; gomb.setActionCommand(i.toString()); add(gomb); } setLayout(gridLayout); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(400, 400); setVisible(true); } public void actionPerformed(ActionEvent event) { String cmd = event.getActionCommand(); System.out.println(cmd); switch(cmd) { case "1" : System.out.println("első"); break; case "2" : System.out.println("második"); break; default: System.out.println("más"); } } public static void main(String[] args) { new Gombok(); } } ===== Külső Linkek ===== * http://docs.oracle.com/javase/tutorial/uiswing/events/index.html * http://docstore.mik.ua/orelly/java-ent/jfc/ch02_06.htm * http://www.wilsonmar.com/1javaawt.htm * http://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html * http://zetcode.com/tutorials/javaswingtutorial/draganddrop/ * http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html