Γεγονότα και Γεγονοστρεφής Προγραµµατισµός

Σχετικά έγγραφα
ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Graphical User Interfaces (GUI) SWING

8. Το μοντέλο συμβάντων του AWT

Εισαγωγή στον Αντικειμενοστρεφή Προγραμματισμό Διάλεξη #18

Week 12: GUIs with Swing

Εισαγωγή στον Αντικειμενοστρεφή Προγραμματισμό Διάλεξη #17

Week 10: Graphical User Interfaces

Ειδικά Θέματα Προγραμματισμού

ημιουργία Γραφικού Περιβάλλοντος

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Graphical User Interfaces (GUI) SWING

ΑΝΤΙΓΡΑΦΗ ΑΡΧΕΙΟΥ ΣΕ ΔΙΣΚΕΤΑ ΑΝΤΙΓΡΑΦΗ ΑΡΧΕΙΟΥ ΑΠΟ ΔΙΣΚΕΤΑ. Από τον κατάλογο που εμφανίζεται επιλέγω: Αποστολή προς Δισκέτα (3,5)

Γραφικές ιεπαφές Χρήστη και Γραφικά

Εργαστήριο 1-1 η Άσκηση - Ανάλυση

ΣΕΛΙ Α 1 ΚΕΦΑΛΑΙΟ 1 - ΑΡΧΙΚΑ

ΠΛΗΚΤΡΟΛΟΓΙΟ. Η ελληνική διάταξη πλήκτρων είναι η παρακάτω (δεν υπάρχουν άλλες διατάξεις για το ελληνικό αλφάβητο):

Αντικειμενοστρεφής Προγραμματισμός Διάλεξη 12 : ΒΑΣΙΚΑ ΣΤΟΙΧΕΙΑ GUI AWT ΚΑΙ

ΓΡΑΦΙΚΕΣ ΔΙΕΠΑΦΕΣ ΧΡΗΣΤΗ- SWING (1)

4 ο Εργαστήριο Τυχαίοι Αριθμοί, Μεταβλητές Συστήματος

MICROSOFT OFFICE 2003

Πρακτικές οδηγίες για την Επεξεργασία Κειμένου

A7.2 Δημιουργία Απλής Γραφικής Εφαρμογής σε Περιβάλλον Scratch

Κλάσεις και Αντικείµενα

αντίστοιχο γεγονός. Όταν όντως το κουμπί

2.1 Αντικειµενοστρεφής προγραµµατισµός

ΤΕΙ Ηρακλείου. Τμήμα Λογιστικής Πληροφορική I 6 η Εργαστηριακή άσκηση (Excel)

Εργαστήριο Δομημένος Προγραμματισμός (C#) Τμήμα Μηχανολογίας Νικόλαος Ζ. Ζάχαρης Καθηγητής Εφαρμογών

Χρήση του πληκτρολογίου

MEDIWARE L.I.S ΟΔΗΓΙΕΣ ΥΠΟΠΡΟΓΡΑΜΜΑΤΟΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ ΕΠΙΣΚΕΨΕΩΝ

Ειδικά Θέματα Προγραμματισμού

Atlantis - Νέο user interface

Κλάσεις. Κατηγορίες Αντικειµένων. Κλάσεις. Φυσικά Αντικείµενα. Χώρος = Οµάδα Φυσικών Αντικειµένων. Πρόγραµµα = Οµάδα

8.1 Top-Level Swing Containers και Swing Components

ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΕΙΣ ΓΛΩΣΣΕΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ Ιανουάριος 2008 Οι απαντήσεις να είναι καθαρογραμμένες με ευδιάκριτους όλους του χαρακτήρες.

Εργαστήριο 2 - Άσκηση - Ανάλυση

10.1 Γενικά για τα streams

Microsoft PowerPoint 2007

Περιεχόμενα ΜΕΡΟΣ ΠΡΩΤΟ. Πρόλογος... 13

ζωγραφίζοντας µε τον υπολογιστή

Εισαγωγή στο πρόγραμμα Microsoft word 2003

ΕΡΩΤΗΜΑΤΟΛΟΓΙΟ. α) pbrush β) brush γ) pbush δ) pbrus. α) ctrl + enter β) ctrl + esc γ) alt + ctrl δ) alt + enter

Ανακαλύπτω. Ο υπολογιστής στην πράξη!

Άσκηση 1(Σκοπός αντικείμενο)

12.6. Άσκηση 6 - [αξιοποίηση γραφικής διεπαφής (GUI)] (έκδοση 2006)

να ακολουθήσουμε Έναρξη Όλα τα Προγράμματα και να ενεργοποιήσουμε την επιλογή Microsoft Word.

1. Τα τμήματα της επιφάνειας εργασίας των Windows

21. ΦΥΛΛΟ ΕΡΓΑΣΙΑΣ 4 - ΔΗΜΙΟΥΡΓΩΝΤΑΣ ΜΕ ΤΟ BYOB BYOB. Αλγόριθμος Διαδικασία Παράμετροι

Αντικειµενοστρεφής Προγραµµατισµός

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Μέθοδοι

Μάθημα 1: Εισαγωγή. Κάνε κλικ την εντολή "κινήσου" και με το ποντίκι πατημένο μετέφερε τη στη περιοχή σεναρίων.

Γ ΓΥΜΝΑΣΙΟΥ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΜΕ ΤΗ ΓΛΩΣΣΑ MicroWorlds Pro

Περιεχόμενα. Πρόλογος 15

ΠΛΗΡΟΦΟΡΙΚΗ ΙΙ (JAVA) 11/3/2008

ΠΛΗΡΟΦΟΡΙΚΗ Ι JAVA Τμήμα θεωρίας με Α.Μ. σε 3, 7, 8 & 9 25/10/07

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Πίνακες Κλάσεις και Αντικείμενα

ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΕΙΣ ΓΛΩΣΣΕΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ Ιανουάριος 2007 Οι απαντήσεις να είναι καθαρογραμμένες με ευδιάκριτους όλους του χαρακτήρες.

Wrapper Classes, Abstract Classes and Interfaces

Οδηγός Χρήστη για το ιαλειτουργικό Χάρτη

ηµιουργία ιαλογικών Προγραµµάτων για το Web

2.1. Εντολές Σχόλια Τύποι Δεδομένων

Εργαστήριο 3 - Άσκηση - Ανάλυση

Κάθε ένα κελί θα πρέπει να περιέχει ένα μόνο στοιχείο δεδομένων, για παράδειγμα το όνομα σε ένα κελί, το επίθετο σε άλλο κελί.

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Δημιουργία Κλάσεων και Αντικειμένων

ΤΟ ΠΕΡΙΒΑΛΛΟΝ ΤΗΣ. Εργαλειοθήκη Παρουσιάζετε το έργο σας Εκκινείτε τα σενάριά σας Σταματάτε όλα τα σενάρια. Οι 8 ομάδες της Παλέτας εντολών

Αντικείµενα. ηµιουργία και χρησιµοποίηση αντικειµένων. ηµιουργία αντικειµένων

Λίγα λόγια από το συγγραφέα Κεφάλαιο 1: Βάσεις δεδομένων και Microsoft Access Κεφάλαιο 2: Microsoft Access

2 ο Εργαστήριο Αλληλεπίδραση και Animation

Microsoft Word. Δυνατότητες του Word. Εισαγωγή και επεξεργασία Κειμένου

Εργαστήριο «Τεχνολογία Πολιτισμικού Λογισμικού» Ενότητα. Επεξεργασία πινάκων

Πρακτικές συμβουλές κατά την πληκτρολόγηση ., ; :! ( ) " " Άνοιγμα και αποθήκευση εγγράφου Αρχείο, Άνοιγμα. Αρχείο / Αποθήκευση

Δημιουργία ενός κενού πίνακα

Σημειώσεις στο PowerPoint

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Στατικές μέθοδοι και μεταβλητές Εσωτερικές κλάσεις

Γενικά (για τις γραπτές εξετάσεις)

Διαδικτυακό Περιβάλλον Διαχείρισης Ασκήσεων Προγραμματισμού

1ο μέρος 1. Φτιάχνουμε την πίστα. Μια ενδεικτική πίστα φαίνεται παρακάτω:

Atlantis - Νέο user interface

Βασικά της γλώσσας JAVA

Πρακτική Άσκηση Για να αντιγράψουμε τη μορφοποίηση μιας λέξης ποιο εργαλείο από τα παρακάτω χρησιμοποιούμε;

Περιεχόμενα. Πρόλογος 15

ΕΓΧΕΙΡΙΔΙΟ ΧΡΗΣΗΣ GRS-1

Εισαγωγή στο Libre Office. Bάιος Κολοφωτιάς Επιστημονικός Συνεργάτης Sweng Lab A.Π.Θ

Κλάσεις. Τροποποιητές, ιασυνδέσεις, Πακέτα. Τροποποιητές ελέγχου προσπέλασης µεταβλητών και µεθόδων

Η πρώτη παράμετρος είναι ένα αλφαριθμητικό μορφοποίησης

Copyright 2017 HP Development Company, L.P.

2 Ορισμός Κλάσεων. Παράδειγμα: Μηχανή για Εισιτήρια. Δομή μιας Κλάσης. Ο Σκελετός της Κλάσης για τη Μηχανή. Ορισμός Πεδίων 4/3/2008

Εργαστήριο Java. Αντικείµενο: Δίκτυα. Χειρισµός URLs. Άσκηση 1. Lab11. Πακέτο java.net

«Αβάκιο» Οδηγός χρήσης Μικρόκοσμου που αποτελείται από τις ψηφίδες Καμβάς, Χελώνα, Γλώσσα, Μεταβολέας, Χρώματα.

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Δημιουργώντας δικές μας Κλάσεις και Αντικείμενα

Γ3.3.Μ7 ΕΠΑΝΆΛΗΨΗ ΜΈΡΟΣ Α: ΈΝΝΟΙΕΣ ΤΙ ΕΊΝΑΙ Η VISUAL BASIC ΤΙ ΜΠΟΡΟΎΜΕ ΝΑ ΚΆΝΟΥΜΕ ΜΕ ΤΗ VISUAL BASIC ΑΝΤΙΚΕΊΜΕΝΑ: ΦΌΡΜΑ ΚΑΙ ΧΕΙΡΙΣΤΉΡΙΑ ΕΤΙΚΈΤΑ LABEL

