User Tools

Site Tools


swing:events

Events και Event Listeners

Όταν ο χρήστης πατήσει ένα πλήκτρο από το πληκτρολόγιο ή μετακινήσει το ποντίκι, ο window manager στέλνει μία ειδοποίηση (event) που σηματοδοτεί την ενέργεια που έκανε ο χρήστης. Για παράδειγμα, πατώντας με τη βοήεια του ποντικιού (αριστερό click) ένα κουμπί από το γραφικό περιβάλλον, μετακινώντας το ποντίκι πάνω στο ενεργό παράθυρο ή εισάγοντας ένα χαρακτήρα από το πληκτρολόγιο παράγεται ένα event που σηματοδοτεί την αλλαγή που έκανε ο χρήστης.

Ο window manager δημιουργεί events για κάθε απειροελάχιστη μεταβολή της θέσης του ποντικιού ή για το πάτημα ενός κουμπιού από το πληκτρολόγιο. Τα περισσότερα προγράμματα δεν τα ενδιαφέρει το σύνολο των events που παράγονται. Προκειμένου ένα πρόγραμμα να μην “βομβαρδίζεται” με πολλά διαφορετικά events τα οποία του είναι αδιάφορα θα πρέπει να θεσπίσει του δικούς του κανόνες για το ποια events το ενδιαφέρουν. Η θέσπιση των κανόνων αυτών γίνεται μέσα από αντικείμενα τύπου event listeners, τα οποία ακούν σε συγκεκριμένου τύπου events.

Θα πρέπει να τονίσουμε ότι υπάρχουν διαφορετικοί τύποι event για κάθε διαφορετικό τύπο αλληλεπίδρασης του χρήστη με το γραφικό περιβάλλον. Για παράδειγμα, η μετακίνηση του ποντικιού ή το πάτημα ενός κουμπιού από το ποντίκι παράγει ένα MouseEvent ενώ το πάτημα ενός κουμπιού ή η επιλογή ενός menu παράγει ένα ActionEvent. Επομένως, το κάθε πρόγραμμα θα πρέπει να θεσπίσει τους κατάλληλους event listeners που διαχειρίζονται τα event που παράγονται από τις οντότητες του γραφικού περιβάλλοντος που ενδιαφέρουν. Η διαδικασία διαχείρισης και αντίδρασης του προγράμματος σε ένα event, ονομάζεται event handling.

Η εικόνα που ακολουθεί συνοψίζει την διαδικασία για την εφαρμογή της προηγούμενης ενότητας που περιέχει μόνο ένα κουμπί (button).

Οι βασικοί τύποι των διαφορετικών Event

