User Tools

Site Tools


swing:intro

This is an old revision of the document!


Δημιουργία παραθυρικών εφαρμογών με Swing

Σε αυτή την ενότητα θα δούμε πως μπορούμε να κατασκευάσουμε παραθυρικές εφαρμογές (Graphical User Interfaces, GUIs) με χρήση της βιβλιοθήκης Swing. Οι παραθυρικές εφαρμογές είναι διαφορετικές από τις εφαρμογές που χρησιμοποιούν την κονσόλα για είσοδο και έξοδο, με την έννοια ότι δεν υφίσταται μία συνεχής ροή προγράμματος, αλλά τμήματα του προγράμματος, εκτελούνται μετά την δημιουργία ενός ερεθίσματος, που ονομάζεται event. Το ερέθισμα αυτό κατά κανόνα δημιουργείται από τον χρήστη που αλληλεπιδρά με το πρόγραμμα μέσω του ποντικιού και του πληκτρολογίου. Το πρόγραμμα εκτελείται όταν δοθεί το επόμενο ερέθισμα από τον χρήστη και να δημιουργηθεί το αντίστοιχo event. Επειδή, το πρόγραμμα υπακούει σε ερεθίσματα, το μοντέλο αυτό είναι γνωστό ως event driven programming (προγραμματισμός με βάση events).

Το παρακάτω σχήμα δείχνει εποπτικά την διαδικασία δημιουργίας ενός event που προκύπτει από το πάτημα ενός κουμπιού (button) με το ποντίκι. Το event “πιάνεται” από ένα event listener και στη στη συνέχεια εκτελείται κώδικας που έχει θεσπιστεί για το event αυτό.

Βασικό χαρακτηριστικό του event driven προγραμματισμού είναι ότι δημιουργούμε αντικείμενα και μεθόδους (event listeners) τα οποία δεν γνωρίζουμε αν θα κληθούν και με ποια σειρά θα κληθούν, καθώς αυτό εξαρτάται από τον χρήστη που χρησιμοποιεί το πρόγραμμα. Ο προγραμματιστής κατά κανόνα δεν έχει τον έλεγχο της σειράς εκτέλεσης των μεθόδων που ορίζει.

Το γραφικό περιβάλλον μίας εφαρμογής αποτελείται από αντικείμενα που αντιπροσωπεύουν οντότητες με τις οποίες ο χρήστης μπορεί να αλληλεπιδράσει. Παραδείγματα, τέτοιων οντοτήτων είναι τα buttons, text boxes, textfields, radio buttons, menu items κ.α. Στην παρακάτω εικόνα δίνεται μία απλή εφαρμογή calculator. Κάθε αριθμός ή τελεστής αριθμητικής πράξης είναι αποθηκευμένο σε ένα αντικείμενο τύπου button. Οι ενδιάμεσοι αριθμοί και το αποτέλεσμα της αριθμητικής πράξης εμφανίζεται στο πεδίο κειμένου (textfield) στην κορυφή του παραθύρου.

Events και Listeners

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

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

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

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

Οι κλάσεις των events βρίσκονται μέσα στο πακέτο java.awt.event. Οι κυριότεροι τύποι event είναι οι εξής:

  • AWTEvent: Είναι η γονική κλάση για όλα τα αντικείμενα τύπου event. Αυτή η κλάση και οι υποκατηγορίες της κληρονομούν την κλάση java.awt.Event.
  • ActionEvent: Ένα ActionEvent δημιουργείται όταν πατήσετε ένα button του γραφικού περιβάλλοντος ή επιλέξετε το στοιχείο μίας λίστας ή επιλέξετε ένα στοιχείο από το μενού της εφαρμογής.
  • KeyEvent: Παράγεται όταν πατιέται ένα πλήκτρο από το πληκτρολόγιο.
  • MouseEvent: Παράγεται α) σε κάθε μεταβολή της θέσης του ποντικιού και β) σε κάθε πάτημα των πλήκτρων του ποντικιού.
  • MouseWheelEvent: Παράγεται σε κάθε μετακίνηση της ροδέλας του ποντικιού.
  • WindowEvent: Ένα event που υποδεικνύει ότι ένα παράθυρο έχει αλλάξει την κατάστασή του. Αυτό το event δημιουργείται από ένα παράθυρο όταν ανοίγει, κλείνει, ενεργοποιείται ή απενεργοποιείται ή γίνεται minimize ή maximize.

