Protokoll Stunde 3

Werbung
Praktikum aus Softwareentwicklung 2, Stunde 3
Lehrziele/Inhalt
1.
2.
3.
4.
5.
Ereignisbehandlung, Auslösen von Ereignissen
JScrollPane
Java2D
Reflection
Eclipse-Tastenkürzel
Ereignisbehandlung, Auslösen von Ereignissen
Löst ein Objekt Ereignisse aus, muss es eine Methode implementieren mit der sich ein Listener
anmelden und eine Methode mit der er sich wieder abmelden kann. Die Methode zum Anmelden
muss add<ListenerName> und die Methode zum Abmelden remove<ListenerName> heißen.
Unterstützt eine Klasse zum Beispiel MouseListener, dann müssen die Methoden addMouseListener
und removeMouseListener heißen. Außerdem muss es die Methode fire<EventName> geben mit der
die Events verschickt werden können.
Listener-Interface
Für jedes mögliche Ereignis muss ein Listener-Interface existieren. Listener-Interfaces können
beliebige Methoden enthalten. Zum Beispiel hat MouseListener die Methoden mouseClicked,
mouseEntered, mouseExited, mousePressed und mouseReleased. Die Methoden müssen als
Parameter ein Event-Object haben, zB: im MouseListener ein MouseEvent.
Listener-Interfaces müssen von dem Marker-Interface java.util.EventListener erben.
Ereignis-Objekte
Für jedes Ereignis muss ein Ereignis-Objekt erstellt und an alle Listener verschickt werden. Jeder
Listener erhält dasselbe Ereignis-Objekt, daher müssen Ereignis-Objekte unveränderbar (immutable)
sein. Ereignis-Objekte in Java erben von der Klasse EventObject. Diese Klasse implementiert
Serializable, daher müssen nicht-serialisierbare Felder als transient markiert werden.
Push oder Pull?
Ereignisse sind häufig mit Änderungen in einem Datenmodell verbunden. Soll man die Änderung
gleich im Event übertragen (Push), oder soll der Interessierte das Datenmodell selbst inspizieren
(Pull)? Eine klare Antwort darauf gibt es nicht. Man muss von Fall zu Fall unterscheiden was die
bessere Alternative ist. Push ist für den Event-Empfänger häufig bequemer, während Pull bei
Änderungen des Datenmodells stabil ist. Bei der Entscheidung Push oder Pull sollte man auch an die
Serialisierbarkeit der gepushten Objekte denken.
JScrollPane
Komponenten die grösser sind als der zur Verfügung stehende Platz werden rechts unten
abgeschnitten. Mit scrollen hat man eine Möglichkeit solche Komponenten doch darzustellen. In Java
übernimmt JScrollPane diese Aufgabe. Damit eine Komponente scrollbar wird muss sie in eine
© Markus Löberbauer 2010
Seite 7
JScrollPane gekapselt werden, zB: new JScrollPane(new JVeryBigComponent()). Und die Komponente
muss ihre Größe für die JScrollPane berechnen können. Dazu kann man die Methode
getPreferredSize überschreiben. Oder wenn man mehr Einfluss auf die JScrollPane haben will das
Interface Scrollable implementieren.
Java2D
Seit Java 1.2 übernimmt Java2D die Zeichenaufgaben in Java, es ist aber kompatibel zu dem RenderVerhalten von Java 1.1. Java2D ermöglicht zB: Abstraktion von physikalischen Pixeln,
Transformationen, Effekte und Antialiasing. Der Einstiegspunkt in Java2D ist die Klasse Graphics2D.
Seit Java 1.2 ist jedes Graphics-Objekt ein Graphics2D-Objekt und kann daher gecaset werden.
Graphics wird nur aus Kompatibilitäts-Gründen in der Schnittstelle übergeben.
Mit Graphics2D kann man die Strichart ändern (setStroke); Transformationen wie zB Skalieren,
Rotieren anbringen (getTransform); das Füllmuster festlegen (setPaint); den Clipping-Bereich setzen;
und die Komposition bestimmen (setComposite). Unter Komposition versteht man: wie vorhandene
Farben auf der Zeichenfläche mit der aktuellen Zeichenoperation verbunden werden sollen.
Beispielsweise kann man das neue Element darüber oder darunter legen oder verschiedene Schnitte
machen, siehe java.awt.AlphaComposite.
Benötigt man ein spezielles Clipping oder spezielle Transformationen sollte man mit einer Kopie des
übergebenen Graphics-Objekts arbeiten. Eine Kopie kann mit der Methode Graphics.create anlegen
werden.
Schrift
Text wird mit der Methode Graphics.drawString ausgegeben. Die Schriftart (java.awt.Font) kann man
mit Graphics.setFont setzen. Zeichnet man eine komplexe Komponente die Text enthält, dann
braucht man häufig die Länge des auszugebenden Texts. Damit man umbrechen oder beispielsweise
abkürzen kann. Solche Maßzahlen über Text kann man über die Klasse FontMetrics erhalten. Objekte
der Klasse FontMetrics kann man über Graphics.getFontMetrics abfragen.
Bilder
Bilder werden mit der Methode Graphics.drawImage gezeichnet. Bilder kann man in Java als
BufferedImage erzeugen, und über ein Graphics2D-Objekt beschreiben. Ein Graphics2D-Objekt erhält
man über die Methoden getGraphics und createGraphics. Die beiden Methoden liefern das gleiche
Objekt, allerdings liefert getGraphics das Objekt aus Kompatibilitätsgründen als Graphics-Objekt.
Häufig ist es interessant Bilder aus Dateien zu laden oder in Dateien zu speichern. Laden von Bildern
erfolgt mit der Methode ImageIO.read, Speichern mit ImageIO.write.
Reflection
Mit Reflection kann der Programmierer zur Laufzeit programmatisch auf Typinformationen zugreifen,
zB: welche Felder, Methoden und Konstruktoren hat eine Klasse. Über Reflection kann man aber
auch Objekte erzeugen, Methoden aufrufen, Felder lesen und schreiben. Mit dynamischen Proxies
(java.lang.reflect.Proxy) kann man zur Laufzeit Objekte erzeugen die gegebene Interfaces
implementieren. Die benötigten Klassen sind in den Packages java.lang.reflect und java.lang.
© Markus Löberbauer 2010
Seite 8
Einsatzgebiete
Die JavaVM benutzt Typinformation beispielsweise zur Speicherbereinigung (garbage collection). In
der Java Klassenbibliothek wird sie benutzt um Klassen nachzuladen (java.util.ServiceLoader).
Programmier können sie benutzen um Werkzeuge zu bauen, zB: Klassen-Browser, Test-Frameworks
(zB: JUnit) und Debugger.
Verwendet man Reflection sollte man sich aber der Nachteile bewusst sein zB:
Geschwindigkeitsverlust durch Klassen-Analyse zur Laufzeit; und Sicherheitsprobleme, über
Reflection kann auch auf private Elemente einer Klasse zugegriffen werden.
Class
Der Einstiegspunkt in Reflection ist die Klasse Class. Ein Objekt dieser Klasse erhält man über:
a.
b.
c.
d.
<Klassenname>.class, zB: ArrayList.class
<Wrapper für einen primitiven Datentyp>.TYPE, zB Integer.TYPE entspricht int.class
ein Objekt mit der Methode getClass()
Class.forName("Klassenname als String"), zB: Class.forName("java.util.ArrayList")
Über das Class-Objekt kann man die Elemente in einer Klasse abfragen: Methoden (getMethods,
getDeclaredMethods), Felder (getFields, getDeclaredFields), Konstruktoren (getConstructors,
getDeclaredConstructors), innere Klassen (getClasses, getDeclaredClasses). Die Methoden mit den
Namen get<…> liefer alle public-Elemente inklusive der geerbten. Die Methoden mit den Namen
getDeclared<…> liefern alle Elemente einer Klasse, unabhängig von ihrer Sichtbarkeit, aber keine
geerbten.
Von allen Elementen kann man mit getDeclaringClass auf die deklarierende Klasse zugreifen.
Elemente einer Klasse
Reflektierte Elemente kann man weiter untersuchen, zB: Methoden auf Rückgabetyp
(getReturnType) und Parametertypen (getParameterTypes); oder man kann damit arbeiten:



Constructor, anlegen neuer Objekte (newInstance)
Method, aufrufen einer Methode (invoke)
Field, lesen und schreiben (get, set; und für primitive Datentypen get<Type>, set<Type>, zB:
getInt, setInt)
Auf Private Elemente einer Klasse kann über Reflection zugegriffen werden, dazu muss man
setAccessible(true) setzen. Ob ein Element zugreifbar ist kann über isAccessible abgefragt werden.
Eclipse-Tastenkürzel
1. Ctrl-Shift-F: Code formatieren.
2. Ctrl-Shift-O: Fehlende Import-Statements einfügen, überflüssige entfernen.
3. Ctrl-Shift-R: Umbenennen einer Klasse, Methode, …
© Markus Löberbauer 2010
Seite 9
Herunterladen