9. Η βιβλιοθήκη Components του AWT Τελειώνοντας αυτό το κεφάλαιο θα μπορείτε: Να αναγνωρίζετε τα βασικά components του AWT Να χρησιμοποιείτε AWT components για να δημιουργείτε διεπαφές χρηστών για πραγματικά προγράμματα Να ελέγχετε τα χρώματα και τις γραμματοσειρές που χρησιμοποιούνται από ένα AWT component 9.1 Διευκολύνσεις του AWT Το AWT παρέχει ένα πλήθος προτύπων διευκολύνσεων (standard facilities). Το κεφάλαιο αυτό θα παρουσιάσει τα διαθέσιμα components και θα αναφέρει πιθανά προβλήματα τα οποία θα πρέπει να γνωρίζετε. Αρχικά περιγράφονται τα components. Αυτά χρησιμοποιούνται για τη δημιουργία διεπαφών χρήστη. Σαφώς πρέπει να γνωρίζετε όλο το σύνολο των UI components ώστε να μπορείτε να επιλέξετε τα κατάλληλα όταν φτιάχνετε τις δικές σας διεπαφές. Τα AWT components παρέχουν μηχανισμούς για έλεγχο της εμφάνισής τους, συγκεκριμένα σε ό,τι αφορά το χρώμα και τη γραμματοσειρά που χρησιμοποιείται για την εμφάνιση κειμένου. Επιπρόσθετα το AWT υποστηρίζει εκτύπωση. Είναι μία διευκόλυνση που προστέθηκε με τη μετάβαση στο JDK 1.1. 9.2 Buttons Έχουμε ήδη συναντήσει το component Button. Παρέχει ένα βασικό component τύπου «πίεσε για να ενεργοποιηθεί» για τη διεπαφή χρήστη. Μπορεί να δημιουργηθεί με μία ετικέτα κειμένου που λειτουργεί ως οδηγία για το χρήστη σχετικά με τη χρήση του. Button b = new Button( Sample ); add(b); Για αντίδραση κατά την πίεση του button χρησιμοποιείται η διεπαφή ActionListener. Η μέθοδος getactioncommand() του ActionEvent που προκύπτει όταν πιέσουμε το button, επιστρέφει εξ ορισμού τη συμβολοσειρά της ετικέτας. Αυτό μπορεί να αλλάξει με χρήση της εντολής setactioncommand() του Button. 9.3 Checkboxes Το checkbox παρέχει μία απλή συσκευή «on/off» με μία ετικέτα κειμένου δίπλα της. Checkbox one = new Checkbox( One, false); Checkbox two = new Checkbox( Two, false); Checkbox three = new Checkbox( Three, true); 1
add(one); add(two); add(three); Η επιλογή ή απο-επιλογή ενός checkox γνωστοποιείται στη διεπαφή ItemInterface. Το ItemEvent που μεταβιβάζεται δηλώνει αν η πράξη ήταν επιλογή ή απο-επιλογή από ένα checkbox με χρήση της μεθόδου getstatechange(). Η μέθοδος επιστρέφει μία από τις σταθερές ItemEvent.DESELECTED και ItemEvent.SELECTED, ανάλογα με το τι είναι κατάλληλο. Η μέθοδος getitem() επιστρέφει ένα αντικείμενο String που αναπαριστά τη συμβολοσειρά ετικέτα του checkbox που επηρεάζεται. class Handler implements ItemListener { public void itemstatechanged(itemevent ev) { String state = deselected ; if (ev.getstatechange() == ItemEvent.SELECTED) { state = selected ; System.out.println(ev.getItem() + + state); 9.4 CheckboxGroups Radio buttons Μπορείτε να δημιουργείτε checkboxes με μία ειδική συνάρτηση δημιουργίας η οποία δέχεται ένα επιπλέον όρισμα, ένα CheckboxGroup. Αν το κάνετε αυτό, τότε αλλάζει η εμφάνιση των check boxes και όλα τα checkboxes που σχετίζονται με το ίδιο checkbox group θα παρουσιάζουν συμπεριφορά radio button. CheckboxGroup cbg = new CheckboxGroup(); Checkbox one = new Checkbox( One, cbg, false); Checkbox two = new Checkbox( Two, cbg, false); Checkbox three = new Checkbox( Three, cbg, true); add(one); add(two); add(three); 9.5 Choice Η choice παρέχει μία απλή είσοδο τύπου «επιλογή ενός από μία λίστα». Choice c = new Choice(); c.additem( First ); c.additem( Second ); c.additem( Third ); 2
add(c); Όταν κάνουμε κλικ πάνω στο choice, παρουσιάζει μία λίστα των στοιχείων που έχουν προστεθεί σε αυτό. Παρατηρήστε ότι τα στοιχεία προστίθενται ως αντικείμενα String. Η διεπαφή ItemListener χρησιμοποιείται για να παρατηρούμε τις αλλαγές στο choice. Οι λεπτομέρειες είναι οι ίδιες όπως με τα checkbox. 9.6 Canvas Ένα Canvas παρέχει ένα κενό (με το χρώμα του φόντου) χώρο. Έχει επιθυμητό μέγεθος μηδέν επί μηδέν, συνεπώς στη γενική περίπτωση θα πρέπει να βεβαιωθείτε ότι ο layout manager θα του δώσει μη μηδενικό μέγεθος. Ο χώρος μπορεί να χρησιμοποιηθεί για ζωγραφική, ή για να γράψετε κείμενο, ή για να λαμβάνετε είσοδο από το πληκτρολόγιο ή το ποντίκι. Στη συνέχεια θα δούμε πώς μπορείτε να σχεδιάζετε αποτελεσματικά στο AWT. Γενικά ο Canvas χρησιμοποιείται είτε ως έχει για να παρέχει ένα γενικευμένο χώρο σχεδίασης ή χρησιμοποιείται ως η βάση ανάπτυξης για να παρέχουμε μία περιοχή εργασίας για ένα custom component. Ο Canvas μπορεί να «ακούει» για όλα τα συμβάντα που εφαρμόζονται σε ένα γενικευμένο component. Συγκεκριμένα μπορεί να θέλετε να προσθέσετε αντικείμενα KeyListener, MouseMotionListener ή MouseListener για να του επιτρέψετε να αντιδρά με συγκεκριμένο τρόπο στην είσοδο από το χρήστη. Οι μέθοδοι στις διεπαφές αυτές λαμβάνουν αντίστοιχα KeyEvent και MouseEvent. Σημείωση Για να λάβουμε συμβάντα πληκτρολογίου σε ένα canvas είναι απαραίτητο να καλέσουμε τη μέθοδο requestfocus() του canvas. Αν δεν γίνει αυτό, γενικά δε θα είναι δυνατό να «κατευθύνουμε» την πληκτρολόγηση στο Canvas. Αντίθετα η πληκτρολόγηση θα πηγαίνει σε άλλο component ή ακόμα μπορεί να χάνεται. Ο κώδικας που ακολουθεί παρουσιάζει ακριβώς αυτό. 3
Ακολουθεί ένα παράδειγμα ενός Canvas import java.awt.*; import java.awt.event.*; import java.util.*; public class MyCanvas implements KeyListener, MouseListener { Canvas c; String s = ; public static void main(string args[]) { Frame f = new Frame( Canvas ); MyCanvas mc = new MyCanvas(); mc.c = new Canvas(); f.add( Center, mc.c); f.setsize(150, 150); mc.c.addmouselistener(mc); mc.c.addkeylistener(mc); f.setvisible(true); public void keytyped (KeyEvent ev) { System.out.println( keytyped ); s += ev.getkeychar(); // Not a good drawing technique!! c.getgraphics().drawstring(s, 0, 20); public void mouseclicked(mouseevent ev) { System.out.println( mouseclicked ); // force the focus onto the canvas c.requestfocus(); public void keypressed(keyevent ev) { System.out.println( keypressed ); public void keyreleased(keyevent ev) { System.out.println( keyreleased); public void mousepressed(mouseevent ev) { System.out.println( mousepressed ); 4
public void mousereleased(mouseevent ev) { System.out.println( mousereleased); public void mouseentered(mouseevent ev) { System.out.println( mouseentered ); public void mouseexited(mouseevent ev) { System.out.println( mouseexited ); 9.7 Label Ένα αντικείμενο Label απλά παρουσιάζει μία γραμμή κειμένου. Το πρόγραμμα μπορεί να αλλάξει το κείμενο, αλλά όχι ο χρήστης. Δεν υπάρχουν ειδικά όρια ή άλλα είδη decoration για το διαχωρισμό ενός label. Label l = new Label( Hello ); add(l); Τα Labels συνήθως δεν αναμένεται ότι θα χειρίζονται συμβάντα, αλλά το κάνουν όπως και ο canvas. Δηλαδή οι πληκτρολογήσεις μπορούν να «συλληφθούν» καλώντας τη requestfocus(). 9.8 TextField Το TextField είναι μία συσκευή εισόδου κειμένου σε μία γραμμή. TextField f = new TextField( Single line, 30); add(f); Επειδή μόνο μία γραμμή είναι δυνατή, μπορεί να ενημερωθεί ένας ActionListener μέσω της actionperformed() σχετικά με το πότε πατήθηκε το πλήκτρο Enter ή Return. Επίσης μπορούν να προστεθούν εφόσον είναι επιθυμητό και άλλο component listeners. Όπως και η text area, μπορεί να τεθεί για ανάγνωση μόνο. Δεν παρουσιάζει scrollbars σε οποιαδήποτε κατεύθυνση, αλλά μπορεί να κάνει scroll για μεγάλα κείμενα δεξιά ή αριστερά αν είναι απαραίτητο. 5
9.9 TextArea Η TextArea είναι μία συσκευή εισόδου κειμένου με πολλές γραμμές και πολλές στήλες. Μπορείτε να την κάνετε μη editable με χρήση της μεθόδου seteditable(boolean), οπότε γίνεται κατάλληλη για browsing κειμένου. Παρουσιάζει οριζόντιες και κάθετες scrollbars. TextArea t = new TextArea( Initial text, 4, 30); add(t); Μπορείτε να προσθέσετε γενικούς component listeners σε μία text area, αλλά επειδή το κείμενο είναι πολλών γραμμών, πιέζοντας το πλήκτρο Enter απλά τοποθετούμε ακόμα ένα χαρακτήρα στην ενδιάμεση μνήμη (buffer). Αν χρειάζεται να αναγνωρίζετε «ολοκλήρωση εισόδου» μπορείτε να τοποθετήσετε ένα button που δηλώνει Apply ή Commit δίπλα στην text area ώστε να επιτρέψετε στο χρήστη να το δηλώσει. 9.9.1. TextComponent Τόσο η text area όσο και το text field τεκμηριώνονται σε δύο σημεία. Αν αναζητήσετε μία κλάση με το όνομα TextComponent θα βρείτε ότι πολλές από τις ουσιώδεις μεθόδους τεκμηριώνονται σε αυτή. Αυτό ισχύει γιατί τόσο η TextArea όσο και η TextField είναι υποκλάσεις της TextComponent. Η ιδέα αυτή θα παρουσιαστεί στη συνέχεια. Έχετε δει ότι οι συναρτήσεις δημιουργίας για αμφότερες τις κλάσεις TextArea και TextField σάς επιτρέπουν να καθορίζεται το πλήθος των στηλών για παρουσίαση. Να θυμάστε ότι το μέγεθος του παρουσιαζόμενου component είναι ευθύνη του layout manager, συνεπώς οι προτιμήσεις αυτές μπορεί να αγνοηθούν. Επιπρόσθετα, το πλήθος των στηλών διερμηνεύεται με όρους του μέσου πλάτους των χαρακτήρων της γραμματοσειράς που χρησιμοποιείται. Το πλήθος των χαρακτήρων που θα παρουσιαστούν τελικά μπορεί να διαφέρει σημαντικά αν χρησιμοποιηθεί αναλογική γραμματοσειρά (proportional spaced font). 9.10 List Μία List σάς επιτρέπει να παρουσιάζετε επιλογές ως κείμενο στο χρήστη, οι οποίες παρουσιάζονται σε μία περιοχή η οποία επιτρέπει την εμφάνιση πολλών στοιχείων ταυτόχρονα. Η List είναι scrollable και μπορεί να υποστηρίξει είτε απλή είτε πολλαπλή κατάσταση επιλογής. List l = new List(4, true); 6
Το αριθμητικό όρισμα στη συνάρτηση δημιουργίας δηλώνει το προτιμούμενο ύψος της λίστας των στοιχείων με βάση το πλήθος των ορατών γραμμών. Όπως πάντα, να θυμάστε ότι αυτό μπορεί να αλλάξει από τον layout manager. Το boolean όρισμα δηλώνει αν η λίστα θα πρέπει να επιτρέπει ή όχι στο χρήστη να κάνει πολλαπλές επιλογές. Σε αμφότερες τις καταστάσεις επιλογής, απλή και πολλαπλή, παράγεται ένα ActionEvent, το οποίο λαμβάνει η διεπαφή ActionListener. Τα στοιχεία επιλέγονται από τη λίστα σύμφωνα με τις συμβάσεις της πλατφόρμας. Για περιβάλλον Unix/Motif σημαίνει ότι ένα απλό κλικ θα επιλέξει μία καταχώρηση στη λίστα, αλλά χρειάζεται διπλό κλικ για να ενεργοποιηθεί η πράξη στη λίστα. 9.11 Frame Πρόκειται για το γενικού σκοπού παράθυρο «πρώτου επιπέδου» (top-level). Έχει decorations τύπου window manager, όπως μπάρα τίτλου και χειριστήρια για αλλαγή μεγέθους. Frame f = new Frame( Frame ); Το μέγεθος ενός frame μπορεί να τεθεί με χρήση της μεθόδου setsize(). Όμως, στη γενική περίπτωση θα πρέπει να τίθεται με χρήση της μεθόδου pack(). Αυτή προκαλεί το layout manager να υπολογίσει ένα μέγεθος που θα περικλείει με «ωραίο» τρόπο όλα τα components του frame. Το μέγεθος του frame τίθεται στη συνέχεια ανάλογα. Τα συμβάντα ενός frame μπορούν να παρακολουθούνται με χρήση όλων των listeners που εφασμόζονται σε γενικά components. Μπορούμε να χρησιμοποιήσουμε το WindowListener, μέσω της μεθόδου windowclosing(), ώστε να αναγνωρίσουμε ότι έχει πιεστεί το quit button στο window manager menu. Δε θα πρέπει να προσπαθείτε να «ακούσετε» τα συμβάντα του πληκτρολογίου, απ ευθείας από το frame. Αν και ορισμένες φορές λειτουργεί η τεχνική που αναφέρθηκε στα components canvas και label, με την κλήση της requestfocus() δηλαδή, δεν είναι αξιόπιστη. Αν χρειάζεται να παρακολουθείτε τα συμβάντα πληκτρολόγησης θα πρέπει να προσθέσετε ένα canvas, ένα panel ή κάτι αντίστοιχο, στο frame και να προσθέσετε το listener στο εσωτερικό component. 7
9.12 Panel Πρόκειται για container γενικού σκοπού. Δεν μπορεί να χρησιμοποιηθεί αυτόνομα, σε αντίθεση με τα frames, τα windows και τα dialogs. Panel p = new Panel(); Από τη στιγμή που ένα Panel δεν μπορεί να παρουσιαστεί, δεν υπάρχει διαθέσιμο και screen shot του. Τα Panels μπορούν να χειρίζονται συμβάντα, με την προϋπόθεση ότι πρέπει να αιτηθούν ρητά την εστίαση του πληκτρολογίου, όπως και με το παράδειγμα του canvas που ήδη αναφέραμε. 9.13 Dialog Ένα Dialog είναι παρόμοιο με ένα Frame, από την άποψη ότι πρόκειται για αυτόνομο παράθυρο με ορισμένα decorations. Διαφέρει από ένα frame από την άποψη ότι έχει λιγότερα decorations και ότι μπορείτε να αιτηθείτε ένα modal dialog, οπότε αποτρέπει όλες τις μορφές εισόδου μέχρι να το κλείσετε. Dialog d = new Dialog(f, Dialog, false); d.add( Center, new Label( Hello, I m a Dialog )); d.pack(); Τα Dialogs στη γενική περίπτωση δεν είναι άμεσα ορατά στο χρήστη μόλις δημιουργηθούν. Συνήθως «παρουσιάζονται» ως αντίδραση σε κάποια άλλη πράξη της διεπαφής χρήστη, όπως πίεση ενός button. public void actionperformed(actionevent ev) { d.setvisible(true); Σημείωση Θα πρέπει να χρησιμοποιείτε ένα Dialog ως επαναχρησιμοποιήσιμη συσκευή. Δηλαδή, δε θα πρέπει να καταστρέφετε ένα αντικείμενο όταν αυτό φεύγει από την οθόνη, αλλά να το κρατάτε για μεταγενέστερη χρήση. Η ύπαρξη του συλλογέα απορριμμάτων βοηθάει στο να «ξοδεύουμε» μνήμη, αλλά να θυμάστε ότι η δημιουργία και η αρχικοποίηση αντικειμένων χρειάζεται χρόνο και δε θα πρέπει να γίνεται χωρίς να υπάρχει κάποιος λόγος. Για να κρύψετε ένα Dialog, πρέπει να καλέσετε πάνω του την setvisible(false). Αυτό συνήθως γίνεται από το WindowListener που είναι προσκολλημένος πάνω του και περιμένει την κλήση στη μέθοδο windowclosing() του συγκεκριμένου listener. Η διαδικασία αυτή είναι παράλληλη με αυτή του κλεισίματος ενός frame. 9.14 FileDialog Είναι μία υλοποίηση μίας συσκευής επιλογής αρχείων. Έχει το δικό του αυτόνομο παράθυρο, με decorations και επιτρέπει στο χρήστη να κάνει browse στο σύστημα αρχείων και να επιλέξει ένα συγκεκριμένο αρχείο για περαιτέρω πράξεις. FileDialog d = new FileDialog(f, FileDialog ); 8
d.setvisible(true); String fname = d.getfile(); Εν γένει, δεν είναι απαραίτητο να χειρίζεστε συμβάντα από ένα FileDialog. Η κλήση στη setvisible(true) απενεργοποιείται μέχρι ο χρήστης να επιλέξει OK, οπότε και εσείς απλά ζητάτε το όνομα του αρχείου που επιλέχθηκε. Αυτό επιστρέφεται ως String. 9.15 ScrollPane Αυτό παρέχει ένα γενικευμένο container που δεν μπορεί να χρησιμοποιηθεί αυτόνομα. Παρέχει ένα viewport σε μία μεγαλύτερη περιοχή και scrollbars για τη διαχείριση αυτού του viewport. Frame f = new Frame( ScrollPane ); Panel p = new Panel(); ScrollPane sp = new ScrollPane(); p.setlayout(new GridLayout(3,4)); sp.add(p); f.add(sp); f.setsize(200, 200); f.setvisible(true); Το ScrollPane δημιουργεί και χειρίζεται τα scroll bars όπως είναι απαραίτητο. «Κρατά» ένα μόνο component και δεν μπορείτε να επιλέξετε το layout manager που χρησιμοποιεί. Αντ αυτού θα πρέπει να προσθέσετε στο ScrollPane ένα Panel, να διαχειριστείτε το layout manager του Panel και να τοποθετήσετε τα components μέσα στο συγκεκριμένο panel. 9
Γενικά δε θα χειριστείτε συμβάντα σε ένα Scroll Pane, αλλά θα το κάνετε στα components που περιέχει. 9.16 Menus Τα menus είναι διαφορετικά από τα υπόλοιπα components σε σημαντικό βαθμό. Γενικά δεν μπορείτε να προσθέτετε menus σε συνήθεις containers και να τα βάζετε να τα τοποθετεί ένας layout manager. Μπορείτε να προσθέσετε menus μόνο σε συγκεκριμένα πράγματα που ονομάζονται menus containers. Γενικά μπορείτε να ξεκινήσετε ένα «δένδρο» από menu μόνο τοποθετώντας σε ένα frame μία menu bar, με χρήση της μεθόδου setmenubar(). Από το σημείο αυτό, μπορείτε να προσθέτετε menus στη menu bar και στη συνέχεια να προσθέτετε menus ή menu items στα menus. Η μόνη εξαίρεση σε αυτό είναι ένα popup menu που μπορεί να προστεθεί σε οποιοδήποτε component αλλά βέβαια δεν υπάρχει στην περίπτωση αυτή ζήτημα layout. 9.16.1. Το help menu Ένα συγκεκριμένο χαρακτηριστικό μίας menu bar είναι ότι μπορείτε να ορίσετε ένα συγκεκριμένο menu να είναι το Help menu. Αυτό γίνεται με τη μέθοδο sethelpmenu(menu). Για να αντιμετωπισθεί ένα menu ως help menu πρέπει να έχει προστεθεί ως τέτοιο στη menu bar και στη συνέχεια θα αντιμετωπίζεται με τον κατάλληλο τρόπο για ένα μενού βοηθείας στη συγκεκριμένη πλατφόρμα. Για παράδειγμα σε συστήματα X/Motif, θα τοποθετηθεί στο δεξί άκρο της menu bar. 9.17 MenuBar Πρόκειται για ένα οριζόντιο μενού. Μπορεί να προστεθεί μόνο σε ένα αντικείμενο Frame και αποτελεί τη ρίζα για όλα τα δένδρα μενού. Frame f = new Frame( MenuBar ); MenuBar mb = new MenuBar(); f.setmenubar(mb); Η MenuBar δεν υποστηρίζει listeners. Αυτό ισχύει γιατί αναμένεται ότι όλα τα συμβάντα που λαμβάνουν χώρα μέσα στην περιοχή ενός menubar θα επεξεργάζονται αυτόματα ως μέρος της συνήθους συμπεριφοράς του menu. 9.18 Menu Η κλάση Menu παρέχει το βασικό pull-down menu. Μπορεί να προστεθεί είτε σε μία MenuBar είτε σε ένα άλλο Menu. MenuBar mb = new MenuBar(); Menu m1 = new Menu( File ); 10
Menu m2 = new Menu( Edit ); Menu m3 = new Menu( Help ); mb.add(m1); mb.add(m2); mb.add(m3); mb.sethelpmenu(m3); Σημείωση Τα μενού που παρουσιάζονται εδώ είναι κενά, που εξηγεί την εμφάνιση του μενού File. Μπορείτε να προσθέσετε έναν ActionListener σε ένα αντικείμενο Menu, αλλά δε συνηθίζεται. Κανονικά, τα menu χρησιμοποιούνται μόνο για να παρουσιάζουν και να ελέγχουν τα menu items που θα δούμε στη συνέχεια. 9.19 MenuItem Τα MenuItems είναι κόμβοι-φύλλα ενός δένδρου menu, υπό μορφή κειμένου. Γενικά τα προσθέτουμε στο menu για ν συμπληρώσουμε την εικόνα. Menu m1 = new Menu( File ); MenuItem mi1 = new MenuItem( Save ); MenuItem mi2 = new MenuItem( Load ); MenuItem mi3 = new MenuItem( Quit ); m1.add(mi1); m1.add(mi2); m1.addseparator(); m1.add(mi3); Συνήθως προσθέτετε ένα ActionListener σε ένα αντικείμενο MenuItem για να παρέχετε συμπεριφορά στα menus σας. 9.20 CheckboxMenuItem Είναι ένα clickable menu item, ώστε να μπορείτε να έχετε επιλογές on ή off μέσα στα menus. Menu m1 = new Menu( File ); MenuItem mi1 = new MenuItem( Save ); CheckboxMenuItem mi2 = new CheckboxMenuItem( Persistent ); m1.add(mi1); 11
m1.add(mi2); Το CheckboxMenuItem πρέπει να παρακολουθείτε μέσω μίας διεπαφής ItemListener. Συνεπώς όταν αλλάζει η κατάσταση του checkbox θα καλείται η μέθοδος itemstatechanged(). 9.21 PopupMenu Παρέχει ένα αυτόνομο μενού που μπορεί να γίνει pop-up σε οποιοδήποτε component. Σε ένα popup menu μπορείτε να προσθέσετε menu items ή menus. Frame f = new Frame( PopupMenu ); Button b = new Button( Press Me ); PopupMenu p = new PopupMenu( Popup ); MenuItem s = new MenuItem( Save ); MenuItem l = new MenuItem( Load ); b.addactionlistener(this); f.add( Center, b); p.add(s); p.add(l); f.add(p); Σημείωση Το PopumMenu πρέπει να προστίθεται σε ένα «γονικό» component. Αυτό δεν είναι ίδιο με την πρόσθεση συνήθως components σε containers. Στο παράδειγμα αυτό το popup προστέθηκε στο frame που το περιέχει. Για να προκαλέσετε ένα PopupMenu να εμφανιστεί πρέπει να καλέσετε τη μέθοδο show. Η παρουσίαση απαιτεί μία αναφορά σε component να λειτουργήσει ως βάση για τις συντεταγμένες x και y. Συνήθως θα χρησιμοποιείτε για το λόγο αυτό το component που προκάλεσε την παρουσίαση. Στην περίπτωσή μας το button b. public void actionperformed(actionevent ev) { p.show(b, 10, 10); Σημείωση Το αρχικό component πρέπει να βρίσκεται κάτω από ή να περιέχεται σε το γονικό component στην ιεραρχία του περιέρχεσθαι. 12
9.22 Έλεγχος των οπτικών απόψεων Μπορείτε να ελέγξετε την εμφάνιση των AWT components από άποψης του χρώματος που χρησιμοποιείται σε foreground και background και της γραμματοσειράς που χρησιμοποιείται για το κείμενο. 9.22.1. Χρώματα Υπάρχουν δύο μέθοδοι για να θέσετε το χρώμα σε ένα component, και είναι setforeground() setbackground() Αμφότερες οι μέθοδοι λαμβάνουν ένα όρισμα που είναι στιγμιότυπο της κλάσης java.awt.color. Μπορείτε να χρησιμοποιήσετε σταθερές χρωμάτων οι οποίες αναφέρονται ως Color.red, Color.blue κλπ. Το πλήρες διαθέσιμο εύρος των προκαθορισμένων χρωμάτων βρίσκεται στη σελίδα τεκμηρίωσης για την κλάση Color. Επιπρόσθετα μπορείτε να δημιουργήσετε ένα συγκεκριμένο χρώμα ως εξής: int r = 255, g = 255, b = 0; Color c = new Color(r, g, b); Μία τέτοια συνάρτηση δημιουργίας δημιουργεί ένα χρώμα με βάση τις καθορισμένες εντάσεις των χρωμάτων κόκκινο (r), πράσινο (g) και μπλε (b), με βάση ένα εύρος από 0 έως 255 για το κάθε ένα. 9.22.2. Γραμματοσειρές Η γραμματοσειρά που χρησιμοποιείται για την παρουσίαση του κειμένου σε ένα component καθορίζεται με χρήση της μεθόδου setfont(). Το όρισμα της μεθόδου αυτής είναι ένα στιγμιότυπο της κλάσης java.awt.font. Δεν υπάρχουν ορισμένες σταθερές για τις γραμματοσειρές, αλλά μπορείτε να δημιουργήσετε μία γραμματοσειρά καθορίζοντας το όνομα της γραμματοσειράς, το στυλ και το μέγεθος σε στιγμές. Font f = new Font( TimesRoman, Font.PLAIN, 14); Τα επιτρεπτά ονόματα γραμματοσειρών περιλαμβάνουν: Dialog Helvetica TimesRoman προσοχή χωρίς κενό ενδιάμεσα Courier Μία πλήρης λίστα μπορεί να καθοριστεί καλώντας τη μέθοδο getfontlist() σε ένα αντικείμενο Toolkit. Το toolkit μπορεί να ληφθεί από το component, αφού αυτό έχει παρουσιαστεί, με χρήση της μεθόδου gettoolkit(). Εναλλακτικά, μπορείτε να χρησιμοποιήσετε το εξ ορισμού toolkit, το οποίο μπορείτε να βρείτε με κλήση της μεθόδου Toolkit.getDefaultToolkit(). Οι σταθερές για τα στυλ των γραμματοσειρών, που στην πράξη είναι τιμές τύπου int είναι μία από: 13
Font.BOLD Fond.ITALIC Font.PLAIN Font.BOLD + Font.ITALIC Τα μεγέθη σε στιγμές πρέπει να καθορίζονται με χρήση μίας τιμής int. 9.23 Εκτύπωση Η εκτύπωση αντιμετωπίζεται στη Java 1.1 με τρόπο στενά συνδεδεμένο με την παρουσίαση στην οθόνη. Λαμβάνεται ένα ειδικό είδος αντικειμένου java.awt.graphics ώστε όλες οι εντολές σχεδίασης (draw) που αποστέλλονται σε αυτό το graphics να αποστέλλονται στην πράξη στον εκτυπωτή. Το σύστημα εκτύπωσης της Java 1.1 επιτρέπει τη χρήση των τοπικών συνθηκών ελέγχου του εκτυπωτή, ώστε ο χρήστης να βλέπει ένα dialog box επιλογής εκτυπωτή όταν ξεκινάτε μία πράξη εκτύπωσης. Ο χρήστης στη συνέχεια μπορεί να διαλέξει επιλογές όπως μέγεθος χαρτιού, ποιότητα εκτύπωσης και εκτυπωτή προς χρήση: Frame f = new Frame( Print test ); Toolkit t = f.gettoolkit(); PrintJob job = t.getprintjob(f, MyPrintJob, null); Graphics g = job.getgraphics(); Οι γραμμές αυτές δημιουργούν ένα Graphics που «συνδέεται» με τον εκτυπωτή που θα επιλέξει ο χρήστης. Λαμβάνει ένα καινούριο graphics για κάθε σελίδα. f.printall(g); Για να γράψετε στον εκτυπωτή μπορείτε να χρησιμοποιήσετε οποιαδήποτε από τις μεθόδους σχεδίασης της κλάσης graphics. Εναλλακτικά, όπως παρουσιάστηκε εδώ, μπορείτε απλά να ζητήσετε από ένα component να «σχεδιάσει τον εαυτό του» στα graphics. Η μέθοδος print() ζητά από ένα component να σχεδιάσει τον εαυτό του με τον τρόπο αυτό, αλλά σχετίζεται μόνο με το component για το οποίο κλήθηκε. Στην περίπτωση ενός container, όπως εδώ, μπορούμε να χρησιμοποιήσουμε τη μέθοδο printall() για να αναγκάσουμε τον container και όλα τα components που περιέχει να σχεδιαστούν στον εκτυπωτή. g.dispose(); job.end(); Αφού έχετε δημιουργήσει μία σελίδα εξόδου όπως θέλετε, χρησιμοποιείτε τη μέθοδο dispose() για να αναγκάσετε τη σελίδα να σταλεί στον εκτυπωτή. Όταν έχετε τελειώσει την εργασία εκτύπωσης (job), καλείται τη μέθοδο end() στο αντικείμενο PrintJob. Αυτό δηλώνει ότι η εργασία εκτύπωσης (print job) έχε ολοκληρωθεί και επιτρέπει στο σύστημα ετεροχρονισμού εκτύπωσης (print spooling) να εκτελέσει την εργασία και στη συνέχεια να απελευθερώσει τον εκτυπωτή για άλλες εργασίες εκτύπωσης. 14
9.24 Εργασίες 9.24.1. Επιπέδου 1: Δημιουργήστε το ακόλουθο layout 1. Με χρήση του πακέτου java.awt δημιουργήστε μία εφαρμογή Java που θα παρουσιάζει τα ακόλουθα components 2. Χρησιμοποιήστε για το Help menu ένα dialog. 9.24.2. Επιπέδου 3: Πρόγραμμα ζωγραφικής 1. Δημιουργήστε το layout που φαίνεται πιο πάνω και γράψτε ένα απλό πρόγραμμα ζωγραφικής που θα χρησιμοποιεί το GUI 2. Χρησιμοποιήστε το java.awt.printjob για να εκτυπώσετε το γραφικό που θα σχεδιαστεί όταν επιλεγεί το μενού Print. 15