Ορισµός Νήµα (thread) είναι µια ακολουθιακή ροή ελέγχου (δηλ. κάτι που έχει αρχή, ακολουθία εντολών και τέλος) σ ένα

ΠΛΗΡΟΦΟΡΙΚΗ Ι JAVA Τμήμα θεωρίας με Α.Μ. σε 3, 7, 8 & 9 6/12/07

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Μέθοδοι

ΕΙΣΑΓΩΓΗ ΣΤΟ POWER POINT

Εγχειρίδιο διαχείρισης χρηστών και λιστών διανομής για τον Υπεύθυνο Φορέα του Δικτύου "Σύζευξις" -1-

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

Το επόμενο σχήμα εμφανίζει την ιεραρχία των GUI-components κλάσεων μαζί με κάποιες επιπλέον συμπληρωματικές κλάσεις που διαχειρίζονται ένα GUI.

Λεπτομέριες τοιχοποιίας Σχεδίαση κάτοψης

Αντικειμενοστρεφής Προγραμματισμός

Μια πρώτη επαφή με το Excel

Οδηγίες για το CABRI - GEOMETRY II Μωυσιάδης Πολυχρόνης - Δόρτσιος Κώστας

ZTrade Quick Start User Manual Version 2.2

Transcript:

Κεφάλαιο 19 Γεγονότα και Γεγονοστρεφής Προγραµµατισµός εν υποστηρίζω ότι έχω ελέγξει γεγονότα, αλλά απλώς εξοµολογούµαι ότι γεγονότα έχουν ελέγξει εµένα. Abraham Lincoln 19.1 Εισαγωγή Οι αλληλεπιδράσεις µε τα προγράµµατά µας που περιγράψαµε στα προηγούµενα επιτυγχάνονταν µέσω διαλόγων. Σ ένα διάλογο εισόδου ο χρήστης µπορούσε να πληκτρολογήσει µια συµβολοσειρά για είσοδο στο πρόγραµµά του, ενώ σ ένα διάλογο εξόδου µπορούσε να πιέσει το κουµπί OK, για να κλείσει το κουτί που περιείχε αποτελέσµατα αυτού. Παρόλο που τέτοιοι διάλογοι διευκολύνουν την είσοδο και την έξοδο ενός προγράµµατος, παρέχουν περιορισµένες δυνατότητες ένας διάλογος εισόδου µπορεί να πάρει µόνο µια τιµή κάθε φορά από το χρήστη κι ένας διάλογος εξόδου µπορεί να εµφανίσει ένα µόνο µήνυµα, έστω κι αν αυτό αποτελείται από πολλές γραµµές. Στις περισσότερες εφαρµογές ή µικροεφαρµογές (βλ. Κεφ. 20) είναι επιθυµητό να παίρνουµε περισσότερες της µιας τιµές δεδοµένων και να εµφανίζουµε περισσότερα από ένα σύνολα αποτελεσµάτων ταυτόχρονα. Για να το πετύχουµε αυτό µπορούµε να υλοποιήσουµε Γ Χ που οδηγούνται από γεγονότα, δηλαδή δηµιουργούν γεγονότα (events), όταν ο χρήστης του προγράµµατος αλληλεπιδρά µε αυτές. Τυπικές αλληλεπιδράσεις του χρήστη περιλαµβάνουν το πάτηµα κάποιου ή κάποιων πλήκτρων του πληκτρολογίου, τη µετακίνηση του ποντικιού, το πάτηµα ε- νός κουµπιού του, την επιλογή ενός στοιχείου κάποιου µενού, το κλείσιµο ενός παραθύρου και, γενικά, κάποια αλληλεπίδραση του χρήστη µε οποιοδήποτε συστατικό 1 της γραφικής διεπαφής του. Όταν ο χρήστης αλληλεπιδρά µ ένα συστατικό µιας τέτοιας Γ Χ, το πρόγραµ- µα του ειδοποιείται ότι έχει συµβεί ένα γεγονός (event) και πρέπει να καλέσει µια µέθοδο για να αντιµετωπίσει το γεγονός αυτό. Οι µέθοδοι που καλούνται όταν 1 Εκτός από τα αντικείµενα τύπου JLabel τα οποία µπορούν να δηµιουργήσουν µόνο γεγονότα εστίασης (focus events). 541

542 Προγραµµατισµός µε Java συµβαίνουν γεγονότα και που πρέπει να τα αντιµετωπίσουν είναι γνωστές ως µέθοδοι χειρισµού γεγονότων (event handling methods) ή χειριστές γεγονότων (event handlers). Αυτό το είδος προγραµµατισµού είναι γνωστό ως προγραµµατισµός οδηγούµενος από γεγονότα ή γεγονοστρεφής προγραµµατισµός (event-driven programming): όταν ο χρήστης αλληλεπιδρά µ ένα συστατικό µιας Γ Χ, το πρόγραµµά του οδηγείται από το γεγονός αυτό, δηλαδή ειδοποιείται ότι έχει συµβεί ένα γεγονός και πρέπει να το χειριστεί καταλλήλως. 19.2 Τύποι γεγονότων Τα γεγονότα της Java χωρίζονται σε δύο κατηγορίες: τα γεγονότα χαµηλού επιπέδου και τα σηµασιολογικά γεγονότα. Τα γεγονότα χαµηλού επιπέδου (low-level events) περιλαµβάνουν τα γεγονότα του πληκτρολογίου (key events) και τα γεγονότα του ποντικιού (mouse events) 2. Τα σηµασιολογικά γεγονότα (semantic events) περιλαµβάνουν τα γεγονότα ενέργειας (action events) 3. Η αιτία που προξενεί ένα σηµασιολογικό γεγονός µπορεί να διαφέρει ανάλογα µε τον τύπο του συστατικού της Γ Χ, µε το οποίο αλληλεπιδρά ο χρήστης. Για παράδειγµα, ένα αντικείµενο τύπου JTextField προκαλεί ένα γεγονός τύπου ActionEvent, όταν ο χρήστης πιέσει το πλήκτρο ENTER µέσα σε αυτό, ενώ ένα αντικείµενο τύπου JButton προξενεί ένα γεγονός του ίδιου τύπου, όταν ο χρήστης το πατήσει µε το ποντίκι. Ο Πίνακας 19.1 δείχνει την ιεραρχία µερικών από τις τάξεις γεγονότων του πακέτου java.awt.event. Με έντονα έχουν σηµειωθεί οι τάξεις που θα περιγράψου- µε στο κεφάλαιο αυτό (το πακέτο javax.swing.event παρέχει κι άλλους τύπους γεγονότων, σχετικούς µε συστατικά του Swing, που δε θα µας απασχολήσουν στο βιβλίο αυτό). java.lang.object java.util.eventobject java.awt.awtevent java.awt.componentevent java.awt.containerevent java.awt.focusevent java.awt.paintevent java.awt.windowevent γεγονότα χαµηλού επιπέδου 2 3 Άλλα γεγονότα χαµηλού επιπέδου περιλαµβάνουν γεγονότα συστατικών (component events), γεγονότα υποδοχέων (container events), γεγονότα εστίασης (focus events) και γεγονότα παραθύρων (window events). Άλλα σηµασιολογικά γεγονότα περιλαµβάνουν γεγονότα αντικειµένων (item events) και γεγονότα επιλογής από λίστα (list selection events).

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 543 java.awt.inputevent java.awt.keyevent java.awt.mouseevent java.awt.mousewheelevent java.awt.actionevent σηµασιολογικά γεγονότα java.awt.adjustmentevent java.awt.itemevent Πίνακας 19.1 Μερική ιεραρχία µερικών από τις τάξεις γεγονότων του πακέτου java.awt.event. Για λόγους φορητότητας, όποτε είναι δυνατό, πρέπει να χρησιµοποιούµε σηµασιολογικά γεγονότα αντί γεγονότα χαµηλού επιπέδου. Για παράδειγµα, ο χειρισµός γεγονότων ενεργείας κάποιου κουµπιού, αντί γεγονότων του ποντικιού, σηµαίνει ότι το κουµπί µας θα ανταποκριθεί κατάλληλα όταν ο χρήστης προσπαθήσει να το ενεργοποιήσει µε κάποιον εναλλακτικό τρόπο, για παράδειγµα. ο χρήστης θα µπορούσε να ενεργοποιήσει το κουµπί λέγοντας µια ορισµένη φράση (audio look and feel). 19.3 Μηχανισµός χειρισµού γεγονότων Για να αντιµετωπιστεί οποιοδήποτε γεγονός, πρέπει να προσδιοριστεί η µέθοδος χειρισµού του γεγονότος αυτού. Έτσι ο µηχανισµός χειρισµού γεγονότων περιλαµβάνει τρία µέρη: την πηγή του γεγονότος, το αντικείµενο του γεγονότος και τον ακροατή του γεγονότος. Η πηγή του γεγονότος (event source) είναι το συστατικό της Γ Χ µε το οποίο ο χρήστης αλληλεπιδρά. Το αντικείµενο του γεγονότος (event object) περιέχει τις πληροφορίες που αφορούν στο γεγονός που συνέβη. Οι πληροφορίες αυτές περιλαµβάνουν µια αναφορά προς την πηγή του γεγονότος, καθώς και οτιδήποτε άλλο απαιτείται από τον ακροατή γεγονότος για να χειριστεί το εν λόγω γεγονός Ο ακροατής του γεγονότος (event listener) είναι ένα αντικείµενο το οποίο ειδοποιείται όταν συµβεί ένα γεγονός. Όταν ειδοποιηθεί, ο ακροατής γεγονότος παραλαµβάνει ένα αντικείµενο-γεγονός και το χρησιµοποιεί για να καλέσει τον κατάλληλο χειριστή που θα αντιµετωπίσει στο γεγονός αυτό.

