Technische Universität München Institut für Informatik Lehrstuhl für Computer Graphik & Visualisierung Praktikum: Grundlagen der Programmierung Prof. R. Westermann, R. Fraedrich, R. Fülöp, H.G. Menz WS 2009 Aufgabenblatt 11 20. Januar 2010 Abgabe: In KW 5/6 (28. Januar – 3. Februar) vor der Übung. GUI und Events 11.1 (Ü) Allgemeine Fragen In diesem Übungsblatt geht es um die Grundlagen der Programmierung von GUIs mit dem Swing Toolkit. (a) Was macht folgende Klasse? Gehen Sie den Code Zeile für Zeile durch und diskutieren Sie was passiert. public class SimpleWindow { public static void main ( String [] args ) { JFrame f = new JFrame ( " PGDP " ); f . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT_ON_CLOSE ); f . add ( new JLabel ( " Hello world ! " )); f . setSize (300 , 200); f . setVisible ( true ); } } (b) In diesem Übungsblatt werden folgende Komponenten von Swing verwendet: JFrame,JButton, JMenuBar, JMenu, JMenuItem, JTextArea, JLabel, JScrollPane, JList, JPanel, JFileChooser, JOptionPane Die Beschreibung zu diesen und vielen weiteren Klassen finden Sie in der API von Swing: http://java.sun.com/javase/6/docs/api/javax/swing/package-summary.html Machen Sie sich mit den oben angegebenen Komponenten vertraut und besprechen Sie wofür man Sie einsetzen könnte. (c) Was ist eine Containerkomponente? Wofür kann Sie eingesetzt werden? Was sind klassische Containerkomponenten? (d) GridLayout und BorderLayout sind sogenannte Layout Manager. Wofür sind diese Klassen zuständig? Diskutieren Sie den Unterschied der beiden Layout Manager. Sehen Sie hierzu in der API zu LayoutManager nach: http://java.sun.com/javase/6/docs/api/java/ awt/LayoutManager.html 1 (e) Die Interaktion des Benutzers mit der GUI wird durch Events gesteuert. Was für eine Rolle spielen hierbei ’Event Listeners’ ? Wie kann man einen Event einer Komponente zuordnen? (f) In der Klasse ColorGUI wird eine einfache GUI erstellt. Gehen Sie dieses Programm schrittweise durch und diskutieren Sie den Aufbau. public class ColorGUI extends JFrame implements ActionListener { private JButton redbutton , yellowbutton , greenbutton , bluebutton ; private JMenuItem redmenuitem , yellowmenuitem , greenmenuitem , bluemenuitem ; public ColorGUI () { setLayout ( new GridLayout (0 , 1)); redbutton = new JButton ( " red " ); add ( redbutton ); yellowbutton = new JButton ( " yellow " ); add ( yellowbutton ); greenbutton = new JButton ( " green " ); add ( greenbutton ); bluebutton = new JButton ( " blue " ); add ( bluebutton ); redbutton . addAct ionLi stener ( this ); yellowbutton . ad dActio nListe ner ( this ); greenbutton . addA ctionL istene r ( this ); bluebutton . addAc tionLi stener ( this ); setJMenuBar ( createMenuBar ()); } protected JMenuBar createMenuBar () { JMenuBar menubar = new JMenuBar (); JMenu colormenu = new JMenu ( " Change colors " ); menubar . add ( colormenu ); redmenuitem = new JMenuItem ( " set red " ); colormenu . add ( redmenuitem ); yellowmenuitem = new JMenuItem ( " set yellow " ); colormenu . add ( yellowmenuitem ); greenmenuitem = new JMenuItem ( " set green " ); colormenu . add ( greenmenuitem ); bluemenuitem = new JMenuItem ( " set blue " ); colormenu . add ( bluemenuitem ); redmenuitem . addA ctionL istene r ( this ); yellowmenuitem . add Action Liste ner ( this ); 2 greenmenuitem . addAc tionLi stener ( this ); bluemenuitem . ad dActio nListe ner ( this ); redmenuitem . setAccelerator ( KeyStroke . getKeyStroke ( KeyEvent . VK_R , ActionEvent . CTRL_MASK )); yellowmenuitem . setAccelerator ( KeyStroke . getKeyStroke ( KeyEvent . VK_Y , ActionEvent . CTRL_MASK )); greenmenuitem . setAccelerator ( KeyStroke . getKeyStroke ( KeyEvent . VK_G , ActionEvent . CTRL_MASK )); bluemenuitem . setAccelerator ( KeyStroke . getKeyStroke ( KeyEvent . VK_B , ActionEvent . CTRL_MASK )); return menubar ; } public void actionPerformed ( ActionEvent e ) { if ( e . getSource () == redbutton || e . getSource () == redmenuitem ) changeColorTo ( Color . RED ); else if ( e . getSource () == yellowbutton || e . getSource () == yellowmenuitem ) changeColorTo ( Color . YELLOW ); else if ( e . getSource () == greenbutton || e . getSource () == greenmenuitem ) changeColorTo ( Color . GREEN ); else if ( e . getSource () == bluebutton || e . getSource () == bluemenuitem ) changeColorTo ( Color . BLUE ); } private void changeColorTo ( Color color ) { redbutton . setBackground ( color ); yellowbutton . setBackground ( color ); greenbutton . setBackground ( color ); bluebutton . setBackground ( color ); } public static void main ( String [] args ) { JFrame frame = new ColorGUI (); frame . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT_ON_CLOSE ); frame . setPreferredSize ( new Dimension (200 , 300)); frame . pack (); frame . setVisible ( true ); } } 11.2 (Ü) Texteditor Schreiben Sie nun einen einfachen Texteditor, der Dateien neu anlegen, laden und speichern kann. Gehen Sie dabei wie folgt vor. Das Hauptfenster Erstellen Sie zunächst die Klasse TextEditor im Package de.tum.ws2009.grprog.uebungsblatt11. TextEditor soll von JFrame abgeleitet sein und ActionListener implementieren. Legen Sie nun mit dieser Klasse ein einfaches Fenster in der main(...) Methode an. 3 Einfügen des Textfeldes Ändern Sie nun den Konstruktor der Klasse TextEditor so ab, dass ein Textfeld JTextArea angezeigt wird sobald das Programm gestartet wird. Wenn Sie nun Text in das Textfeld einfügen, der mehr Platz in Anspruch nimmt als in dem Textfeld vorhanden ist, kann nur sehr umständlich mit den Cursortasten gescrollt werden. Für diesen Fall stellt das Swing Toolkit eine JScrollPane zur Verfügung. Verwenden Sie nun die JScrollPane um dem Textfeld Scrollbalken hinzuzufügen. Sehen Sie in der Dokumentation nach wie dies geht. Das Menü Fügen Sie nun ein Menü zu Ihrem Programm hinzu. Erstellen Sie dazu der Übersicht halber eine Methode JMenuBar createMenuBar() in der das Menü erzeugt wird. Legen Sie den Menupunkt ’File’ und ’ ?’ an. Unterhalb von ’File’ sollen die Untermenupunkte ’New’, ’Save’, ’Load’ und ’Quit’ erscheinen. Der Untermenupunkt von ’ ?’ ist ’Info’. Der Statusbalken Fügen Sie nun einen Statusbalken hinzu der immer die letzte Statusmeldung enthält und am unteren Rand des Fensters erscheinen soll. Verwenden Sie hierzu z.B. ein JLabel. Um mehr als ein Element darstellen zu können müssen Sie den Layout Manager ändern. Hier bietet sich ein BorderLayout Manager an. Eventbehandlung Wenn Sie auf einen Menüpunkt klicken passiert im Moment noch nichts. Im Folgenden wird dem Programm nun ein wenig Leben eingehaucht in dem den Menüpunkten Events hinzugefügt werden. Erweitern Sie hierzu die Methode public void actionPerformed(ActionEvent e) in der Klasse TextEditor um folgende Funktionalität: ’New’ Das Textfeld wird geleert. ’Save’ Der Text in dem Textfeld wird in eine neue Datei gespeichert. Verwenden Sie für die Auswahl der Datei die Klasse JFileChooser. ’Load’ Eine Textdatei soll ausgewählt werden (JFileChooser) und anschließend in das Textfeld geladen werden. ’Quit’ Das Programm wird auf Nachfrage beendet. Verwenden Sie für die Nachfrage die Klasse JOptionPane. ’Info’ Es soll ein Dialogfenster mit dem Namen des Autors des Programms angezeigt werden. Bei allen Events soll eine kurze Statusmeldung im Statusbalken angezeigt werden. Das Laden und Speichern von Dateien wird in der Klasse Tools bereitgestellt. Achten Sie darauf dass bei den angebotenen Methoden die Datei zum Laden existieren muss, bzw. beim Überschreiben keine Rückfrage erfolgt. Tastenkombinationen Erweitern Sie das Programm um folgende Tastenkombinationen: ’New’ Strg + n ’Save’ Strg + s ’Load’ Strg + l 4 ’Quit’ Strg + x ’Info’ F1 Quit Wenn Sie auf das Schließensymbol in der rechten oberen Ecke klicken wird das Editorfenster ohne Rückfrage geschlossen. Wie können Sie eine entsprechende Rückfrage anzeigen lassen wenn das Programm auf diese Weise beendet wird? Suchen Sie hierfür eine Lösung mit Hilfe des Internets. 11.3 (H) Raytracer (31 Punkte) Erstellen Sie eine GUI für unseren Raytracer mit folgenden Eigenschaften. Das Programmfenster soll wie folgt aussehen: Auf der linken Seite ist ein Textfeld in das eine Szenenbeschreibungsdatei geladen werden kann. Rechts oben befindet sich die Vorschau für die Szene die im Textfeld beschrieben ist. Unter dem Vorschaubild werden Statusmeldungen in einer Liste angezeigt. Am unteren Ende befindet sich ein Statusbalken der Informationen über die Szenenbeschreibungsdatei enthält. Erweitern Sie die Klasse RaytracerGUI in Package de.tum.ws2009.grprog.uebungsblatt11.raytracer. Das Textfeld (4 Punkte) Fügen Sie das Textfeld auf der linken Seite ein. Erweitern Sie dazu den Konstruktor der Klasse RaytracerGUI an der entsprechenden Stelle. Achten Sie darauf, dass die Referenz auf das JTextArea Objekt als Klassenvariable deklariert ist (nicht nur lokal), da in folgenden Teilaufgaben auf das Textfeld aus anderen Methoden heraus zugegriffen werden muss. Verwenden Sie nun die JScrollPane um dem Textfeld Scrollbalken hinzuzufügen. 5 Setzen Sie die Eigenschaften des Textfeldes so, dass am Zeilenende an Wortgrenzen in die nächste Zeile umgebrochen wird. (API) Das Menu (3 Punkte) Erstellen Sie nun das Menu. Fügen Sie die beiden Menupunkte ’File’ und ’Raytracer’ ein. ’File’ hat die Untermenupunkte ’New file’, ’Save to file’, ’Load from file’ und ’Quit program’. ’Raytracer’ hat den Untermenupunkt ’Reload preview’. Das Menu sollen in der Methode JMenuBar createMenuBar() erstellt und im Konstruktor gesetzt werden. Geänderter Text (3 Punkte) Fügen Sie eine Klassenvariable textHasChanged ein, die speichert ob eine Änderung im Textfeld durchgeführt wurde. Verwenden Sie einen DocumentListener um diese Variable zusetzen. Der Statusbalken (4 Punkte) Fügen Sie unterhalb des Textfeldes einen Statusbalken ein der den Dateinamen der Szenenbeschreibungsdatei und die aktuelle Länge des Strings in dem Textfeld und die Anzahl der Zeilen der Szenenbeschreibung enthält. Falls eine neue Datei angelegt wurde soll an Stelle des Dateinamens ’new file’ stehen. Beachten Sie dass sich diese Werte während dem Editieren der Datei ändern und updaten Sie diese falls nötig. ActionEvents (14 Punkte) Implementieren Sie nun folgendes Verhalten. ’New file’ Nach einem Klick auf den Untermenupunkt ’New file’ wird, so die aktuelle Szenenbeschreibung seit dem letzten Speichern verändert wurde, nachgefragt, ob die Änderungen gespeichert werden sollen. Je nach Benutzereingabe wird die Szenbeschreibung in eine vom Benutzer ausgewählte Datei gespeichert. Anschließend wird das Textfeld geleert. (Tastenkombination Strg + n) ’Save to file’ Das Speichern der Szenenbeschreibung ist über den Menupunkt ’Save to file’ möglich. Zunächst wird mit JFileChooser eine Datei ausgewählt. Akzetiert der Benutzer (JOptionPane) das die Datei, so sie existiert, überschrieben wird, wird der Inhalt des Textfeldes in der Datei gespeichert, sonst wird dieser Vorgang abgebrochen. (Tastenkombination Strg + s) ’Load from file’ Ähnlich wie beim Speichern, wird eine Datei ausgewählt. Existiert sie wird der Inhalt in das Textfeld geladen. (Tastenkombination Strg + l) ’Quit program’ Wurde das Textfeld seit dem letzten Speichern geändert soll der Benutzer die Möglichkeit erhalten die Szenenbeschreibung zu speichern. Anschließend wird das Programm beendet. (Tastenkombination Strg + x) ’Reload preview’ Die Szenenbeschreibung im Textfeld wird gespeichert und anschließend die Bildvorschau erzeugt. (Tastenkombination F5) Zum Speichern und Laden der Textdateien können Sie die entsprechenden Methoden aus der Tools Klasse verwenden. Ergänzen Sie die angegebenen Tastenkombinationen zu den Menupunkten. Vergessen Sie nicht die Variable textHasChanged an den passenden Stellen auf false/true zusetzen. Statusmeldungen (3 Punkte) Erstellen Sie sinnvolle Statusmeldungen die in der Liste unter dem Previewfenster angezeigt werden. Neue Statusmeldungen werden immer oben in die Liste eingefügt. Die Meldungen sollen den 6 Benutzer über erfolgreiche Aktionen und eventuelle Probleme beim Laden, Speichern, etc. informieren. Sie können mit logdata.add(0,’’entry’’) den String ”entry” an der ersten Stelle der Liste einfügen. 7