Event Listeners

Για τον πιάσιμο των παραπάνω τύπων events, η Java ορίζει ένα σύνολο από interfaces, τα οποία τα οποία όταν υλοποιούνται σε μία κλάση έχουν την δυνατότητα να πιάνουν συγκεκριμένους τύπους από events. Οι κυριότεροι Event Listeners είναι οι εξής:

  • java.util.EventListener: Γενικό interface που πρέπει να υλοποιούν όλα τα αντικείμενα τύπου EventListener. Όλα τα subinterfaces του συγκεκριμένου interface που μας ενδιαφέρουν βρίσκονται στο πακέτο java.awt.event.
  • ActionListener:
  • KeyListener:
  • MouseListener:
  • MouseMotionListener:
  • MouseWheelListener:
  • WindowListener:

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

Το πρώτο μου πρόγραμμα

Παρακάτω φτιάχνουμε ένα πρώτο απλό παραθυρικό πρόγραμμα το οποίο έχει μόνο ένα κουμπί που τερματίζει την εφαρμογή. Κατεβάστε και τρέξτε τα επόμενα δύο αρχεία.

FirstWindow.java
import javax.swing.JFrame;
import javax.swing.JButton;
 
public class FirstWindow {
  public static final int WIDTH = 300;
  public static final int HEIGHT = 200;
 
  public static void showGUI() {
    JFrame firstWindow = new JFrame();
    firstWindow.setSize(WIDTH, HEIGHT);
    firstWindow.setTitle("First Window Program!");
    firstWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    JButton endButton = new JButton("Click to end program.");
    EndingListener buttonEar = new EndingListener();
    endButton.addActionListener(buttonEar);
    firstWindow.add(endButton);
    firstWindow.setVisible(true);
  }
 
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        showGUI();
      } 
    });
  }
}
EndingListener.java
import java.awt.event.*;
 
public class EndingListener implements ActionListener {
  public void actionPerformed(ActionEvent e) {
    System.exit(0);
  }
}

Ας εξετάσουμε όμως τι κάνει το πρόγραμμα μας. Αρχικά δημιουργούμε ένα αντικείμενο του τύπου JFrame μέσα από την κλήση.

    JFrame firstWindow = new JFrame();

Το αντικείμενο αυτό είναι ένα απλό παράθυρο με τρία κουμπιά (minimize, resize, close). Στη συνέχεια ορίζουμε το μέγεθος του παραθύρου (σε pixels) και τον τίτλο του.

    firstWindow.setSize(WIDTH, HEIGHT);
    firstWindow.setTitle("First Window Program!");

Από την εμπειρία σας γνωρίζετε ότι όταν πατήσετε το κουμπί για το κλείσιμο του παραθύρου τότε το παράθυρο κλείνει και η εφαρμογή τερματίζεται. Η παρακάτω γραμμή διαχειρίζεται διαφορετικά ένα click event στο κουμπί κλεισίματος του παραθύρου, όπου όταν πατήσετε το κουμπί κλεισίματος αντί το παράθυρο να κλείσει δεν κάνει τίποτα.

firstWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

Στην συνέχεια ορίζουμε ένα αντικείμενο τύπου JButton (κουμπί) με τίτλο “Click to end program.” και δημιουργούμε και έναν Listener τον οποίο συνδέουμε με το συγκεκριμένο κουμπί.

JButton endButton = new JButton("Click to end program.");
EndingListener buttonEar = new EndingListener();
endButton.addActionListener(buttonEar);

Προσθέτουμε το κουμπί στο παράθυρο και ορίζουμε ότι το παράθυρο που φτιάξαμε θέλουμε να είναι ορατό.

firstWindow.add(endButton);
firstWindow.setVisible(true);

Χρήση μίας ανώνυμης κλάσης ActionListener

Για να μην έχουμε πολλαπλά αρχεία, μία παραλλαγή των παραπάνω είναι να τοποθετήσουμε την κλάση EndingListener σε μία ανώνυμη κλάση, ως εξής:

FirstSwingDemo2.java
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.event.*;
 