Τα περισσότερα από τα events που μας ενδιαφέρουν κληρονομούν την κλάση java.awt.AWTEvent που με τη σειρά της κληρονομεί την κλάση java.util.EventObject. Οι κλάσεις των events βρίσκονται μέσα στα πακέτα java.awt.event και javax.swing.event. Οι βασικοί τύποι event είναι οι εξής:

  • ActionEvent: Ένα ActionEvent δημιουργείται όταν πατήσετε ένα button του γραφικού περιβάλλοντος ή επιλέξετε το στοιχείο ενός combo box ή επιλέξετε ένα στοιχείο από το κεντρικό μενού της εφαρμογής.
  • ItemEvent: Ένα event που σηματοδοτεί κατά πόσο ένα αντικείμενο τύπου checkbox είναι επιλεγμένο ή απο-επιλεγμένο. Τα event αυτού του τύπου λαμβάνονται από αντικείμενα της κλάσης ItemListener που συνδέονται με το checkbox component που το οποίο παράγει το event.
  • KeyEvent: Παράγεται όταν πιέζεται ένα πλήκτρο από το πληκτρολόγιο και προέρχεται από το component του γραφικού περιβάλλοντος που εκείνη τη στιγμή είναι ενεργό (έχει το focus). Κάθε χαρακτήρας στο πληκτρολόγιο αντιστοιχίζεται σε ένα μοναδικό εικονικό (virtual) ακέραιο αριθμό. Οι κυριότερες μέθοδοι της κλάσης είναι οι εξής:
    • public int getKeyCode(): Επιστρέφει τον κωδικό του πλήκτρου που πατήθηκε.
    • public char getKeyChar(): Επιστρέφει τον χαρακτήρα που αντιστοιχεί στο πλήκτρο που πατήθηκε. Έχει νόημα να κληθεί μόνο εάν έχει πατηθεί πλήκτρο ή συνδυασμός πλήκτρων που παράγουν εκτυπώσιμους χαρακτήρες, δηλαδή keyTypedEvent (δες KeyListener παρακάτω).
  • MouseEvent: Προϋπόθεση για να παραχθεί ένα MouseEvent είναι το ποντίκι να βρίσκεται πάνω από το component με το οποίο θα συνδεθεί το συγκεκριμένο event. Οι περιπτώσεις στις οποίες παράγεται ένα τέτοιου τύπου event είναι οι εξής:
    1. Ένα από τα τρία κουμπιά του ποντικιού (αριστερό ή δεξί ή ροδέλα) έχει πατηθεί.
    2. Ένα από τα τρία κουμπιά του ποντικιού έχει ελευθερωθεί.
    3. Ένα από τα τρία κουμπιά του ποντικιού έχει πατηθεί και ελευθερωθεί.
    4. Ο δρομέας του ποντικιού εισάγεται στην περιοχή του component για το οποίο παράγεται το event.
    5. Ο δρομέας του ποντικιού εξάγεται από περιοχή που συμπίπτει με το component για το οποίο παράγεται το event.
    6. Ο δρομέας του ποντικιού μετακινείται πάνω σε περιοχή που συμπίπτει με το component.
    7. Ο δρομέας του ποντικιού μετακινείται έχοντας παράλληλα πατημένο το αριστερό πλήκτρο σέρνωντας (drags) ένα component.
  • Οι κυριότερες μέθοδοι της κλάσης MouseEvent: είναι οι εξής:
    • public int getButton(): Κάθε πλήκτρο του ποντικιού αντιστοιχεί σε μία ακέραια σταθερά. Επιστρέφει έναν αριθμό που αντιστοιχεί στο πλήκτρο ή τα πλήκτρα του ποντικιού που έχουν πατηθεί.
    • public int getClickCount(): Επιστρέφει τον αριθμό των click που συνδέονται με το συγκεκριμένο event.
    • public Point getPoint(): Επιστρέφει τη θέση του δρομέα σε σχέση με το component με το οποίο συνδέεται το event.
    • public Point getLocationOnScreen(): Επιστρέφει τη θέση του δρομέα στην οθόνη.
  • MouseWheelEvent: Παράγεται σε κάθε μετακίνηση της ροδέλας του ποντικιού. Κυριότερες μέθοδοι είναι οι εξής:
    • public int getWheelRotation(): Επιστρέφει τον αριθμό των μονάδων (click) που ο τροχός του ποντικιού περιστρέφεται ως ακέραιος αριθμός. Όταν η ροδέλα κινείται προς τα πάνω οι τιμές είναι αρνητικές, ενώ όταν κινείται προς τα πάνω οι τιμές είναι θετικές.
    • public double getPreciseWheelRotation(): Επιστρέφει τον αριθμό των μονάδων (click) κατά τις οποίες ο τροχός του ποντικιού περιστρέφεται ως αριθμός κινητής υποδιαστολής (για μεγαλύτερη ακρίβεια). Όταν η ροδέλα κινείται προς τα πάνω οι τιμές είναι αρνητικές, ενώ όταν κινείται προς τα πάνω οι τιμές είναι θετικές.
  • WindowEvent: Ένα event που υποδεικνύει ότι ένα παράθυρο έχει αλλάξει την κατάστασή του. Αυτό το event δημιουργείται από ένα παράθυρο όταν ανοίγει, κλείνει, ενεργοποιείται ή απενεργοποιείται ή γίνεται minimize ή maximize. Κυριότερες μέθοδοι της κλάσης είναι:
    • public int getNewState(): Επιστρέφει ένα μοναδικό ακέραιο που αντιστοιχεί στη νέα κατάσταση του παραθύρου.
    • public int getOldState(): Επιστρέφει ένα μοναδικό ακέραιο που αντιστοιχεί στην προηγούμενη κατάσταση του παραθύρου.
    • public Window getWindow(): Επιστρέφει το παράθυρο από το οποίο προήλθε το event.
  • FocusEvent: Παράγεται κάθε φορά που ένα component του γραφικού περιβάλλοντος γίνεται ενεργό ή ανενεργό (κερδίζει ή χάνει το focus).

Event Listeners

Για τον πιάσιμο των παραπάνω τύπων events, η Java ορίζει ένα σύνολο από interfaces, τα οποία τα οποία όταν υλοποιούνται από μία κλάση και συνδυαστούν με κάποιο από τα components του γραφικού περιβάλλοντος έχουν την δυνατότητα να πιάσουν συγκεκριμένους τύπους από events. Όλα τα interfaces που μας ενδιαφέρουν είναι απόγονοι της κλάσης java.util.EventListener και βρίσκονται στο πακέτο java.awt.event