544 Προγραµµατισµός µε Java 19.3.1 Πηγές γεγονότων Όταν συµβεί κάποιο γεγονός, ειδοποιούνται µόνο οι ακροατές γεγονότων που έχουν εγγραφεί στην πηγή του γεγονότος και που αφουγκράζονται γεγονότα του ίδιου τύπου µε αυτό που συνέβη. Για παράδειγµα, αν ένας ακροατής γεγονότων του ποντικιού έχει εγγραφεί µε κάποιο συστατικό µιας Γ Χ και το συστατικό δεν έχει ακροατές άλλων γεγονότων, τότε το συστατικό αυτό µπορεί να αντιδράσει µόνο σε γεγονότα του ποντικιού. Κάθε πηγή γεγονότων µπορεί να έχει περισσότερους από έναν ακροατές γεγονότων. Ο διερµηνευτής της Java πρέπει να διατηρεί µια λίστα από τους εγγεγραµµένους ακροατές κάθε πηγής γεγονότων και να τους ειδοποιεί όταν συµβεί οποιοδήποτε γεγονός. Πρέπει επίσης να παρέχει µεθόδους που επιτρέπουν στους ακροατές µιας πηγής γεγονότων να εγγράφονται και ακυρώνουν την εγγραφή τους µε αυτήν. Ένας ακροατής γεγονότων µπορεί επίσης να είναι εγγεγραµµένος µε περισσότερες από µια πηγές γεγονότων, για παράδειγµα µε δύο ή περισσότερα κουµπιά. Τέλος, µια ενέργεια µπορεί να προκαλέσει περισσότερα του ενός γεγονότα. Για παράδειγµα η πίεση του πλήκτρου k µέσα σ ένα πεδίο κειµένου προξενεί τρία γεγονότα: ένα γεγονός πατήµατος πλήκτρου, ένα γεγονός εισαγωγής χαρακτήρα κι ένα γεγονός απελευθέρωσης πλήκτρου. 19.3.2 Αντικείµενα γεγονότων Όταν ένα γεγονός δηµιουργείται από την αλληλεπίδραση του χρήστη µ ένα συστατικό µιας Γ Χ, τότε δίνεται στο γεγονός αυτό ένα µοναδικό αναγνωριστικό γεγονότος (event identifier) που το προσδιορίζει µονοσήµαντα. Οι πληροφορίες οι σχετικές µ ένα γεγονός µιας Γ Χ αποθηκεύονται σ ένα αντικείµενο µιας τάξης που επεκτείνει την τάξη AWTEvent. Τα αντικείµενα της τάξης αυτής περιέχουν πληροφορίες σχετικές µε το γεγονός που συνέβη, καθώς και την ταυτότητα της πηγής του. Το αντικείµενο-γεγονός χρησιµοποιείται για να προσδιορίσει τον τύπο του ακροατή προς τον οποίο πρέπει να διανεµηθεί το αντίστοιχο γεγονός. Ο τελευταίος µε τη σειρά του καθορίζει τη µέθοδο-χειριστή που πρέπει να κληθεί. 19.3.3 Ακροατές γεγονότων Ένας ακροατής γεγονότων ακούει ή αφουγκράζεται ορισµένους τύπους γεγονότων που προέρχονται από πηγές γεγονότων µέσα σ ένα πρόγραµµα και καλεί την κατάλληλη µέθοδο χειρισµού του κάθε γεγονότος που έχει συµβεί. Η χρήση ακροατών γεγονότων για την αντιµετώπιση αυτών είναι γνωστή ως µοντέλο

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 545 ανάθεσης γεγονότων (delegation event model): η αντιµετώπιση ενός γεγονότος ανατίθεται σ ένα ειδικό αντικείµενο, τον ακροατή γεγονότος. Όταν συµβαίνει ένα γεγονός, το γεγονός αυτό διανέµεται µόνο στους ακροατές γεγονότων που α- ντιστοιχούν στον τύπο του. Η διανοµή (dispatchnig) ενός γεγονότος έχει ως αποτέλεσµα την κλήση της ανάλογης µεθόδου χειρισµού κάθε εγγεγραµµένου ακροατή γεγονότος για τον τύπο του εν λόγω γεγονότος. Ένας ακροατής ενός γεγονότος Γ Χ είναι ένα αντικείµενο µιας τάξης που υλοποιεί µια ή περισσότερες διεπαφές ακροατών-γεγονότων από το πακέτο java. awt.event και το πακέτο javax.swing.event. Κάθε διεπαφή ακροατή γεγονότων προσδιορίζει µια ή περισσότερες µεθόδους χειρισµού γεγονότων που πρέπει να είναι ορισµένες σε µια τάξη που υλοποιεί τη διεπαφή αυτή 4. Ο Πίνακας 19.2 δείχνει την ιεραρχία µερικών από τις διεπαφές ακροατών γεγονότων του πακέτου java.awt.event. Με έντονα έχουν σηµειωθεί οι διεπαφές που θα περιγράψουµε στο κεφάλαιο αυτό. java.util.eventlistener java.awt.event.keylistenet java.awt.event.mouselistener java.awt.event.mousemotionlistener java.awt.event.mousewheellistener java.awt.event.actionlistener java.awt.event.adjustmentlistener java.awt.event.componentlistener java.awt.event.containerlistener java.awt.event.focuslistener java.awt.event.itemlistener java.awt.event.textlistener java.awt.event.windowlistener Πίνακας 19.2 Μερική ιεραρχία µερικών από τις διεπαφές γεγονότων του πακέτου java.awt.event. Κάθε τύπος γεγονότος έχει µια αντίστοιχη διεπαφή ακροατή γεγονότος. Για παράδειγµα τα γεγονότα τύπου KeyEvent τυγχάνουν χειρισµού από αντικείµενα τύπου KeyListener, τα γεγονότα τύπου MouseEvent τυγχάνουν χειρισµού από αντικείµενα τύπου MouseListener και MouseMotionListener, ενώ 4 Γιατί οι διεπαφές ορίζουν αφηρηµένες µεθόδους και η τάξη θα παραµένει αφηρηµένη και δε θα µπορεί να χρησιµοποιηθεί για να δηµιουργήσει αντικείµενα.