public class FirstSwingDemo2 {
  public static final int WIDTH = 300;
  public static final int HEIGHT = 200;
 
  public static void showGUI() {
    JFrame firstWindow = new JFrame();
    firstWindow.setSize(WIDTH, HEIGHT);
    firstWindow.setTitle("First Window Program!");
    firstWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    JButton endButton = new JButton("Click to end program.");
 
    ActionListener buttonEar = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    };
 
    endButton.addActionListener(buttonEar);
    firstWindow.add(endButton);
    firstWindow.setVisible(true);
  }
 
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        showGUI();
      } 
    });
  }
}

Το παραπάνω παράθυρο ως αυτόνομη κλάση

Αν θέλατε να δημιουργήσετε μία κλάση που να υλοποιεί το συγκεκριμένο παράθυρο, θα μπορούσατε να το κάνετε ως εξής:

FirstWindow.java
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.event.*;
 
public class FirstWindow extends JFrame {
  public static final int WIDTH = 300;
  public static final int HEIGHT = 200;
 
  public static void showGUI() {
    JFrame firstWindow = new JFrame();
    firstWindow.setSize(WIDTH, HEIGHT);
    firstWindow.setTitle("First Window Program!");
    firstWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    JButton endButton = new JButton("Click to end program.");
    ActionListener buttonEar = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    };
    endButton.addActionListener(buttonEar);
    firstWindow.add(endButton);
    firstWindow.setVisible(true);
  }
 
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        showGUI();
      } 
    });
  }
}

Βασικές μέθοδοι της κλάσης JFrame

Οι βασικές μέθοδοι της κλάσης JFrame είναι οι παρακάτω:

  • public JFrame(): default κατασκευαστής του παραθύρου.
  • public JFrame(String title): Κατασκευαστής του παραθύρου στον οποίο ορίζεται και ο τίτλος.
  • public void setTitle(String title): Ορισμός του τίτλου του παραθύρου.
  • public void setSize(int width, int height): Ορισμός του μεγέθους του παραθύρου σε pixels.
  • public void add(Component componentToAdd): Προσθέτει ένα γραφικό component στο παράθυρο.
  • public void setLayout(LayoutManager manager): Ορίζει το layout για το παράθυρο. Θα δούμε πιο κάτω τι είναι το layout και θα δούμε επίσης τα πιο ενδιαφέροντα layouts.
  • public void setMenuBar(JMenuBar menubar): Ορίζει την μπάρα για το μενού στο παράθυρο.
  • public void setDefaultCloseOPeration(int operation): Ορίζει την διαδικασία που θα τρέξει όταν ο χρήστης πατήσει το κουμπί (επάνω δεξιά) που κλείνει το παράθυρο. Η μεταβλητή operation μπορεί να πάρει μία από τις παρακάτω τιμές:
    • JFrame.DO_NOTHING_ON_CLOSE: Δεν κάνει τίποτα. Αν υπάρχουν ορισμένοι window listeners αυτοί εκτελούνται.
    • JFrame.HIDE_ON_CLOSE: Κρύβει το παράθυρο αφού εκτελέσει πιθανώς ορισμένους window listeners. Το παράθυρο δεν είναι δυνατόν να ανακτηθεί, αλλά η εφαρμοργή δεν τερματίζεται. Η παραπάνω τιμή είναι η default αν δεν έχει οριστεί κάποια άλλη.
    • JFrame.DISPOSE_ON_CLOSE: Τερματίζει το τρέχον παράθυρο. Αν υπάρχουν και άλλα παράθυρα αυτά παραμένουν, ενώ αν δεν υπάρχουν τερματίζει η εφαρμογή.
    • JFrame.EXIT_ON_CLOSE: Τερματίζει το τρέχον παράθυρο και συνολικά την εφαμοργή (αν υπάρχουν και άλλα παράθυρα τερματίζουν και αυτά).

Η μέθοδος w.setVisible(true), ορίζει ότι το παράθυρο θα είναι ορατό. Αν ορίσετε w.setVisible(false), τότε το παράθυρο δεν εμφανίζεται και το πρόγραμμα τερματίζεται μόλις αρχίσει η εκτέλεση του.

swing/intro.1521484186.txt.gz · Last modified: 2018/03/19 18:29 by gthanos