Οι κυριότεροι Event Listeners είναι οι εξής:

  • ActionListener: Έχει την δυνατότητα να “πιάσει” ένα ActionEvent. Διαθέτει την εξής μέθοδο:
    • void actionPerformed(ActionEvent e):
  • ItemListener: Έχει την δυνατότητα να “πιάσει” ένα ItemEvent, το οποίο συνήθως παράγεται από ένα CheckBox component.
  • KeyListener: Έχει την δυνατότητα να “πιάσει” ένα KeyEvent. Διαθέτεις τις εξής μεθόδους:
    • void keyTyped(KeyEvent e): Η μέθοδος καλείται εάν πατηθεί ένα πλήκτρο ή συνδυασμός πλήκτρων που αντιστοιχεί σε εκτυπώσιμο χαρακτήρα. Δεν έχει σημασία εάν το πλήκτρο έχει ελευθερωθεί ή όχι, αρκεί να έχει σηματοδοτηθεί η παραγωγή του χαρακτήρα προς την εφαρμογή.
    • void keyPressed(KeyEvent e): Η μέθοδος καλείται εάν πατηθεί οποιοδήποτε πλήκτρο.
    • void keyReleased(KeyEvent e): Η μέθοδος καλείται όταν ελευθερωθεί οποιοδήποτε πλήκτρο που πατήθηκε προηγούμενα.
  • MouseListener: Έχει τη δυνατότητα να “πιάσει” MouseEvents που συνδέονται με ενέργειες του ποντικιού (π.χ. αριστερό/δεξί click, πάτημα ή απελευθέρωση ενός κουμπιού του ποντικιού ή είσοδος/έξοδος του ποντικιού) πάνω σε ένα component της εφαρμογής. Συγκεκριμένα, οι μέθοδοι που διαθέτει είναι οι εξής:
    • void mouseClicked(MouseEvent e): Καλείται όταν πατηθεί ένα κουμπί του ποντικιού (πατηθεί και απελευθερωθεί) πάνω στο στοιχείο (component).
    • void mousePressed(MouseEvent e): Καλείται όταν πατηθεί ένα κουμπί του ποντικιού πάνω στο στοιχείο (component).
    • void mouseReleased(MouseEvent e): Καλείται όταν έχει ελευθερωθεί ένα κουμπί του ποντικιού που προηγουμένως πατήθηκε πάνω στο στοιχείο (component).
    • void mouseEntered(MouseEvent e): Καλείται όταν το ποντίκι μπαίνει στην περιοχή του στοιχείου (component).
    • void mouseExited(MouseEvent e): Καλείται όταν το ποντίκι βγαίνει στην περιοχή του στοιχείου (component).
  • MouseMotionListener: Έχει την δυνατότητα να “πιάσει” events που συνδέονται με την κίνηση του ποντικιού και το σύρσιμο (dragging) στοιχείων του γραφικού περιβάλλοντος. Διαθέτεις τις εξής μεθόδους:
    • void mouseDragged(MouseEvent e): Καλείται όταν πατηθεί ένα κουμπί του ποντικιού πάνω σε ένα στοιχείο και στη συνέχεια συρθεί. Τα συμβάντα MOUSE_DRAGGED θα συνεχίσουν να παραδίδονται στο στοιχείο όπου σύρεται, μέχρι να απελευθερωθεί το κουμπί του ποντικιού.
    • void mouseMoved(MouseEvent e): Καλείται όταν ο δρομέας του ποντικιού έχει μετακινηθεί σε ένα στοιχείο, αλλά δεν έχουν πατηθεί κουμπιά από τον ποντίκι.
  • MouseWheelListener: Έχει την δυνατότητα να “πιάσει” events που συνδέονται με την κίνηση της ροδέλας του ποντικιού. Μοναδική μέθοδος του interface είναι
    • void mouseWheelMoved(MouseWheelEvent e): η οποία καλείται σε κάθε κίνηση της ροδέλας.
  • WindowListener: Έχει την δυνατότητα να “πιάσει” events που συνδέονται με την αλλαγή στην κατάσταση του παραθύρου. Κυριότερες με μέθοδοι του interface είναι:
  • FocusListener: Έχει την δυνατότητα να “πιάσει” events που συνδέονται με την αλλαγή του στοιχείου που έχει το focus.
    • void focusGained(FocusEvent e): Το στοιχείο λαμβάνει το focus.
    • void focusLost(FocusEvent e): Το στοιχείο χάνει το focus.