546 Προγραµµατισµός µε Java τα γεγονότα τύπου ActionEvent τυγχάνουν χειρισµού από αντικείµενα τύπου ActionListener. Στην περίπτωση ενός γεγονότος τύπου KeyEvent το γεγονός διανέµεται σε κάθε εγγεγραµµένο ακροατή τύπου KeyListener Το αναγνωριστικό του γεγονότος τύπου KeyEvent προσδιορίζει ποια µέθοδος-χειριστής των γεγονότων του πληκτρολογίου καλείται αυτόµατα. Στην περίπτωση ενός γεγονότος τύπου MouseEvent, το γεγονός διανέµεται σε κάθε εγγεγραµµένο ακροατή MouseListener ή Mouse- MotionListener, ανάλογα µε τον τύπο του γεγονότος που συµβαίνει. Το αναγνωριστικό του γεγονότος τύπου MouseEvent προσδιορίζει ποια µέθοδος-χειριστής (από τις επτά διαφορετικές µεθόδους χειρισµού γεγονότων του ποντικιού) καλείται αυτόµατα. Τέλος στην περίπτωση ενός γεγονότος τύπου ActionEvent, το γεγονός διανέµεται στη µέθοδο-χειριστή actionperformed κάθε εγγεγραµµένου ακροατή ActionListener (η actionperformed είναι η µόνη µέθοδος-χειριστής που υπάρχει στη διεπαφή ActionListener). Για να επεξεργαστεί κάποιο γεγονός, ο προγραµµατιστής πρέπει να κάνει τρία πράγµατα: Α) να δηλώσει ότι η τάξη χειρισµού του γεγονότος ή των γεγονότων είτε υλοποιεί µια διεπαφή ακροατή γεγονότων είτε επεκτείνει (κληρονοµεί) µια τάξη που υλοποιεί µια διεπαφή ακροατή γεγονότων Β) να εγγράψει έναν ή περισσότερους ακροατές γεγονότων στο συστατικό ή στα συστατικά της Γ Χ που αναµένεται να δηµιουργήσουν γεγονότα και Γ) να υλοποιήσει µια µέθοδο ή ένα σύνολο µεθόδων χειρισµού του γεγονότος ή των γεγονότων αυτών. 19.4 Η τάξη InputEvent Αυτή η (αφηρηµένη) τάξη είναι υπερτάξη των τάξεων KeyEvent και MouseEvent. Η τάξη InputEvent παρέχει τις µεθόδους isaltdown(), iscontroldown(), ismetadown() και isshiftdown() τις οποίες κληροδοτεί στις τάξεις KeyEvent και MouseEvent. Όλες αυτές οι µέθοδοι είναι δηµόσιες, τύπου boolean και, στην περίπτωση του πληκτρολογίου, επιστρέφουν την τιµή true, αν το πλήκτρο Alt, Ctrl, Meta ή Shift 5, αντίστοιχα, ήταν 5 Τα πλήκτρα Alt, Ctrl, Meta και Shift είναι γνωστά ως πλήκτρα τροποποίησης (modifier keys). Το πλήκτρο Meta µπορεί να διαφέρει από πληκτρολόγιο σε πληκτρολόγιο και χρησιµοποιείται σε ειδικές εφαρµογές, π.χ. στο συντάκτη κειµένου emacs.

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 547 πατηµένο όταν συνέβη το γεγονός, ειδάλλως επιστρέφουν την τιµή false. Η τάξη InputEvent παρέχει επίσης τη µέθοδο: public int getmodifiers() επιστρέφει τη σηµαία τροποποίησης (modifiers flag) του γεγονότος που συνέβη. Πιο συγκεκριµένα, επιστρέφει 1 αν το πλήκτρο Shift ήταν πατηµένο όταν συνέβη το γεγονός, 2 αν το πλήκτρο Ctrl ήταν πατηµένο, 8 αν το πλήκτρο Alt ήταν πατηµένο, 3 αν τα πλήκτρα Ctrl και Shift ήταν πατηµένα κ.λπ. 19.5 Χειρισµός γεγονότων του πληκτρολογίου Γεγονότα του πληκτρολογίου δηµιουργούνται όταν πλήκτρα αυτού πατιούνται ή αφήνονται. 19.5.1 Η τάξη KeyEvent Ένα γεγονός τύπου KeyEvent είναι χαµηλού επιπέδου και παράγεται από κάποιο συστατικό (π.χ. ένα αντικείµενο τύπου JTextField), όταν µέσα στα πλαίσια του συστατικού αυτού- ένα πλήκτρο του πληκτρολογίου πιέζεται ή αφήνεται ή όταν ένας χαρακτήρας του κώδικα UNICODE εισάγεται. Ένα τέτοιο γεγονός περνιέται σ όλα τα αντικείµενα τύπου KeyListener ή KeyAdapter (που υλοποιεί τη διεπαφή KeyListener, βλ. Κεφ. 19.7, παρακάτω), τα οποία είναι εγγεγραµµένα για να δέχονται γεγονότα αυτού του τύπου µε χρήση της µεθόδου addkeylistener του συστατικού (βλ. Κεφ. 18.2). Με τον τρόπο αυτό κάθε τέτοιο αντικείµενο ακροατής παίρνει το γεγονός, όταν αυτό συµβαίνει. Η τάξη KeyEvent παρέχει µια ακέραιη σταθερά κώδικα εικονικού πλήκτρου (virtual key code) για να παραστήσει το κάθε πλήκτρο του πληκτρολογίου (τα αναγνωριστικά όλων των σταθερών αυτών αρχίζουν µε τους χαρακτήρες VK_, π.χ. VK_J ή VK_HOME). Μερικές από τις µεθόδους της τάξης KeyEvent είναι: public int getkeycode () για ένα γεγονός πίεσης ή απελευθέρωσης πλήκτρου επιστρέφει τον ακέραιο κώδικα του πλήκτρου αυτού, ενώ για ένα γεγονός εµφάνισης χαρακτήρα επιστρέφει την τιµή VK_UNDEFINED public char getkeychar () επιστρέφει το χαρακτήρα του κώδικα UNICODE που αντιστοιχεί στο πλήκτρο που προκάλεσε το γεγονός αυτό ή την τιµή CHAR_UNDEFINED (στην περίπτωση που

548 Προγραµµατισµός µε Java δεν υπάρχει αντίστοιχος έγκυρος χαρακτήρας). Για παράδειγµα, η πληκτρολόγηση του πλήκτρου a έχοντας πατηµένο το πλήκτρο Shift, επιστρέφει την τιµή 'A' public static String getkeytext (int keycode) επιστρέφει µια συµβολοσειρά που περιγράφει τον κώδικα keycode του πλήκτρου που προκάλεσε το γεγονός, π.χ. "End", "F7", ή "C" public static String getkeymodifierstext(int modifiers) επιστρέφει µια συµβολοσειρά που περιγράφει τη σηµαία τροποποίησης (βλ. Κεφ. 19.4), π.χ. "Shift" όταν modifiers = 1 ή "Ctrl+Shift" όταν modifiers = 3 public boolean isactionkey() επιστρέφει την τιµή true αν το πλήκτρο που προκάλεσε το γεγονός είναι πλήκτρο ενέργειας (action key), π.χ. βελάκι, Home, End, Page Up, Page Down, F1-F12, Num Lock, Scroll Lock, Caps Lock και Pause, ειδάλλως επιστρέφει την τιµή false. 19.5.2 Η διεπαφή KeyListener Κάθε τάξη που επιθυµεί να επεξεργαστεί γεγονότα του πληκτρολογίου πρέπει είτε να υλοποιεί τη διεπαφή KeyListener (κι όλες τις µεθόδους της) είτε να επεκτείνει την αφηρηµένη τάξη KeyAdapter (βλ. Κεφ. 19.7, παρακάτω) και να ακυρώνει µόνο τις µεθόδους που την ενδιαφέρουν. Το αντικείµενο-ακροατής που δηµιουργείται από µια τέτοια τάξη εγγράφεται ακολούθως µε ένα συστατικό µε χρήση της µεθόδου addkeylistener του συστατικού αυτού (βλ. Κεφ. 18.2). Για κάθε γεγονός του πληκτρολογίου καλείται η ανάλογη µέθοδος-χειριστής της διεπαφής αυτής. Η διεπαφή KeyListener έχει τις παρακάτω µεθόδους, κάθε µια των οποίων έχει ως παράµετρο ένα αντικείµενο τύπου KeyEvent: public void keypressed (KeyEvent event) καλείται όταν πατηθεί κάποιο πλήκτρο του πληκτρολογίου public void keytyped (KeyEvent event) καλείται όταν πατηθεί ένα πλήκτρο του πληκτρολογίου που εµφανίζει κάποιο χαρακτήρα (π.χ. το πλήκτρο j, αλλά όχι το πλήκτρο Shift ή το πλήκτρο F1) public void keyreleased (KeyEvent event) καλείται όταν αφεθεί κάποιο πλήκτρο µετά από ένα γεγονός πίεσης ή εµφάνισης ενός χαρακτήρα.

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 549 Παράδειγµα 19.1 // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java (βλ. Κεφ. 17.3.2) import javax.swing.*; public class KeyDemo extends JFrame implements KeyListener { private JLabel instr, textpr, keypr, textre, keyre, textty, keyty; JPanel info; // βοηθητικό πανό // στήσε τη Γ Χ public KeyDemo () { super("επίδειξη γεγονότων του πληκτρολογίου"); // ετικέτα οδηγιών instr = new JLabel ("Πιέστε οποιοδήποτε πλήκτρο " + "του πληκτρολογίου..."); instr.setforeground (new Color (225, 23, 225)); // ποιο είναι το πλήκτρο που πατήθηκε textpr = new JLabel ("Το πλήκτρο που πατήθηκε: "); textpr.setforeground (new Color (225, 23, 225)); keypr = new JLabel (); keypr.setforeground (new Color (225, 23, 225)); // ποιος είναι ο χαρακτήρας που εισήχθη textty = new JLabel ("Ο χαρακτήρας που εισήχθη: "); textty.setforeground (new Color (225, 23, 225)); keyty = new JLabel (); keyty.setforeground (new Color (225, 23, 225)); // ποιο είναι το πλήκτρο που ελευθερώθηκε textre = new JLabel ("Το πλήκτρο που αφέθηκε: "); textre.setforeground (new Color (225, 23, 225)); keyre = new JLabel (); keyre.setforeground (new Color (225, 23, 225)); // πρόσθεσε όλες τις ετικέτες (εκτός από αυτή των // οδηγιών) στο πανό info = new JPanel (); info.setlayout (new GridLayout (3, 2));

550 Προγραµµατισµός µε Java info.setbackground (new Color (35, 98, 214)); info.add (textpr); info.add (keypr); info.add (textty); info.add (keyty); info.add (textre); info.add (keyre); Container c = getcontentpane (); c.setlayout (new FlowLayout()); c.setbackground (new Color (35, 98, 214)); // πρόσθεσε την ετικέτα οδηγιών και το πανό στον // υαλοπίνακα περιεχοµένων του πλαισίου c.add (instr); c.add (info); // να επιτρέψεις στο πλαίσιο να επεξεργαστεί τα // γεγονότα του πληκτρολογίου addkeylistener (this); setsize (350, 110); setvisible (true); } // KeyDemo // χειρίσου το πάτηµα οποιουδήποτε πλήκτρου public void keypressed (KeyEvent event) { if (event.getkeychar() == KeyEvent.CHAR_UNDEFINED) keypr.settext (event.getkeytext (event.getkeycode())); else keypr.settext ("" + event.getkeychar()); keyre.settext (""); keyty.settext (""); } // keypressed // χειρίσου την απελευθέρωση οποιουδήποτε πλήκτρου public void keyreleased (KeyEvent event) { if (event.getkeychar() == KeyEvent.CHAR_UNDEFINED) keyre.settext (event.getkeytext (event.getkeycode())); else keyre.settext ("" + event.getkeychar()); keypr.settext ("");

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 551 keyty.settext (""); } // keyreleased // χειρίσου την εισαγωγή ενός χαρακτήρα public void keytyped (KeyEvent event) { keyty.settext ("" + event.getkeychar()); keyre.settext (""); } // keytyped // εκτέλεσε την εφαρµογή public static void main( String args[] ) { KeyDemo application = new KeyDemo(); application.setdefaultcloseoperation (JFrame.EXIT_ON_CLOSE); } // main } // KeyDemo Τα αποτελέσµατα της εκτέλεσης του προγράµµατος της παραπάνω εφαρµογής παρουσιάζονται στην Εικόνα 15 του ένθετου του βιβλίου. 19.6 Χειρισµός γεγονότων του ποντικιού Γεγονότα του ποντικιού µπορούν να συµβούν σε οποιοδήποτε συστατικό Γ Χ προέρχεται από την τάξη java.awt.component, αν ο δροµέας του ποντικιού βρίσκεται µέσα στα φανερά όρια που έχει το συστατικό αυτό πάνω στην οθόνη. Τα γεγονότα του ποντικιού είναι χαµηλού επιπέδου και είναι αντικείµενα της τάξης MouseEvent 6. 19.6.1 Η τάξη MouseEvent Ένα γεγονός του ποντικιού (mouse event) παράγεται από κάποιο συστατικό ό- ταν: πιέζεται ένα κουµπί του ποντικιού αφήνεται ένα κουµπί του ποντικιού πιέζεται και αφήνεται ένα κουµπί του ποντικιού 6 Καθώς και της τάξης MouseWheelEvent, που δεν περιγράφεται στο βιβλίο αυτό.

552 Προγραµµατισµός µε Java ο δείκτης του ποντικιού µπαίνει στο φανερό µέρος της γεωµετρίας ενός συστατικού και ο δείκτης βγαίνει από το φανερό µέρος της γεωµετρίας ενός συστατικού. Ένα γεγονός κίνησης του ποντικιού (mouse motion event) παράγεται από κάποιο συστατικό όταν: το ποντίκι κινείται ή το ποντίκι σέρνεται. Ένα γεγονός της πρώτης κατηγορίας περνιέται σ όλα τα αντικείµενα τύπου MouseListener ή MouseAdapter (τα οποία υλοποιούν τη διεπαφή Mouse- Listener, βλ. Κεφ. 19.7, παρακάτω) που είναι εγγεγραµµένα σε κάποιο συστατικό -για να δέχονται γεγονότα του τύπου αυτού- µε χρήση της µεθόδου add- MouseListener του συστατικού (βλ. Κεφ. 18.2). Ένα γεγονός της δεύτερης κατηγορίας περνιέται σ όλα τα αντικείµενα τύπου MouseMotionListener ή MouseMotionAdapter (τα οποία υλοποιούν τη διεπαφή MouseMotionListener, βλ. Κεφ. 19.7, παρακάτω) που είναι εγγεγραµµένα για να δέχονται γεγονότα του τύπου αυτού µε χρήση της µεθόδου addmouselistener του συστατικού (βλ. Κεφ. 18.2). Με τον τρόπο αυτό κάθε αντικείµενο ακροατής παίρνει το γεγονός, όταν αυτό συµβαίνει. Κάθε µέθοδος χειρισµού ενός γεγονότος του ποντικιού παίρνει ως παράµετρο ένα αντικείµενο τύπου MouseEvent το οποίο περιέχει πληροφορίες σχετικές µε τον τύπο του γεγονότος που συνέβη. Η τάξη MouseEvent κληρονοµεί από την τάξη InputEvent, µεταξύ άλλων, και τις παρακάτω µεθόδους, οι οποίες εδώ έχουν και κάποια επιπλέον ιδιαίτερη σηµασία -εκτός αυτής που παρουσιάστηκε στο Κεφάλαιο 19.4. public boolean isaltdown() επιστρέφει true όταν ο χρήστης πατήσει το µεσαίο πλήκτρο ενός ποντικιού µε τρία πλήκτρα. Για να το επιτύχει αυτό µ ένα ποντίκι που έχει µόνο ένα ή δύο πλήκτρα, ο χρήστης µπορεί να πιέσει το πλήκτρο Alt του πληκτρολογίου και ταυτόχρονα το αριστερό πλήκτρο του ποντικιού public boolean ismetadown() επιστρέφει την τιµή true όταν ο χρήστης πατήσει το δεξί πλήκτρο ενός ποντικιού µε τρία πλήκτρα. Για να το επιτύχει αυτό µ ένα ποντίκι που έχει ένα µόνο πλήκτρο, ο χρήστης µπορεί να πιέσει το πλήκτρο Meta του πληκτρολογίου και ταυτόχρονα να πιέσει το πλήκτρο του ποντικιού. Μερικές από τις µεθόδους της τάξης MouseEvent είναι:

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 553 public int getbutton() επιστρέφει µια από τις στατικές σταθερές τύπου int NOBUTTON, BUTTON1, BUTTON2, BUTTON3 -που είναι δηλωµένες στην τάξη MouseEvent-, ανάλογα µε αν και ποιο κουµπί του ποντικιού άλλαξε κατάσταση public int getclickcount() επιστρέφει το πλήθος των φορών που πατήθηκε και αφέθηκε το κουµπί του ποντικιού σε αυτό το γεγονός (για να επιστρέψει η µέθοδος αυτή ακέραιο µεγαλύτερο του 1, πρέπει η χρονική απόσταση µεταξύ των διαδοχικών φορών να είναι σχετικά µικρή) public int getx() επιστρέφει την οριζόντια συντεταγµένη (x) της θέσης του ποντικιού σχετικά µε την αρχή του συστατικού public int gety() επιστρέφει την κατακόρυφη συντεταγµένη (y) της θέσης του ποντικιού σχετικά µε την αρχή του συστατικού 19.6.2 Η διεπαφή MouseListener Κάθε τάξη που επιθυµεί να επεξεργαστεί γεγονότα του ποντικιού (γεγονότα της πρώτης κατηγορίας) πρέπει είτε να υλοποιεί τη διεπαφή MouseListener (κι όλες της τις µεθόδους) είτε να επεκτείνει την αφηρηµένη τάξη MouseAdapter (βλ. Κεφ. 19.7, παρακάτω) και να ακυρώνει µόνο τις µεθόδους που την ενδιαφέρουν. Το αντικείµενο-ακροατής που δηµιουργείται από µια τέτοια τάξη εγγράφεται ακολούθως µε ένα συστατικό µε χρήση µε χρήση της µεθόδου addmouselistener του συστατικού αυτού (βλ. Κεφ. 18.2). Για κάθε γεγονός τέτοιου είδους καλείται η ανάλογη µέθοδος-χειρισµού της διεπαφής αυτής. Η διεπαφή Mouse- Listener έχει τις παρακάτω µεθόδους, κάθε µια των οποίων έχει ως παράµετρο ένα αντικείµενο τύπου MouseEvent: public void mousepressed (MouseEvent e) καλείται όταν πατηθεί ένα πλήκτρο του ποντικιού µε το δείκτη του ποντικιού να βρίσκεται πάνω στο συστατικό public void mouseclicked (MouseEvent e) καλείται όταν πατηθεί κι αφεθεί ένα πλήκτρο του ποντικιού πάνω στο συστατικό, χωρίς να έχει κινηθεί ο δείκτης του ποντικιού public void mousereleased (MouseEvent e)

554 Προγραµµατισµός µε Java καλείται όταν αφήνεται ένα κουµπί του ποντικιού, ενώ ο δείκτης του ποντικιού βρίσκεται πάνω στο συστατικό. Το γεγονός αυτό ακολουθεί πάντα ένα γεγονός που συµβαίνει όταν πατηθεί κάποιο πλήκτρο του ποντικιού (είτε έχει κινηθεί ο δείκτης του ποντικιού είτε όχι). public void mouseentered (MouseEvent e) καλείται όταν ο δροµέας του ποντικιού µπαίνει στα φυσικά όρια του συστατικού public void mouseexited (MouseEvent e) καλείται όταν ο δροµέας του ποντικού αφήνει (βγαίνει από) τα φυσικά όρια του συστατικού. Το συστατικό που αναφέρεται στις παραπάνω µεθόδους είναι εκείνο στο οποίο ο συγκεκριµένος ακροατής είναι εγγεγραµµένος. 19.6.3 Η διεπαφή MouseMotionListener Κάθε τάξη που επιθυµεί να επεξεργαστεί γεγονότα κίνησης του ποντικιού (γεγονότα της δεύτερης κατηγορίας) πρέπει είτε να υλοποιεί τη διεπαφή MouseMotionListener (κι όλες της τις µεθόδους) είτε να επεκτείνει την αφηρηµένη τάξη MouseMotionAdapter (βλ. Κεφ. 19.7, παρακάτω) και να ακυρώνει µόνο τις µεθόδους που την ενδιαφέρουν. Το αντικείµενο-ακροατής που δηµιουργείται από µια τέτοια τάξη εγγράφεται ακολούθως µε ένα συστατικό µε χρήση µε χρήση της µεθόδου addmousemotionlistener του συστατικού αυτού (βλ. Κεφ. 18.2). Για κάθε γεγονός τέτοιου είδους καλείται η ανάλογη µέθοδος της διεπαφής αυτής. Η διεπαφή MouseMotionListener έχει τις παρακάτω µεθόδους, κάθε µια των οποίων έχει ως παράµετρο ένα αντικείµενο τύπου MouseEvent: public void mousemoved (MouseEvent e) καλείται όταν το ποντίκι κινηθεί µε το δείκτη του να βρίσκεται πάνω στο συστατικό και χωρίς να πατηθεί οποιοδήποτε από τα κουµπιά του public void mousedragged (MouseEvent e) καλείται όταν πατιέται το αριστερό κουµπί του ποντικιού, ενώ ο δείκτης του βρίσκεται πάνω στο συστατικό, και στη συνέχεια, ενώ κρατιέται πατηµένο, το ποντίκι κινείται [η διαδικασία αυτή είναι γνωστή ως σύρσιµο (dragging) του ποντικιού]. Τέτοια γεγονότα παραδίδονται επαναληπτικά στο συστατικό (από το οποίο ξεκίνησε το γεγονός) µέχρι τη στιγµή που θα αφεθεί το κουµπί του ποντικιού που ήταν πατη- µένο (άσχετα µε το αν αυτό θα συµβεί εντός ή εκτός των ορίων του συστατικού).

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 555 Παράδειγµα 19.2 // επίδειξη γεγονότων του ποντικιού // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java import javax.swing.*; public class MouseDemo extends JFrame implements MouseListener, MouseMotionListener { private JLabel where, what; // στήσε τη Γ Χ και κάνε την εγγραφή των ακροατών // των γεγονότων του ποντικιού public MouseDemo () { super("επίδειξη γεγονότων του ποντικιού"); // πού είναι το ποντίκι (εντός ή εκτός πλαισίου) where = new JLabel(); where.setforeground (Color.WHITE); // τι κάνει το ποντίκι what = new JLabel (); what.setforeground (Color.white); Container c = getcontentpane(); c.add (where, BorderLayout.NORTH); c.add(what, BorderLayout.SOUTH); c.setbackground (new Color (147, 85, 106)); // η εφαρµογή "ακούει" τα δικά της γεγονότα του // ποντικιού addmouselistener (this); addmousemotionlistener (this); setsize (300, 100); setvisible (true); } // MouseDemo // χειριστές γεγονότων της MouseListener // χειρίσου το γεγονός που συµβαίνει όταν πατηθεί // και "αµέσως" αφεθεί κάποιο πλήκτρο του // ποντικιού