Παράδειγμα - Πιάνοντας ένα event μέσω ενός Event Listener

Παρακάτω δίνεται το παράδειγμα της κλάσης EventHandling, η οποία δημιουργεί ένα παράθυρο και “πιάνει” διάφορα events που παράγονται από το ποντίκι και το πληκτρολόγιο στα επιμέρους components της παραθυρικής εφαρμογής. Η εφαρμογή δημιουργεί ένα κουμπί και τα εξής τέσσερα (3) textfield πεδία:

  • Button Clicks: Μετράει πόσες φορές έχει γίνει click το κουμπί στα δεξιά.
  • Keyboard Input: Δηλώνει ποιος χαρακτήρας πατήθηκε κάθε φορά όταν το focus είναι στο συγκεκριμένο textfield.
  • Mouse current position on window: Δηλώνει τη θέση του δρομέα του ποντικιού εντός της εφαρμογής.

Το κουμπί εμφανίζει διαφορετικά μηνύματα όταν ο δρομέας του ποντικιού βρίσκεται πάνω από αυτό, απομακρύνεται ή γίνεται click.

EventHandling.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
 
public class EventHandling extends JFrame {
  JFrame frame;
  JPanel framePanel;
  JPanel textFieldPanel;
  JButton button;
  JTextField actionEventTextField;
  JTextField keyEventTextField;
  JTextField mouseMotionEventTextField;
  int buttonClickedCount;
  private static int TEXT_FIELD_SIZE = 20;
 
  public EventHandling() {    
    frame = new JFrame("CE325 - Event Handling Demo");    
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
    button = new JButton("  Put Cursor!  ");
    button.setBackground(new Color(0xe9,0xe9,0xe9));
    button.setFont(new Font("Courier", Font.BOLD, 15));
    Border buttonBorder = BorderFactory.createRaisedBevelBorder();
    button.setBorder(buttonBorder);
 
    buttonClickedCount = 0;
    button.addActionListener( new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        buttonClickedCount++;
        actionEventTextField.setText("Button clicked "+buttonClickedCount+" times!");
      }
    });
 
    button.addMouseListener( new MouseListener() {
      public void mouseClicked(MouseEvent e) {        
      }
      public void mouseEntered(MouseEvent e) {
        button.setText("  Press  me!   ");
      }
      public void mouseExited(MouseEvent e) {
        button.setText("  Put Cursor!  ");
      }
      public void mousePressed(MouseEvent e) {
        button.setText("  Release Me!  ");
      }
      public void mouseReleased(MouseEvent e) {
        button.setText("  Press again  ");
      }
    });
 
    frame.add(button, BorderLayout.EAST);
 
    textFieldPanel = new JPanel(new GridLayout(5, 2, 3, 3));    
 
    textFieldPanel.add(new JLabel("Button Clicks:"));
    actionEventTextField = new JTextField("", TEXT_FIELD_SIZE);    
    textFieldPanel.add(actionEventTextField);
 
    textFieldPanel.add(new JLabel("Keyboard Input:"));
    keyEventTextField = new JTextField("", TEXT_FIELD_SIZE);
    keyEventTextField.addKeyListener( new KeyListener() {
      public void keyTyped(KeyEvent e) {        
        keyEventTextField.setText("Character \""+e.getKeyChar()+"\" was pressed");
      }
      public void keyPressed(KeyEvent e) {
        keyEventTextField.setText("");
      }
      public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_SHIFT || 
           e.getKeyCode() == KeyEvent.VK_CONTROL ||
           e.getKeyCode() == KeyEvent.VK_ENTER
           )
          return;        
        String str = keyEventTextField.getText();        
        str = str.substring(0,str.length()-1);
        keyEventTextField.setText(str);
      }
    });    
    textFieldPanel.add(keyEventTextField);    
 
    textFieldPanel.add(new JLabel("Mouse current position on window:"));
    mouseMotionEventTextField = new JTextField("", TEXT_FIELD_SIZE);
    frame.addMouseMotionListener( new MouseMotionListener() {
      public void mouseDragged(MouseEvent e) {
      }
      public void mouseMoved(MouseEvent e) {
        mouseMotionEventTextField.setText("Cursor position at "+e.getX()+", "+e.getY());
      }
    });    
    textFieldPanel.add(mouseMotionEventTextField);    
 
    frame.add(textFieldPanel, BorderLayout.CENTER);
 
    frame.pack();
    frame.setVisible(true);
  }
 
  public static void main(String []args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
       new EventHandling();
      }
    });
  }
}
swing/events.txt · Last modified: 2021/04/13 05:16 (external edit)