556 Προγραµµατισµός µε Java public void mouseclicked (MouseEvent event) { what.settext ("Κλικ στο σηµείο [" + event.getx() + ", " + event.gety() + "]"); } // mouseclicked // χειρίσου το γεγονός που συµβαίνει όταν πατηθεί // κάποιο πλήκτρο του ποντικιού public void mousepressed (MouseEvent event) { what.settext ("Πάτηµα στο σηµείο [" + event.getx() + ", " + event.gety() + "]"); } // mousepressed // χειρίσου το γεγονός που συµβαίνει όταν αφεθεί // κάποιο πλήκτρο του ποντικιού public void mousereleased (MouseEvent event) { what.settext ("Απελευθέρωση στο σηµείο [" + event.getx() + ", " + event.gety() + "]"); } // mousereleased // χειρίσου το γεγονός που συµβαίνει όταν το // ποντίκι "µπει στο πλαίσιο" public void mouseentered (MouseEvent event) { where.settext ("Το ποντίκι βρίσκεται µέσα στο" + " πλαίσιο"); } // mouseentered // χειρίσου το γεγονός που συµβαίνει όταν το // ποντίκι "βγει από το πλαίσιο" public void mouseexited (MouseEvent event) { where.settext ("Το ποντίκι βρίσκεται έξω από το " + "πλαίσιο"); what.settext (""); } // mouseexited // χειριστές γεγονότων της MouseMotionListener // χειρίσου το γεγονός που συµβαίνει όταν ο // χρήστης κουνάει το ποντίκι public void mousemoved (MouseEvent event) { what.settext("μετακίνηση στο σηµείο [" + event.getx() + ", " + event.gety() + "]" ); } // mousemoved

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 557 // χειρίσου το γεγονός που συµβαίνει όταν ο // χρήστης "σέρνει το ποντίκι" έχοντας πατηµένο // κάποιο πλήκτρο του public void mousedragged (MouseEvent event) { what.settext ("Σύρσιµο στο σηµείο [" + event.getx() + ", " + event.gety() + "]"); } // mousedragged // εκτέλεσε την εφαρµογή public static void main(string args[]) { MouseDemo application = new MouseDemo(); application.setdefaultcloseoperation (JFrame.EXIT_ON_CLOSE ); } // main } // MouseDemo 19.7 Τάξεις προσαρµογείς ή προσαρµοστικές τάξεις Πολλές από τις διεπαφές ακροατών γεγονότων, π.χ. οι MouseListener και MouseMotionListener, περιέχουν περισσότερες από µια µεθόδους. Είναι φανερό ότι δεν είναι πάντα επιθυµητό να ορίζουµε όλες τις µεθόδους που περιέχει µια διεπαφή ακροατή γεγονότων. Για παράδειγµα, ένα πρόγραµµα µπορεί να χρειάζεται να χρησιµοποιήσει µόνο τη µέθοδο mouseclicked από τη διεπαφή Mouse- Listener ή τη µέθοδο mousedragged από τη διεπαφή MouseMotion- Listener. Στην περίπτωση αυτή θα πρέπει να υλοποιήσει στοιχειωδώς (απλά γράφοντας την επικεφαλίδα και ένα κενό σώµα για την κάθε µία) και τις υπόλοιπες µεθόδους της αντίστοιχης διεπαφής, πράγµα το οποίο είναι (αν µη τι άλλο) χρονοβόρο. Για το λόγο αυτό, τα πακέτα java.awt.event και javax.swing.event παρέχουν τάξεις προσαρµογείς ακροατών γεγονότων. Μια τάξη προσαρµογέας ή προσαρµοστική τάξη (adapter class) υλοποιεί µια διεπαφή και παρέχει µια εξ ορισµού υλοποίηση (ένα κενό σώµα) για την κάθε µέθοδο µιας διεπαφής. Ο προγραµµατιστής µπορεί να επεκτείνει µια προσαρµοστική τάξη για να κληρονοµήσει την εξ ορισµού (µε κενό σώµα) υλοποίηση της κάθε µεθόδου και να ακυρώσει µόνο τη µέθοδο ή τις µεθόδους που χρειάζεται για το χειρισµό γεγονότων. Οι τάξεις προσαρµογείς που παρέχει το πακέτο java.awt.event, καθώς και οι διεπαφές που υλοποιούν δίνονται στον Πίνακα 19.3 (Με έντονα έχουν σηµειωθεί οι τάξεις και οι διεπαφές που περιγράφουµε στο κεφάλαιο αυτό).

558 Προγραµµατισµός µε Java Τάξη προσαρµογέας γεγονότων ComponentAdapter ContainerAdapter FocusAdapter KeyAdapter MouseAdapter MouseMotionAdapter WindowAdapter Υλοποιούµενη διεπαφή ComponentListener ContainerListener FocusListener KeyListener MouseListener MouseMotionListener WindowListener Πίνακας 19.3 Τάξεις προσαρµογείς και αντίστοιχες διεπαφές που υλοποιούν. Μια τάξη που υλοποιεί µια διεπαφή, έχει µια σχέση IS-A µε τη διεπαφή αυτή. Όλες οι άµεσες ή έµµεσες υποτάξεις της εν λόγω τάξης αυτής κληρονοµούν τη σχέση αυτή. Έτσι, ένα αντικείµενο µιας τάξης, που κληρονοµεί µια τάξη προσαρ- µογέα γεγονότων είναι ένα αντικείµενο του αντίστοιχου τύπου ακροατή γεγονότων (π.χ. ένα αντικείµενο µιας υποτάξης της τάξης MouseAdapter είναι ένα αντικεί- µενο τύπου MouseListener). 19.8 Χρήση εσωτερικών τάξεων για το χειρισµό γεγονότων Όπως είδαµε παραπάνω, για να χρησιµοποιήσουµε µια τάξη-προσαρµογέα πρέπει να δηµιουργήσουµε µια υποτάξη της, αντί να υλοποιήσουµε άµεσα µια διεπαφή ακροατή γεγονότων. Τι µπορούµε να κάνουµε στην περίπτωση που επιθυµούµε να επεκτείνουµε και κάποια άλλη τάξη εκτός της τάξης-προσαρµογέα; Για παράδειγµα, ας υποθέσουµε ότι γράφουµε µια εφαρµογή, που επεκτείνει την τάξη JFrame (ή µια µικροεφαρµογή που επεκτείνει την τάξη JApplet (βλ. Κεφ. 20), έστω, και επιθυµούµε η εφαρµογή (ή η µικροεφαρµογή) µας να περιέχει εντολές που χειρίζονται γεγονότα του ποντικιού, έστω. Εφόσον η Java δεν επιτρέπει πολλαπλή κληρονοµικότητα, η τάξη µας δεν µπορεί ταυτόχρονα να επεκτείνει την τάξη JFrame (JApplet) και την τάξη MouseAdapter. Η λύση είναι να χρησι- µοποιήσουµε µέσα στην τάξη JFrame (JApplet) µια εσωτερική τάξη (βλ. Κεφ. 17.1.2), η οποία να επεκτείνει (κληρονοµεί) την τάξη MouseAdapter! Για παράδειγµα, // ένα παράδειγµα χρήσης µιας επώνυµης εσωτερικής τάξης public class MyClass extends JFrame

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 559 {... kapoioantikeimeno.addmouselistener (new MyAdapter());... // ορισµός επώνυµης εσωτερικής τάξης class MyAdapter() extends MouseAdapter { public void mouseclicked (MouseEvent e) {... // ο χειριστής του γεγονότος γράφεται εδώ... } } // MyAdapter } // MyClass // το ίδιο παράδειγµα µε χρήση µιας ανώνυµης // εσωτερικής τάξης public class MyClass extends JFrame {... kapoioantikeimeno.addmouselistener (new MouseAdapter() // ορισµός της ανώνυµης εσωτερικής τάξης { public void mouseclicked (MouseEvent e) {... // ο χειριστής του γεγονότος γράφεται εδώ... } } // ανώνυµη εσωτερική τάξη } // MyClass Η χρήση ανώνυµων εσωτερικών τάξεων είναι καλύτερη από τη χρήση των επωνύµων, γιατί µας επιτρέπει να γράφουµε την υλοποίηση των ακροατών των γεγονότων µας στη γειτονία των εντολών που εγγράφουν αυτούς στα συστατικά των προγραµµάτων µας, ιδιαίτερα αν οι υλοποιήσεις αυτές περιέχουν λίγες εντολές.

560 Προγραµµατισµός µε Java Η χρήση εσωτερικών τάξεων λύνει ακόµα και το πρόβληµα που προκύπτει στην περίπτωση που οι χειριστές των γεγονότων µας χρειάζονται να προσπελάσουν ιδιωτικές υποστασιακές µεταβλητές της περιβάλλουσας (εξωτερικής) τάξης. Όπως αναφέραµε στο Κεφάλαιο 17.1.2 αν δε δηλώσουµε την εσωτερική µας τάξη ως τύπου static, τότε αυτή µπορεί να αναφέρεται στις υποστασιακές µεταβλητές της περιβάλλουσας τάξης της σαν οι εντολές της να βρίσκονταν µέσα στην τελευταία. Παράδειγµα 19.3 // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java import javax.swing.*; public class PaintApp extends JFrame { private int x = -10, y = -10; // στήσε τη Γ Χ και κάνε την εγγραφή του ακροατή // των γεγονότων του ποντικιού public PaintApp () { super("πίνακας Ζωγραφικής... "); // δηµιούργησε µια ετικέτα και βάλε τη στην περιοχή // SOUTH του διαχειριστή διάταξης BorderLayout getcontentpane().add(new Label ("Σύρε το ποντίκι για να σχεδιάσεις"), BorderLayout.SOUTH ); addmousemotionlistener ( // ανώνυµη εσωτερική τάξη new MouseMotionAdapter() { // αποθήκευσε τις συντεταγµένες της θέσης που // σέρνεται το ποντίκι και κάλεσε τη repaint // για να "ξαναβάψεις" public void mousedragged (MouseEvent event) { x = event.getx(); y = event.gety(); repaint(); } } // ανώνυµη εσωτερική τάξη

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 561 ); // addmousemotionlistener setsize (300, 200); setvisible (true); } // PaintApp // σχεδίασε µια έλλειψη µέσα σ ένα ορθογώνιο // διαστάσεων στη συγκεκριµένη θέση του παραθύρου public void paint (Graphics g) { // στο σηµείο αυτό δεν καλέσαµε επίτηδες τη µέθοδο // super.paint(g) για να αποτρέψουµε την // επανασχεδίαση g.setcolor (Color.RED); g.filloval (x, y, 4, 4); } // εκτέλεσε την εφαρµογή public static void main( String args[] ) { PaintApp application = new PaintApp(); application.setdefaultcloseoperation (JFrame.EXIT_ON_CLOSE); } // main } // PaintApp Η Εικόνα 16 του ένθετου του βιβλίου παρουσιάζει ένα παράδειγµα εκτέλεσης του προγράµµατος της παραπάνω εφαρµογής. 19.9 Χειρισµός σηµασιολογικών γεγονότων Όπως ήδη αναφέραµε, ένα σηµασιολογικό γεγονός που σηµατοδοτεί ότι έχει συµβεί µια ενέργεια πάνω σ ένα συστατικό µιας Γ Χ. Τα σηµασιολογικά γεγονότα δηµιουργούνται από συστατικά (π.χ. αντικείµενα τύπου JButton) όταν κάποια σχετική µε αυτά ενέργεια λάβει χώρα (π.χ. πατιούνται). Ένα τέτοιο γεγονός περνιέται σ όλα τα αντικείµενα τύπου ActionListener τα οποία είναι εγγεγραµ- µένα για να δέχονται γεγονότα αυτού του τύπου µε χρήση της µεθόδου addactionlistener του συστατικού (βλ. Κεφ. 18.4.2 και 18.4.4). Με τον τρόπο αυτό κάθε τέτοιο αντικείµενο ακροατής παίρνει το γεγονός, όταν αυτό συµβαίνει και δε χρειάζεται να γνωρίζει τις λεπτοµέρειες επεξεργασίας των γεγονότων του ποντικιού. Έτσι µπορεί να επεξεργαστεί γεγονότα που έχουν σηµασία (σηµασιολογικά), όπως πάτηµα κουµπιού.

562 Προγραµµατισµός µε Java 19.9.1 Η Τάξη ActionEvent Τα σηµασιολογικά γεγονότα είναι αντικείµενα της τάξης ActionEvent. Η τάξη αυτή 7 κληρονοµεί από την υπερτάξη της java.util.eventobject τη µέθοδο: public Object getsource() επιστρέφει το αντικείµενο στο οποίο δηµιουργήθηκε αρχικά το γεγονός. 19.9.2 Η ιεπαφή ActionListener Κάθε τάξη που επιθυµεί να χειριστεί ένα σηµασιολογικό γεγονός πρέπει να υ- λοποιεί τη διεπαφή ActionListener του πακέτου java.awt.event και τη (µοναδική της) µέθοδο actionperfomed. Το αντικείµενο-ακροατής που δη- µιουργείται από µια τέτοια τάξη εγγράφεται ακολούθως µε ένα συστατικό µε χρήση της µεθόδου addactionlistener του συστατικού αυτού. Όταν συµβεί ένα σηµασιολογικό γεγονός καλείται η µέθοδος actionperfomed που έχει επικεφαλίδα: public void actionperformed (ActionEvent γεγονός) και καλείται όταν συµβαίνει το γεγονός (στην περίπτωση που αναφέραµε, το πάτηµα ενός κουµπιού τύπου JButton). Παράδειγµα 19.4 Οι συγκεκριµένες περιοχές σχεδίασης βοηθούν στο διαχωρισµό της περιοχής σχεδίασης από την υπόλοιπη Γ Χ. Για παράδειγµα, αν θέλουµε να βεβαιωθούµε ότι τα γραφικά και η Γ Χ µας εµφανίζονται σωστά, µπορούµε να ξεχωρίσουµε τη Γ Χ και τα γραφικά µε το να δηµιουργήσουµε συγκεκριµένες περιοχές σχεδίασης ως υποτάξεις της τάξης JPanel. // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java import javax.swing.*; class DrawPanel extends JPanel 7 Όπως κι όλες οι υπόλοιπες τάξεις που περιγράψαµε στο κεφάλαιο αυτό.

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 563 { public final static int CIRCLE = 1, SQUARE = 2, LINE = 3; private int shape; // ανάλογα µε την τιµή της µεταβλητής shape σχεδίασε // έναν κύκλο, ένα τετράγωνο ή µία γραµµή public void paint (Graphics g) { // εδώ είναι απαραίτητη η εντολή αυτή, γιατί αλλιώς // θα εµφανίσει το νέο σχήµα χωρίς να εξαφανίσει το // παλιό super.paint (g); g.setcolor (new Color(148, 118, 171)); switch (shape) { case CIRCLE: g.filloval (30, 10, 60, 60); break; case SQUARE: g.fillrect (130, 10, 60, 60); break; case LINE: g.drawline (230, 10, 280, 60); break; default:; } } // paint // ζωγράφισε το σχήµα που προσδιορίζει η παράµετρος // shapetodraw public void draw (int shapetodraw) { shape = shapetodraw; repaint(); } // draw } // DrawPanel // δοκιµή της τάξης DrawPanel µε χρήση ενός // αντικειµένου της public class DrawPanelApp extends JFrame implements ActionListener { private JPanel buttons; // το πανό µε τα κουµπιά private DrawPanel mypanel; // το πανό σχεδίασης

564 Προγραµµατισµός µε Java private JButton circle, square, line; // τα κουµπιά // στήσε τη Γ Χ public DrawPanelApp () { super ("Σχεδιασµός Σχηµάτων"); // δηµιούργησε µια συγκεκριµένη περιοχή σχεδίασης mypanel = new DrawPanel(); mypanel.setbackground (new Color (169, 203, 143)); // το κουµπί "Τετράγωνο" square = new JButton ("Τετράγωνο"); square.setopaque (true); square.setbackground (new Color (169, 203, 143)); // πρόσθεσε έναν ακροατή ενεργείας στο κουµπί αυτό square.addactionlistener (this); // το κουµπί "Κύκλος" circle = new JButton ("Κύκλος"); circle.setopaque (true); circle.setbackground (new Color (169, 203, 143)); // πρόσθεσε έναν ακροατή ενεργείας στο κουµπί αυτό circle.addactionlistener (this); // το κουµπί "Γραµµή" line = new JButton ("Γραµµή"); line.setopaque (true); line.setbackground (new Color (169, 203, 143)); // πρόσθεσε έναν ακροατή ενεργείας στο κουµπί αυτό line.addactionlistener (this); // καθόρισε το πανό και πρόσθεσε του τα κουµπιά buttons = new JPanel (); buttons.setlayout (new FlowLayout ()); buttons.add (circle); buttons.add (square); buttons.add (line); buttons.setbackground (new Color (169, 203, 143)); // πρόσθεσε το πανό µε τα κουµπιά και την περιοχή //σχεδίασης στον υαλοπίνακα των περιεχοµένων του // πλαισίου Container container = getcontentpane(); container.add (mypanel, BorderLayout.CENTER);

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 565 } container.add (buttons, BorderLayout.SOUTH); setsize (300, 150); setvisible (true); public void actionperformed (ActionEvent e) { // αν πατήθηκε το κουµπί "Τετράγωνο" if (e.getsource() == square) // σχεδίασε ένα τετράγωνο mypanel.draw (DrawPanel.SQUARE); // αν πατήθηκε το κουµπί "Κύκλος" else if (e.getsource() == circle) // σχεδίασε έναν κύκλο mypanel.draw (DrawPanel.CIRCLE); // αν πατήθηκε το κουµπί "Γραµµή" else if (e.getsource() == line) // σχεδίασε µια γραµµή mypanel.draw (DrawPanel.LINE); } // actionperformed // εκτέλεσε την εφαρµογή public static void main( String args[] ) { DrawPanelApp application = new DrawPanelApp(); application.setdefaultcloseoperation (JFrame.EXIT_ON_CLOSE); } // main } // DrawPanelApp Η Εικόνα 17 του ένθετου του βιβλίου παρουσιάζει τα αποτελέσµατα της εκτέλεσης του προγράµµατος της παραπάνω εφαρµογής, ανάλογα µε το κουµπί που πατιέται. Ασκήσεις 19 1. Γράψτε µια εφαρµογή που να περιέχει µόνο ένα κουµπί. Κάθε φορά που ο χρήστης πατά το κουµπί αυτό, εκείνο θα πρέπει να αποκτά ως παρασκηνιακό χρώµα ένα οποιοδήποτε από τα προκαθορισµένα χρώµατα της τάξης Color (εκτός από ένα που µπορείτε να το χρησιµοποιήσετε ως προσκηνιακό χρώµα).

566 Προγραµµατισµός µε Java 2. Γράψτε µια εφαρµογή που να σχεδιάζει τρία ορθογώνια στην οθόνη. Κάθε φορά που ο χρήστης πατά κάποιο πλήκτρο του ποντικιού εντός των ορίων κάποιου σχήµατος, το σχήµα θα πρέπει να αλλάζει χρώµα, ενώ όταν το αφήνει το σχήµα θα πρέπει να επανέρχεται στο αρχικό του χρώµα (π.χ. από ανοιχτό σε πιο σκούρο και από σκούρο σε πιο ανοιχτό). 3. Γράψτε µια εφαρµογή που να επιτρέπει στο χρήστη να εισάγει κείµενο απευθείας στην οθόνη της (όχι, για παράδειγµα, µέσα σε κάποιο πεδίο κειµένου), όπως περίπου συµβαίνει και στους επεξεργαστές κειµένου. Προσπαθήστε να υλοποιήσετε στοιχειωδώς και το αποτέλεσµα της πληκτρολόγησης των χαρακτήρων Enter (αλλαγή γραµµής) και Backspace (οπισθοδρόµιση, δηλαδή σβήσιµο του τελευταίου χαρακτήρα που είχε πληκτρολογηθεί). Επίσης µε πίεση του πλήκτρου Esc (διαφυγή) θα πρέπει να σβήνονται όλες οι γραµµές του κειµένου στην οθόνη, έτσι ώστε ο χρήστης να µπορεί να πληκτρολογήσει το κείµενό του από την αρχή. Το κείµενο που θα µπορεί να πληκτρολογήσει ο χρήστης θα πρέπει να είναι µέχρι το πολύ τρεις γραµµές. Για ευκολία, µπορείτε να υποθέσετε ότι µπορεί να πηγαίνει µόνο σε επόµενη γραµµή (µε το πλήκτρο Enter) και όχι σε προηγούµενη γραµµή. ηλαδή από τη στιγµή που αλλάζουµε γραµµή, το κεί- µενο της προηγούµενης γραµµής δεν µπορεί να τροποποιηθεί (παρά µόνο µε τη διαγραφή όλων των γραµµών µε χρήση του πλήκτρου Esc). Προγράµµατα 19 1. Γράψτε µία εφαρµογή που να παίζει κρεµάλα (hangman) µε το χρήστη. Η κρυµµένη λέξη µπορεί να δίνεται στη γραµµή των εντολών από κάποιον (υποθετικά) άλλο χρήστη. Η εφαρµογή σας θα πρέπει στη συνέχεια να σχεδιάζει το περιβάλλον του παιχνιδιού και να περιµένει από το χρήστη να εισάγει γράµ- µατα. Η εισαγωγή γραµµάτων γίνεται απλώς µε την πίεση πλήκτρων από το χρήστη (όχι, για παράδειγµα, µε χρήση κάποιου πεδίου κειµένου). Η εφαρµογή σας θα πρέπει, λοιπόν, να ακούει τα γεγονότα του πληκτρολογίου και να αντιδρά κατάλληλα σε αυτά. Ο τρόπος που θα επιλέξετε να παρουσιάσετε γραφικά τη διαδικασία του παιχνιδιού (επιλογή λαθεµένου γράµµατος από τον παίκτη, εντοπισµός γράµµατος κ.λπ.) αφήνεται στην κρίση σας. 2. Ένα γραφείο συνοικεσίων διατηρεί έναν πίνακα πελατών. Για τον κάθε πελάτη υπάρχει: το ονοµατεπώνυµό του,

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 567 η διεύθυνση του, το φύλο του, η ηλικία του και Γράψτε µία εφαρµογή που να δέχεται τα στοιχεία ενός νέου πελάτη και να: i) εµφανίζει όλους τους υπάρχοντες πελάτες που είναι συµβατοί µε το νέο πελάτη. Η συµβατότητα προσδιορίζεται από το φύλο (υποθέτουµε ότι οι συµβατοί για κάποιον πελάτες πρέπει να είναι αντίθετου από αυτόν φύλου) και από την ηλικία (η διαφορά ηλικίας πρέπει να είναι το πολύ 10 χρόνια!) και ii) προσθέτει το νέο πελάτη στο πίνακα πελατών του γραφείου. 3. Soundex είναι µια µέθοδος που κωδικοποιεί ονόµατα µε τέτοιο τρόπο, ώ- στε, αν διαφέρουν λίγο µεταξύ τους, η κωδικοποίηση τους είναι πιθανό να είναι η ίδια. Η κωδικοποίηση βασίζεται στη φωνητική οµαδοποίηση των χαρακτήρων ως εξής: οµάδα 0: οµάδα 1: οµάδα 2: οµάδα 3: οµάδα 4: οµάδα 5: οµάδα 6: A, Ε, Ι, O, U, H, W, Y κι όλοι οι χαρακτήρες που δεν είναι γράµµατα B, F, P, V C, G, J, K, Q, S, X, Z D, T L M, N R Οι χαρακτήρες ενός ονόµατος κωδικοποιούνται αρχικά ως ψηφία, ανάλογα µε την οµάδα στην οποία ανήκουν. Έτσι, το όνοµα SCHMIDT κωδικοποιείται ως 2205033, ενώ το SMITH ως 25030. Κατόπιν, τα διαδοχικά ψηφία του αριθ- µητικού κώδικα που είναι ίδια αντικαθιστούνται µε ένα µόνο ψηφίο και τέλος διαγράφονται όλα τα '0'. Έτσι, τα παραπάνω δύο ονόµατα καταλήγουν να έχουν τον ίδιο κώδικα 253. Γράψτε µία εφαρµογή η οποία να δέχεται ένα κείµενο από το χρήστη και να εµφανίζει το αντίστοιχο κωδικοποιηµένο µε τη µέθοδο Soundex. Οι κώδικες των λέξεων θα πρέπει να χωρίζονται µεταξύ τους όπως ακριβώς και οι λέξεις του κει- µένου.

568 Προγραµµατισµός µε Java Απαντήσεις 19 1. // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java import javax.swing.*; public class RandomBackground extends JFrame implements ActionListener { JButton a_button; // ένας πίνακας µε όλα τα προκαθορισµένα χρώµατα της // τάξης Color εκτός από το µαύρο που θα χρησιµοποιήσουµε // ως προσκηνιακό χρώµα Color colors[] = {Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE, Color.YELLOW}; public RandomBackground () { super ("Ένα απλό κουµπί..."); a_button = new JButton ("Πάτησέ µε"); a_button.setopaque (true); // τυχαίο παρασκηνιακό χρώµα a_button.setbackground (colors[(int)(math.random() * 12)]); a_button.setforeground (Color.BLACK); a_button.setfont (new Font ("Arial", Font.BOLD, 24)); a_button.addactionlistener (this); getcontentpane ().add (a_button); setsize (200, 200); setvisible (true); } // RandomBackground public void actionperformed (ActionEvent e) { // επιλογή τυχαίου παρασκηνιακού χρώµατος a_button.setbackground (colors[(int)(math.random() * 12)]); } // actionperformed

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 569 public static void main (String args[]) { RandomBackground app = new RandomBackground (); app.setdefaultcloseoperation (EXIT_ON_CLOSE); } // main } // RandomBackground Ένα τυχαίο στιγµιότυπο από την εκτέλεση του προγράµµατος της παραπάνω εφαρµογής δίνεται στην Εικόνα 18 του ένθετου του βιβλίου. 2. // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java import javax.swing.*; public class ChangeColor extends JFrame { // όλα τα απαραίτητα για τη σχεδίαση των ορθογωνίων Point points[] = {new Point(50, 50), new Point(300, 70), new Point (50, 150)}; // βλ. Παράδ. 9.5 int widths[] = {100, 50, 200}; int heights[] = {50, 200, 150}; Color colors[] = {Color.blue, Color.yellow, Color.red}; public ChangeColor () { super ("Κάνε κλικ και άλλαξε τα χρώµατα..."); addmouselistener (new MouseAdapter () { public void mousepressed (MouseEvent e) // όταν πατηθεί κάποιο κουµπί του ποντικιού { // αν για κάποιο από τα ορθογώνια for (int i = 0; i < 3; i++) { // το κουµπί έχει πατηθεί εντός των ορίων του if (e.getx() > points[i].getx() && e.getx() < (points[i].getx() + widths[i])) if (e.gety() > points[i].gety() && e.gety() < (points[i].gety() + heights[i])) // κάνε το χρώµα του πιο σκούρο colors[i] = colors[i].darker(); } repaint ();

570 Προγραµµατισµός µε Java } // mousepressed public void mousereleased (MouseEvent e) // όταν αφεθεί κάποιο κουµπί του ποντικιού { // αν για κάποιο από τα ορθογώνια for (int i = 0; i < 3; i++) { // το κουµπί έχει πατηθεί εντός των ορίων του if (e.getx() > points[i].getx() && e.getx() < (points[i].getx() + widths[i])) if (e.gety() > points[i].gety() && e.gety() < (points[i].gety() + heights[i])) // επανάφερε το αρχικό του χρώµα // επειδή για να αφεθεί ένα πλήκτρο του // ποντικιού πρέπει πρώτα να έχει πατηθεί (το // χρώµα του έχει γίνει πιο σκούρο), αρκεί να // το κάνουµε πιο ανοιχτό για να το // επαναφέρουµε colors[i] = colors[i].brighter(); } repaint (); } // mousereleased }); setsize (400, 350); setvisible (true); } // ChangeColor public void paint (Graphics g) { // σχεδίασε τα τρία ορθογώνια for (int i = 0; i < 3; i++) { g.setcolor (colors[i]); g.fillrect (points[i].getx(), points[i].gety(), widths[i], heights[i]); } } // paint public static void main (String args[]) { ChangeColor app = new ChangeColor(); app.setdefaultcloseoperation (EXIT_ON_CLOSE); } // main } // ChangeColor

Κεφάλαιο 19: Γεγονότα και Γεγονοστρεφής Προγραµµατισµός 571 3. // βασικά πακέτα της Java import java.awt.*; import java.awt.event.*; // πακέτα επέκτασης της Java import javax.swing.*; public class EditorApp extends JFrame { // οι γραµµές του κειµένου StringBuffer lines[] = new StringBuffer [3]; int current_line = 0; boolean finished = false; public EditorApp () { super ("Πληκτρολόγησε το κείµενό σου..."); for (int j = 0; j < 3; j++) lines[j] = new StringBuffer(); addkeylistener (new KeyAdapter () { public void keypressed (KeyEvent e) { // αν πατήθηκε το πλήκτρο Enter και δεν έχουν // εξαντληθεί οι γραµµές if (e.getkeycode() == KeyEvent.VK_ENTER &&!finished) { if (current_line == 2) finished = true; else current_line++; } // αν πατήθηκε το πλήκτρο Backspace και δεν // έχουν εξαντληθεί οι γραµµές else if (e.getkeycode() == KeyEvent.VK_BACK_SPACE &&!finished) { // αν υπάρχουν χαρακτήρες να διαγράψουµε if (lines[current_line].length() > 0) // διάγραψε τον τελευταίο χαρακτήρα lines[current_line].deletecharat (lines[current_line].length()-1); } // αν πατήθηκε το πλήκτρο Esc

572 Προγραµµατισµός µε Java else if (e.getkeycode() == KeyEvent.VK_ESCAPE) { current_line = 0; for (int j = 0; j < 3; j++) lines[j].delete (0, lines[j].length()); finished = false; } // αν πατήθηκε οποιοδήποτε άλλο πλήκτρο και δεν // έχουν εξαντληθεί οι γραµµές else if (!finished) lines[current_line].append (e.getkeychar()); repaint (); } // keypressed }); setsize (450, 200); setvisible (true); getcontentpane().setbackground (new Color (128, 128, 192)); } // EditorApp public void paint (Graphics g) { super.paint (g); g.setcolor (Color.WHITE); g.setfont (new Font ("Comic Sans MS", Font.BOLD, for (int i = 0; i < 3; i++) g.drawstring (new String(lines[i]), 50, 50+50*i); } // paint public static void main (String args[]) { EditorApp app = new EditorApp (); app.setdefaultcloseoperation (EXIT_ON_CLOSE); } // main } // EditorApp 20)); Ένα στιγµιότυπο της εκτέλεσης του προγράµµατος της παραπάνω εφαρµογής δίνεται στην Εικόνα 19 του ένθετου του βιβλίου.