Ja, wunderbar. Dann können wir ja direkt pünktlich anfangen.
Das ist toll. Herzlich willkommen zur neunten Vorlesung. SC2.
Und wie ihr seht, stehe ich wieder hier vorne.
Heute geht es um die Programmierung von grafischen Benutzungsoberflächen oder auch Graphical User Interfaces.
Gouise kurz. Das Ganze wird heute so drei inhaltliche Abschnitte
haben. Ich werde zuerst ein bisschen was erzählen,
welche guten Komponenten es denn so gibt.
Insbesondere jetzt bezogen auf Java
Das Ganze machen wir hier am Beispiel von Java,
ist ja klar. Wir haben ja ein SC1,
ein SC2 als einzige Programmiersprache Java am Start.
Das heißt, vieles von dem ist jetzt sehr Java-spezifisch,
was ich erzähle, aber vieles wird auch einfach allgemeingültig sein.
Das müsst ihr so ein bisschen selber auseinanderpflücken.
Es ist sicherlich gut, wenn ihr erstmal mit den Java-Gooing-Konzepten
vertraut werdet und dann ist es für euch relativ leicht.
Andere Sprachen und andere Frameworks entsprechend zu übernehmen oder mitzuarbeiten
Der zweite Teil wird dann so ein bisschen darauf eingehen,
wie man auf Ereignisse reagieren kann. Da ist ja schon
ein bisschen was vorbereitet worden in der letzten Vorlesung.
Da sage ich dann auch noch was zu.
Und zum Schluss sage ich auch noch was zum Layout.
Also tatsächlich, wie man solche grafischen Nutzungsoberflächen layouten kann,
sodass sie beim Verändern der Größe zum Beispiel angenehm die Komponenten vergrößern,
die größer werden sollen und andere so lässt, wie sie sind.
Das kann man innen. Java sehr schön trennen.
Okay, aber erstmal nochmal ein bisschen Wiederholung
Entwurfsregeln, die wir euch zur Verfügung gestellt haben,
die auch hier im Übungsbetrieb für SE2 gelten.
Die habe ich hier noch mal so ganz kurz zusammengefasst.
Das ist ja die Übersichtsfolie, die ich schon vor
zwei Wochen mal oder vor drei Wochen vorgestellt habe.
Wir haben also diese vier Elementtypen, Materialienfachwerte, Werkzeuge, Services.
Und wir haben die dann auch in der Mediathek exemplarisch gesehen.
Wir haben auch gesehen, wie diese Elementarten in den Kinokarten,
Verkaufssystemen auftreten können. Und heute geht es jetzt um Wert
Das heißt, um die Dinger hier oben,
die sind immer mit Absicht hier so weiter oben angeordnet,
weil man sich so vorstellt, irgendwie weiter unten sind so die systemnahen Abstraktionen.
Und hier ist sozusagen die Schnittstelle zum Benutzer. Das heißt,
so ein Werkzeug hat eine grafische Benutzungsschnittstelle und genau darum geht es
uns ja heute, wir wollen solche Dinger ja bauen.
Wir haben diese etwas größeren Systeme, also die Mediathek und
auch dieses Kinokartenverkaufssystem, ganz bewusst in SE2 gewinnt.
Wir haben zwei Systeme gewählt, weil wir sagen,
ein System könnte langweilig werden im Laufe des Semesters.
Es ist ganz schön, wenn man die Konzepte auch in
zwei verschiedenen Systemen angewendet sieht.
Trotzdem sind die
ganz schön groß
Und ich hatte deshalb, wenn ihr euch erinnert,
vor zwei Wochen einen oder vor drei Wochen,
also in der vorletzten Vorlesung,
ein sehr kleines System angefangen zu bauen.
Und das sieht ungefähr so aus. Ich hatte hier
was gebaut mit einem Ereigniszähler. Das war das Material.
Das war die Idee. Man hat irgendwie ein Material,
das zu einem bestimmten Zeitpunkt erzeugt wird, diesen Erzeugungszeitpunkt sich merkt.
Und dann ab da einfach immer so registrieren kann,
wenn irgendein Ereignis eintritt. Also man kann sich hier so
ein eigenes Zähler machen, wie Schafe springen über einen Zaun.
Wenn ich nachts nicht einschlafen kann, dann fange ich an,
Schafe zu zählen.
Dann kann ich mir tatsächlich hier so
ein kleines Ding bauen
Die Schnittstelle sieht auch relativ überschaubar aus. Es ist also
eine möglichst kleines Material, um das Ganze hier gut demonstrieren zu können.
Wir haben hier Operationen, die die Ereignis-Art rausgibt.
Also wenn man so ein Ereigniszähler erzeugt,
dann muss man angeben, welches Ereignis da gezählt wird.
Also was weiß ich, Chuck Norris rettet die Welt oder
scharf springt über den Zaun oder Koala fällt vom Baum, irgend sowas.
Dann kann man sich von so einem Material den Erzeugungszeitpunkt geben lassen als String.
Dann kann man sich den Zählerstand geben lassen,
also wie viele Ereignisse dieser Art sind schon gezählt worden.
Und man kann eben halt dieses Registrierereignis aufrufen,
um zu sagen, hier ist gerade wieder das Ereignis aufgetreten
Das heißt, das Ding hat einen Zustand, der kann verändert werden,
der Zustand kann sondiert werden mit sondierenden Operationen. Also ein richtiges,
echtes Material und aber auch ein fachliches Material im Sinne von,
es geht darum, fachliche Dinge zu zählen.
Es kann ja auch sowas geben wie ein Biologen,
der in Afrika irgendwelche Tiere in freier Wildbahn zählen will,
registrieren will, wie oft sie etwas tun.
Der macht sich vielleicht dann mit diesem Werkzeug und vielleicht
ein bisschen netterer Software dazu noch.
Kann er sich eben halt so mehrere Zähler auf den Bildschirm
holen und kann immer draufklicken, wenn irgendwas passiert.
Also das ist, und diese Materialien kann man dann hinterher
auch auswerten. Also es ist tatsächlich so,
diese Materialien speichern ja etwas
Ihren Zeitpunkt und dann aber auch, wie oft etwas passiert.
Und dann kann man das Material hinterher irgendwo geeignet auswerten.
Also es ist tatsächlich etwas, was auch Dinge dauerhaft festhalten kann. Ja,
und wie gesagt, wenn wir uns jetzt hier mal so ein Ding erzeugen,
das können wir im Blue Jay auch interaktiv machen,
dann sage ich hier irgendwie scharf über Zaun.
So, dann habe ich hier tatsächlich meinen kleinen Ereigniszähler,
der irgendwie so aussieht. Und ich kann jetzt hier,
ach so, das kann man ja mal vielleicht dann zeigen,
also hier nochmal das jetzt nochmal in Erinnerung bekommt,
bin ich jetzt hier an diesem Ereignis Zähler irgendwie Aufrufe,
registriere Ereignis,
dann wird auch dieser Zähler hier tatsächlich um eins hochgezählt.
Okay, soweit so gut. Dann haben wir gesagt,
wir wollen jetzt das,
was hier in Blue Jay ja so interaktiv so schön geht,
das geht natürlich nicht, normalerweise nicht mit so einem einfachen Material.
Das ist ja nur ein normales Java-Material. Das heißt,
wir haben gesagt, wir wollen jetzt ein Werkzeug bauen,
mit nehmen der Benutzer interaktiv dieses Material bearbeiten kann.
Ich habe das dann auch schon fertig gebaut und habe dann
hier irgendwie solche Dinger hingelegt, mal gucken hier,
sowas wie Schaf über Zaun. So soll diese Gui dann aussehen.
Ich habe also hier einen Titel, scharf über Zaun.
Und dann ist hier der Erzeugungszeitpunkt seit dem 6.6.2012, 14.23 Uhr.
Aha, kann man jetzt hier sozusagen registrieren,
wie oft das Ereignis passiert, dass ein Schaf über einen Zaun springt.
Dann kann ich hier draufklicken und dann zählt dieser Zähler hoch.
Das wollen wir bauen. Das ist ein relativ kleines System,
aber steckt schon relativ viel Technik dahinter, die wir jetzt hier uns gemeinsam angucken werden.
Und was wir eben halt schon in der letzten Woche angefangen haben,
war, dass wir diese Entwurfsregeln von SE2 hergenommen haben.
Also das, was wir hier auf den,
der vor dir stehen haben, die Werkzeugklasse,
die ja dieses Material irgendwie visualisieren soll,
grafisch an der Oberfläche, erhält ihr Material als Konstruktorparameter.
Wir haben keine Services im Spiel, deswegen müssen hier keine Services
übergeben werden und die Werkzeugklasse erzeugt ein Exemplar ihrer UI-Klasse.
Wir haben ja gesagt,
die Werkzeugklasse kümmert sich sozusagen um den Zugriff auf das Material
und verändert das Material und kümmert sich gleichzeitig darum,
dass irgendwas grafisch dargestellt wird und lagert einen Teil dieser
grafischen Darstellung in diese UI-Klasse aus
So, und deswegen haben wir letzte Woche auch schon,
oder damals in der Vorlesung, dieses Zählwerkzeug schon angefangen zu bauen.
Das ist wirklich sehr einfach. Das ist eine klasse Zählwerkzeug,
die hält intern eine Referenz auf ihre Zählwerkzeuge UI.
Und eine Referenz auf ein Material, das durch das Werkzeug bearbeitet wird.
So, und dann ist es hier einfach so,
man muss hier beim Konstrukteaufruf ein solches Ereignis,
ein solchen eigenes Zähler, ein Material übergeben.
Das wird abgelegt und dann wird hier noch die UI erzeugt.
Die UI haben wir damals irgendwie ganz einfach leer implementiert,
da ist auch nichts drin.
Also einfach nur momentan
ein leerer Kasten
Und was wir auch gemacht haben,
wir haben hier irgendwie doch mal so ein Start-up geschrieben,
dass man da schon mal relativ schnell immer was sehen kann und das testen kann.
Also Ereigniszähler hier,
Norris rettet die Welt und dann entsprechend hier wird dieses Ereigniszähler,
dieses Material an das Zielwerkzeug übergeben hier in dem Konstruktoraufruf.
So, das ist also ganz einfach,
wenn man das jetzt aufruft, dann passiert ja noch nicht viel,
weil wir noch gar keine grafischen Benutzungselemente da drin haben.
Das ist der Stand, den wir vor drei Wochen gebaut haben.
Der sich weitgehend an diese Regeln hält,
die wir hier besprochen haben
Damals habe ich dann gesagt,
naja, bevor man jetzt gut verstehen kann,
wie man solche grafischen Oberflächen baut,
müssen wir erst mal so ein bisschen was an Grundlagen uns ansehen,
nämlich einmal über Entwurfsmuster und über grafische Benutzungsschnittstellen.
Entwurfsmuster, die vor diesem war letzte Woche, prominent wichtig,
war das Beobachtermuster, das ihr auch in den Übungen ja jetzt intensiv durchkaut.
Das ist tatsächlich nicht verkehrt, dieses Muster gut zu kennen,
weil das in unheimlich vielen Kontexten in interaktiven Systemen auftaucht.
Das ist also echt sehr, sehr wichtig und sehr relevant.
Wird euch immer wieder über den Weg laufen
Also haben wir da schon mal so ein bisschen Grundlage gelegt,
dass ihr jetzt wisst, wie man irgendwie das hinkriegen kann,
dass irgendwie jemand was beobachtet und beobachtbar, Beobachter informiert werden,
wenn an einem beobachtbaren Ding etwas geändert wird.
Und grafische Bindezuschnittstellen, das ist heute dran.
Das ist jetzt genau das Thema für die heutige Veranstaltung.
Was wir uns jetzt erstmal ansehen werden, ist,
wie welche Google-Komponenten gibt es denn überhaupt?
Ich werde also jetzt gleich erstmal diese UI-Klasse ein bisschen befüllen mit so ein paar Google-Elementen.
Und da gehe ich jetzt erstmal so ein bisschen darauf ein,
warum überhaupt man warum wir so viel Wert darauf legen,
dass diese Dinge getrennt werden.
Dass wir also die GUI von der Fachlichkeit trennen. Dieser eine Satz,
der klingt ganz unschuldig, Technologiezyklen unterscheiden sich von fachlichen Zyklen,
aber das ist genau der entscheidende Punkt.
In der Informatik ist es unheimlich stark,
so dass neue Technologiezyklen sehr, sehr schnell kommen.
Also es kommt relativ schnell, kommen neue Frameworks,
neue Standards, neue Sprachen, neue Darstellungsformen.
Und die fachlichen Zyklen, das ist das,
was an fachlichen Problemen gelöst wird.
Also zum Beispiel bei einer Versicherung,
Versicherungsverträge werden irgendwie verwaltet
Fachlichen Zyklen da sind anders. Die richten sich nach
gesetzlichen Vorgaben, was in dem Fachbereich so passiert.
Was ändert sich im Versicherungswesen und so weiter? Und die sind
eigentlich komplett entkoppelt voneinander und wenn man da jedes Mal,
wenn der eine Zyklus irgendwas ändert, man alles,
beides ändern müsste in der Software, wäre das sehr unflexibel.
Also versucht man das sehr stark zu entkoppeln. Wir wollen also
die Fachlichkeit unserer Anwendung möglichst klar rausschälen und diese fachlich motivierten
Änderungen dann auch wirklich nur an diesem fachlichen Kern ausführen und die Präsentation,
die Handhabung, diese Darstellung, wie das in grafischen Benutzungsoberflächen stattfindet,
dass man wir davon eigentlich trennen
Es sollte also aus formaler Sicht eigentlich irrelevant sein,
ob eine fachliche Operation über eine grafische oder zum Beispiel über
eine textuelle Schnittstelle angestoßen wird.
Irgendwie sowas wie Versicherungsvertrag wurde unterschrieben. Da kann man irgendjemanden Sachbearbeiter
auf den Button klicken oder kann das irgendwo als Text irgendwo eintragen?
Ist eigentlich wurscht. Es geht immer, das Fachlicht passiert immer das Gleiche.
So, und genau das haben wir auch in unseren Entwurfsregeln sehr konsequent,
also die Werkzeuge stark zuständig für Präsentationen der Handhabung.
Das sind Materialien, Fachwerte, die sind stark einfach an der Funktionalität orientiert.
Also an der Fachlichkeit, die da irgendwie gerade beantragt wird.
Und jetzt gibt es, wenn wir mit Graf Vermissungsoberflächen arbeiten wollen,
eine ganze Menge von solchen grafischen Oberflächen.
Das ist hier schon fast eine veraltete Aussage.
Also Betriebssysteme bieten seit einigen Jahren Unterstützung. Das ist jetzt
schon relativ lange. Windows API, McAtosh, Toolbox,
Motive war mal irgendwie ein Gui-Tool-Kit für Unix-Systeme.
Diese APIs sind tatsächlich üblicherweise sehr plattformabhängig gewesen.
Das ist auch heute noch an vielen Stellen so.
Und für den Anspruch von Java
Das ist ja mal angetreten als Programmiersprache, Right Ones, Run Anywhere.
Ich schreibe also einmal mein Java-Programm, das läuft auf jeder Plattform.
Haben die tatsächlich sich große Mühe gegeben, Goui-Toolkids zu bauen für Java,
nämlich einmal das Abstract Windowing-Toolkid, AWT und später dann Swing.
Und die sind eigentlich auch sehr eng verbandelt,
also tatsächlich schimmert AWT an vielen Stellen noch durch, wenn man das benutzt.
Wenn man mit Zwingen arbeitet, muss man auch mit AWT
arbeiten, die sind also so ein bisschen nebeneinander.
Deswegen setzt auch stark auf AWT auf. Im Skript sind da
noch zwei Folien, die das ein bisschen die Unterschiede sind,
da will ich nicht drauf eingehen.
Es geht einfach darum, dass hier eigentlich geschafft wurde,
Plattform, Plattform unabhängig, grafische Oberflächen anzubieten.
Und Zwingen und APT sind tatsächlich objektorientierte Toolkids,
die also ganz stark von Vererbungen und Subtyping Gebrauch machen.
Und gerade auch mit diesen sehr objektorientiert entworfenen Toolkids ist es gut möglich,
diesen Quelltext der Werkzeugkonstruktion sauber von der Funktionalität zu trennen.
Und was wir jetzt ja schon gesagt haben, bauen,
wie diese wunderbare kleine Applikation hier, scharf über Zaun,
so ähnlich ist das ja hier auch.
Wir haben hier jetzt eine kleine Mini-Oberfläche, wo man Button
klicken kann und irgendwie zwei Label hat und noch einen Titel für dieses Fenster.
Und ja, hier haben wir jetzt so was Ähnliches,
also auch irgendwie ein Zwingbeispiel, man kann da draufklicken und hinweis hochgezählt.
Vielleicht mache ich im nächsten Jahr mal irgendwie dieses Beispiel lieber
auf die Folie, sieht ein bisschen netter aus.
Also ein Knopf mit einem Text, ein Ausgabefeld, relativ einfach,
wenn der Knopf kaputt wird, dann wird ein Zähler hochgezählt.
Total simpel. Und jetzt eben genau,
was ich eingangs gesagt habe,
welche drei Schritte machen wir jetzt erst mal,
welche Gummi-Komponenten gibt es in Swing
Dann, wie können wir diese Komponenten mit unseren fachlichen Klassen verbinden?
Also wie kriegen wir mit, wenn an der Oberfläche irgendwas passiert?
Dass da was geklickt wurde zum Beispiel. Das wollen wir dann irgendwie
in unseren Materialklassen entsprechend dafür sorgen, dass da was hochgezählt wird.
Und schließlich, welche Möglichkeiten gibt es fürs Layout?
So, wenn wir uns jetzt mal einfach angucken,
was ist so an Swing-Komponenten gibt, dann ist das wirklich ein riesen Zoo.
Also allein nur Swing hat da schon wirklich ein relativ umfangreiches Angebot.
J-Label, J-Button, also J-Label ist eigentlich sowas wie ein Textfeld.
Das ist eigentlich meist nur gelesen werden kann.
Manchmal auch mit einer BitMap drauf, also ein Bild.
Dann gibt es sowas wie J. Buttons, also irgendwelche Möglichkeiten,
etwas zu klicken, also aktiv irgendwie etwas zu verändern durch Mausaktionen.
J. Textfield, also ein Text, mehrere,
also ein Textfeld ist eigentlich üblicherweise eine einteilige Textbox.
Jane Text Area kann auch mehrteilig sein,
also so für Editoren, ganz gut geeignet.
Jay List, ich selektiere aus einer Liste von Elementen etwas,
die Reihenfolge ist auch wichtig, deswegen hier so eine Liste.
Jake Combo Box kennt ihr auch, sowas,
wo man dann irgendwo hier draufklicken kann und dann aus
einer Liste von Elementen was auswählen kann. Jay Scrollpain,
ich habe etwas, was zu groß ist für den Bildschirm,
ich muss also irgendwie dem Bildschirm eben mit Balken irgendwie das zu positionieren und so weiter.
Gibt es also hier jetzt einiges. Und das geht
noch weiter. Also es gibt dann auch zusammengesetzte Google-Komponenten,
ein J. Frame ist üblicherweise so die Top-Level-Komponente von einem Java-Fenster.
Also das, was sozusagen die Schnittstelle zum Betriebssystem darstellt.
Also auch hier jetzt ist es ja einfach so, das ist ein Windows-Fenster.
Und sozusagen der äußerste Rand dieses Fensters ist durch ein J. Frame modelliert.
Dann so J. Dialog. Ich stelle eine Frage oder man sagt irgendwie,
ja, nein oder hier irgendwelche etwas umfangreicher ein Internal Frame.
Man kann also dafür sorgen, dass solche Frames auch nur innerhalb eines Fensters bleiben dürfen.
Dann hier so verschiedene Dialoge, um Wachen abzufragen.
Und was wir auch schon mal so angesprochen hatten,
so ein J. Color Chooser, also so ein Tool,
wo ich dann einfach tatsächlich eine Farbe auswählen kann und die
dann in einem bestimmten Kontext auf bestimmte Elemente in einem Grafiksystem angewendet werden sollen.
Die sind, wie gesagt, recht umfangreich.
Ich habe hier auch nochmal einfach zur Demo,
wo ist es denn
Die API von Java, das ist 5.0,
ist aber ja egal. Es gibt inzwischen Java 7,
aber das ist in der Hinsicht jetzt nicht so ein Riesenunterschied.
Dann sieht man einmal hier Java AWT, wenn ich mir jetzt hier angucke,
was ist da so an Interfaces gibt, ist das schon ziemlich viel.
Und an Klassen ist das auch ziemlich viel. Und das ist noch nicht alles,
denn es gibt auch noch AWT Color,
Color Data Data Trends für Drag and Drop Event,
Fond und so weiter, also alles AWT.
Und dann gibt es noch Java X Swing,
kommt irgendwo weiter unten hier,
war leider ganz schön bald unten da,
Java X Swing,
auch da wieder
ganz viele Interfaces und dann sehr viele Klassen
Auch da gibt es dann noch wieder verschiedene weitere Unterpakete.
Also das ist schon ein ziemlich dicker Hund.
Und ich gebe jetzt heute hier so einen, sagen wir,
allerersten Einstieg und von da aus kann man sich eigentlich vieles dann auch gut erschließen.
Und was ganz wichtig ist, ist, dass diese Gui-Komponenten
in so einer Swing-Oberfläche geschachtelt sind. Das heißt,
zum einen muss man sie erst mal erzeugen,
wie alles, was man irgendwie haben will in Java,
muss man erst mal die Plare erzeugen,
von diesen Gui-Komponenten und dann musste man die irgendwie ineinander schachteln.
Die werden tatsächlich hierarchisch angeordnet und es gibt also in dem Sinne Container-Komponenten,
die andere Komponenten aufnehmen können und atomare Komponenten,
so was wie ein J-Button ist üblicherweise nicht in der Lage,
noch Elemente aufzunehmen
Und diese Container-Komponenten können natürlich auch mehrfach gedachtelt sein, also es können auch wieder Container-Komponenten drin sein.
Und diese Container haben üblicherweise eine Schnittstelle, wo man,
mit der man Komponenten eintragen kann, sowas wie Operation Ad, Füge hinzu. So,
und dann, wenn man so eine Gui mal hat,
als Beispiel, also hier irgendwie ein Label,
dann hier so ein komisches Tabellenlayout mit zwei Labels,
dann zwei Textfeldern und hier unten noch irgendwie drei Buttons,
wenn man das sich einfach in der Objektstruktur anguckt,
als Objektgeflecht in Java, dann sieht er so ungefähr so aus,
man hat also einen J-Frame als Top-Level Window,
großen J-Label, dann einen J. Panel,
wo dann wieder entsprechend verschiedene Label drin sind und einen weiteren J. Panel,
der dann irgendwie diese Buttons enthält.
Also hier, das ist ein Panel, das Gelbe ist ein Panel.
Das heißt also, man sieht, die sind ineinander geschachtelt.
Okay, und was ich schon gesagt habe,
es gibt sogenannte Top-Level-Container, das heißt,
das sind diejenigen, die den Kontakt zum Betriebssystem herstellen?
Top-Level-Container in Zwingen sind zum Beispiel J. Frame,
aber es gibt auch J. Dialog, also wenn so ein modaler Dialog aufpoppt,
wo man dann gefragt wird, ob man weitermachen will oder nicht.
Und ähnliche J. Applets und J. Frame enthält unter anderem einen sogenannten Content-Pain.
Das ist der Hauptbereich einer grafischen Anwendung. Also selbst wieder
ein Container, in dem dann die Hauptkomponenten eingetragen werden.
Hier ist es mal dargestellt. Also so bei einem J. Frame,
also wir können uns das ja wieder live angucken hier.
Hier haben wir ja so unser Ding. Man sieht hier
der Titlebar, das ist also ganz oben,
das ist üblicherweise auch vom Betriebssystem dann irgendwie vorgegeben,
wie das aussieht. Dann kann man haben eine Menüleiste,
kennt ihr auch von den meisten Anwendungen,
dass man da irgendwie so ein Pfeil-Menü hat und ein Bearbeiten-Menü und so weiter,
haben wir in dieser Anwendung hier nicht.
Könnten wir aber ohne weiteres bauen. Mit so Menü-Einträgen und
so weiter
Und dann kommt hier der Content-Pain, das ist sozusagen die Hauptarbeitsfläche der Anwendung.
Da haben wir tatsächlich jetzt hier unsere drei Elemente drin,
nämlich zwei Label und einen Button.
Ja, und das ist jetzt etwas,
was wir uns einfach mal konkret ansehen. Das heißt,
wir bauen jetzt mal, wie weiter in so einem kleinen System.
Ich werde in dieser Veranstaltung relativ viel programmieren.
Soll euch nicht davon abhalten, auch mal was reinzurufen,
wenn ihr was nicht versteht.
Ich bin hier sehr konzentriert und fokussiert
und versuche das irgendwie
gut verständlich
Aber eben halt auch so schnell, dass es verständlich bleibt.
Gut. Wir haben den Regeln gesagt, so ein Werkzeug
besteht bei uns aus einer Werkzeugklasse und einer UI-Klasse.
Das haben wir in unserem Entwurf ja schon hier vorliegen.
Hier ist unsere Werkzeugklasse, das ist die UI-Klasse.
Und die Werkzeugklasse vermittelt, müssen wir uns gleich angucken,
erzeugt ein Exemplar ihrer UI-Klasse. Das haben wir auch schon gebaut.
So, jetzt gucken wir uns die UI-Klasse ein.
Die UI-Klasse eines Werkzeugs hat die Aufgaben,
die Google-Komponenten zu erzeugen, zu Layouten und zu verwalten.
Das erste ist eine UI, eine UI-Klasse-App,
nicht von UI-Framework-Klassen, wie J Frame oder J Panel.
Das ist bei uns einfach eine willkürliche Regel.
Wir haben gesagt, das soll nicht so sein.
Ihr werdet in vielen Java-Lehrbüchern genau das Gegenteil finden.
Da ist dann irgendwie die fachliche Klasse, sagt dann irgendwie Extense J-Frame.
Also MyFrame, Extense J-Frame. Hässliches Zeug wollen wir nicht.
Wir machen das so, dass die UI-Klassen eigentlich die Schnittstelle möglichst schmal halten sollen.
Das heißt, nur die Schnittstellen, die wir selber hinzudefinieren.
Wenn ich von einer ziemlich Dann sehe ich wirklich,
ich weiß nicht, wie viele hundert Operationen, ziemlich lästig.
Und die definiert als oberste UI-Komponente üblicherweise einen J. Frame.
Das heißt, wir können jetzt einfach mal in unserer Zählwerkzeug-UI,
sagen wir jetzt DU, wir möchten gerne eine einen J. Frame haben.
Das sei mal der Frame, mit dem wir arbeiten.
Und in meinem Konstruktor mache ich jetzt was ganz Überraschendes.
Ich erzeuge mir nämlich tatsächlich einen J. Frame.
Ist ein New J. Frame
So, das kann ich jetzt so nicht übersetzen,
weil er sagt, J. Frame kenne ich gar nicht.
Klar, J. Frame ist eine Klasse aus Java X Swing,
also muss ich hier um, muss ich nicht,
aber ich kann ja auch den vollqualifizierten Namen angeben,
aber ich mache es jetzt einfach mal.
Java X, Swing,
und dann mache ich es mir jetzt leicht,
indem ich hier nicht alles einzeln importiere,
weil das werden jetzt im Warfe der ganzen Vereine
mehr,
portiere ich erstmal alles
Und jetzt kann ich das hier schon mal übersetzen.
Ja, jetzt kann ich also diesen Framehat tatsächlich erzeugen.
Das ist jetzt noch relativ unspektakulär. Wenn wir in Richtung unseres Werkzeugs hier wollen,
dann wollen wir ja zum Beispiel den Titel setzen.
Bei einem JFrame kann man den Titel setzen.
Und tatsächlich kann man das sogar schon im Konstrukteaufruf sagen.
Also kann ich hier irgendwie sagen, hier soll ein Titel übergeben werden.
Na gut, wo kriege ich den her? Na,
der kriegt das, die UI hoffentlich von ihrem Werkzeug irgendwie reingereicht,
weil das Werkzeug weiß ja, was es für ein Werkzeug es ist.
Also sagen wir hier, als Parameter kommt jetzt das da rein.
Und das geht auch noch zu übersetzen. Jetzt haben wir
natürlich die Situation, dass Killwerkzeug nicht mehr übersetzbar ist,
weil er sagt,
hier den Konstrukt
Weil was tun, naja, ich werde dem irgendwie jetzt übergeben und
das natürlich hier in diesem Fall die Ereignisart, die wir zählen wollen.
Das heißt, ich lasse mir jetzt von dem Zähler hier,
da sage ich jetzt mal, Get, Ereignisart,
heißt das Ding, glaube ich.
Ich kann also an dem Zähler sagen,
beschreib dich mal selber, was du denn so zählst.
Und das müsste jetzt auch übersetzbar sein.
Ich habe also jetzt tatsächlich meiner UI hier diesen String übergeben.
Okay, zurück in das UI, die UI-Klasse.
Jetzt haben wir unseren Frame.
Mache ich mal was, was ein bisschen geschummelt ist,
aber das werde ich dann später erklären.
Ich schreibe hier mal hin, Container, Content-Pain.
Ich möchte mir nämlich meinen eigenen Content-Pain hier erstmal erzeugen.
Es sei ein New J Panel sein. Ein J Panel
ist auch nichts weiter als ein Stück Oberfläche, grob gesagt.
Also so ein Stück Leinwand kann man so,
das Panel heißt ja mit der Leinwand.
Und das erzeuge ich mir jetzt hier erstmal und dann
setze ich an dem Frame-Set Content-Pain.
Das sind Operationen, die da definiert sind.
Also so müsste es gehen. Das kann ich nicht übersetzen.
Natürlich nicht, weil ich den Container wieder nicht kenne.
Also importiere Import Java, AWT. Ihr seht,
man braucht häufig aus beiden Welten was. Das ist so
ein bisschen doof. Jetzt müsste das eigentlich übersetzbar sein.
Ja. Okay, das ist ja schon mal ganz schön.
Jetzt habe ich sozusagen den Titel schon mal übergeben.
Was brauchen wir als nächstes? Na, wir holen uns wieder
unser Zielsystem angucken. Wir wollen hier diesen Label da.
Also wir müssen erst mal ein Label definieren.
Okay, ich mache das mal. Private, J Label
. Das ist der Zeitlabel, den nenne ich einfach mal
Boah. Und jetzt fange ich an, das gleiche Spiel an.
Moment, ich erzeuge mir erstmal ein Zeitlabel, ist gleich New J Label.
Und auch da ist es jetzt so, bei so einem Label,
wenn ich den erzeuge, kann ich dem gleich eine Zeichenkette übergeben,
die auf dem Label angezeigt werden soll.
Und da ist es natürlich jetzt, sage ich jetzt einfach mal,
die Zeit, dieser Erzeugungszeitpunkt, übergebe ich da mal.
Und wo kriege ich den her? Natürlich wieder hoffentlich
irgendwie vernünftig übergeben
So, jetzt habe ich schon mal hier mein Sidelabel in
einer Werkzeugklasse aufpassen. Das will ich nicht mehr übersetzen.
Ich muss jetzt wieder hier entsprechend einen wahren Parameter übergeben.
Ich mache das mal so ein bisschen eingerückt hier.
Get erzeugungserzeugungszeitpunkt. Das ist bestimmt ungelaubt, wie es heißt.
Ein eigenes Zähler habe ich hier die API-Get-Erzeugungszeitpunkt.
Ach toll, sogar richtig. Also das heißt, da
müsste sich jetzt Übersetzbar sein. Ja. Also mein Werkzeug
übergibt jetzt schon mal immerhin die Ereignisart und den Erzeugungszeitpunkt.
Und in der UI-Klasse wird das entsprechend in dem Label,
beziehungsweise in dem Titel abgelegt. Achso, ich muss ja
wieder im Moment, da will ich hin. Ja,
jetzt haben wir, was haben wir denn sonst noch so?
Wir wollen natürlich auch den Button da irgendwie erzeugen.
Okay, also brauchen wir auch einen Jay Button.
Es ist jetzt ein bisschen mühselig, aber so ist es halt.
Private Jay Button, mein Button. Zack. Auch den
werde ich jetzt hier mal eben erzeugen und dann mache ich es mir jetzt mal einfach,
da sage ich jetzt New J. Button und da gebe ich den Text jetzt hier mal direkt an.
Also sauberer wäre es vielleicht auch,
wenn jetzt irgendwie das Werkzeug das hier mit kontrolliert,
aber ich sage jetzt hier einfach mal hardcodiert registrieren,
also das, was auch auf dem Label steht in unserem Zielsystem,
so und damit habe ich auch mein Bein.
Das lässt sich hoffentlich übersetzen, ja, lässt sich übersetzen.
Ich muss auch nichts übergeben jetzt, das heißt,
dass andere Werkzeuge dürfte jetzt auch übersetzbar sein hier,
das Werkzeug, die Werkzeugklasse, ja.
So, und dann haben wir das Letzte noch,
das ist ja dieser andere Label,
wenn wir uns das hier nochmal angucken in unserem Zielsystem,
dann brauchen wir noch hier ein Label,
der den Zähler darstellt.
Also wirklich den Zähler-Label. So, letzte müde Aktion,
dann haben wir es, mehr oder weniger,
Private J Label, ein weiterer Label, und jetzt den Zähl-Label.
Okay. Ja, und was mache ich da?
Naja, ich erzeuge mir den wieder genauso wie bisher auch.
Also Zähl-Label ist gleich. New J Label. Und jetzt
habe ich wieder so ein bisschen das Problem,
was übergebe ich dem denn?
Ja,
ich mache jetzt hier irgendwie
Wer? Das ist irgendwas, was harmlos ist hier,
der Wert des Zählers und lass mir den hier was dringend übergeben.
Das heißt, das Ding kann ich jetzt übersetzen. So,
jetzt habe ich tatsächlich alle Google-Komponenten in meiner UI-Komponente erzeugt.
Die UI-Komponente ist dafür zuständig, Google-Komponenten zu erzeugen,
erzeugt sich in Frame. Was wir jetzt hier noch nicht
gemacht haben, wir haben hier noch nicht geschachtelt.
Ja, also eigentlich müsste ich jetzt hier
noch diese ganzen Komponenten jetzt in den Content-Pain reinlegen.
Das heißt, das ist genau das, was ich machen kann.
Ich kann sagen, Content-Pain.at und schmeiß jetzt hier den Zeitlabel rein
Und das kann ich jetzt tatsächlich mit den anderen beiden Komponenten auch machen.
Das heißt, jetzt lasse ich mir hier noch den,
schmeiße ich da auch den Button rein.
Und ich schmeiße hier noch den Zähl-Label rein. So,
auch ihr seht, ich kann also in diesen Content-Pain jetzt
diese ganzen Dinger schon reinstecken. Das haben wir also schon
diese Komponenten ineinander geschachtelt. Das ist noch nicht ganz alt.
Was jetzt üblicherweise dass ich irgendwie eine Größe festlege.
Ich habe jetzt da schon vorher ein bisschen ausprobiert,
also da müssen wir jetzt hier nicht zu viel Zeit mit verschwenden.
Ich kann jetzt sagen, tatsächlich frame.set-size. Und dann sage ich hier
270 mal 80, das ist eine ganz gute Größe.
Und dann sage ich zum Schluss Frame-Set visible true.
Also das Ding soll sichtbar gemacht werden.
Eine Gummi-Komponente ist nicht sichtbar, bevor das nicht aufgerufen wird.
Das muss man einfach wissen. So,
damit habe ich jetzt hier eigentlich meine UI-Klasse fertig.
Die kann ich auch übersetzen. Meine Werkzeugklasse wird jetzt
noch nicht übersetzbar sein,
es fehlt noch ein Parameter
Ich muss also jetzt hier noch mal eben hinzufügen, Zähler,
Zähler, Gip, nee, Get, wie heißt das Ding?
Zählerstand, Zähler, Get, Zählerstand. So,
das kann ich aufrufen, das wird jetzt auch nicht übersetzbar sein,
warum nicht? Wer weiß, warum, ja. Genau,
das ist ein Int, wir wollen aber einen Trink übergeben,
also schummeln wir hier so ein bisschen.
Ja, ich muss mal eben hier improvisieren,
ich bastel damals schnell einen String draus,
So wird also dieser Int-in-in-in-in-string umgewandelt. So, lässt sich
jetzt offensichtlich übersetzen. Und jetzt, juhu, haben wir
das erste Mal etwas, was man sich angucken kann.
Das heißt, wir können den mal zur Seite schieben hier
und können jetzt sagen, wir können jetzt auch unser Start-up übersetzen.
Und wir das jetzt aufrufen, dann wird da hoffentlich,
oho, ein Ding kommen, was ziemlich ähnlich aussieht.
In unserem Start-up hatten wir gesagt, es ist irgendwie Norris,
rettet die Welt. Okay, also das ist das Material,
was wir hier haben. Jetzt sagen wir hier,
Norris rette mal
Okay, man kann hier schon klicken, das ist toll.
Ihr seht, dieser Button, der reagiert hier,
da habe ich nichts für programmiert. Ich habe einfach nur gesagt, Button,
ich erzeug dich, ich packe dich in die Oberfläche rein,
du bist da und du kannst da jetzt reagieren.
Ja, der ist aktiviert, man kann Buttons auch deaktivieren,
also ausgrauen sozusagen. Und der ist jetzt aktiv. Ja,
man sieht da auch was, aber es passiert ja nicht das,
was wir erwarten. Aber immerhin haben wir jetzt schon mal gesehen,
wie man diese Komponenten ineinander reinschmeißen kann und weiter miteinander Beziehungen setzt.
Und wir haben auch jetzt schon so ein bisschen gesehen,
wie wir diese Aufteilung machen,
also diese UI-Klasse ist nichts weiter als ein Nummer,
indem man diese UI-Komponenten drin hält, erzeugt.
Das Layout, das drücken wir dann später an.
Und das Zielwerkzeug muss halt irgendwie sich so eine UI erzeugen.
Sehr schön. Damit haben wir schon dieses hier mehr oder weniger umgesetzt.
Eine UI-Klasse stellt, die für ihre Werkzeugklasse relevanten UI-Mente über Ghetta
an ihrer Schnittstelle zollt. Das haben wir jetzt noch nicht gebaut,
werden wir gleich brauchen, wenn wir weitermachen wollen.
Dann haben wir hier eine UI-Klasse, hat keine Abhängigkeit zu anderen Elementtypen.
Das ist ganz wichtig. Das ist wirklich so eigentlich nur
eine Auslagerung. Wir haben diese Werkzeugklasse und wir wollen so
ein paar Sachen in die UI-Klasse auslagern,
einfach damit das ein bisschen sauber getrennt ist.
Aber diese UI-Klasse gehört eigentlich zum Werkzeug
Und deswegen sollte die auch nicht irgendwie Beziehungen haben zu irgendwelchen anderen Elementarten.
So eine UI-Klasse hat eigentlich nur Importe aus den Framework, UI-Framework-Paketen.
Und die sollte auch als Paket interne Klasse deklariert sein.
Na gut, das haben wir hier gemacht.
Wenn wir uns das mal angucken,
das ist ja hier bei mir sogar bei allen Klassen so,
weil wir ja nur ein Paket haben momentan,
das ist ja ein sehr kleines System.
Aber hier sieht man auch, das ist eine Klasse,
Unpublic davor. Das heißt, außerhalb dieses Paketes ist
diese Klasse nicht sichtbar. So soll es sein bei
einer UI-Klasse
Die ist also sehr eng mit ihrem Werkzeug verkoppelt.
Ja, soweit so gut. Das ist sehr schön. Jetzt,
bevor ich den Schritt mache,
dass wir auch die Dinger miteinander verkoppeln können,
dass wir wirklich reagieren können,
dass da auf den Button geklickt wurde und dann das Material entsprechend geändert wird,
will ich nochmal eine Sache zeigen,
die jetzt eigentlich sich auch schon so ein bisschen mitergibt mit diesem Problem der Aktualisierung der Gui.
Wir haben jetzt gesagt, die Materialklasse,
die Werkzeugklasse erhält ihr Material als Konstrukt am Parameter.
Haben wir auch so gebaut. Oder über Setter. Also
hier so über Setter, wenn das Material austauschbar ist.
Jetzt bauen wir doch einfach mal in unsere Werkzeugklasse
eine Methode rein
Die da lautet, Public Void, Set, R-Eignes,
Zähler. So, da übergebe ich ein Ereigniszähler.
So, und was passiert da? Naja, relativ einfach
. Ich sage einfach hier Zähler ist gleich dieser Ereigniszähler,
der übergeben wurde. Ich möchte sozusagen bei meinem Werkzeug
das Material austauschbar machen
Warum nicht? Fachlich kann das ja durchaus sinnvoll sein.
So, das kann ich jetzt übersetzen. Ja, wunderbar
. Und jetzt kann ich mir tatsächlich hier mal so ein
Ereignis Zähler bauen, also hier irgendwie scharf über Zaun.
Und jetzt kann ich mir hier auch ein Zählwerkzeug bauen,
kann dem diesen Ereignis Zähler geben. Hier, ups.
So, und jetzt habe ich tatsächlich hier meine Gui,
die dann auch das anzeigt, scharf über Zaun.
Und jetzt mache ich mal was anderes.
Ich mache jetzt hier mal einen zweiten Ereigniszähler.
Koala fällt
Runter. So. Ja, und das wollen wir auch irgendwie,
das sagen wir irgendwie,
hm, wir wollen das bei unserem Werkzeug,
wollen wir das jetzt mal anders setzen, das heißt,
ich sage jetzt hier, Set-Ereigniszähler und übergebe diesen Ereigniszähler.
Dieses Material, ich tausche das Material aus.
Und was man jetzt sieht, ist, dass dieser Wechsel
des Materials sich gar nicht in der Gummi auswirkt.
Das ist ja auch logisch, haben wir ja nicht programmiert.
Das heißt, wenn das Material sich ändert,
muss natürlich die Gummi irgendwie jetzt was anderes anzeigen.
Also hier müsste ich jetzt irgendwie stehen,
Koala fällt runter und hier müsste auch ein anderer Erzeugungszeitpunkt stehen,
möglicherweise eine Minute später
Okay, dann würde ich sagen,
bauen wir das doch mal da rein,
weil das ist nämlich etwas, was man relativ häufig machen muss.
Ich habe also hier mein Zählwerkzeug und ich habe hier
die Möglichkeit, ein Ereignis Zähler zu setzen.
Was würde ich denn jetzt mir wünschen, was ich jetzt machen kann?
Und ich glaube, das ist so, ich nenne das,
habe das mal von einem Kollegen mal schön beschrieben gehört,
nach dem Maniana-Prinzip.
Ich schreibe jetzt einfach aktualisiere UI. Das ist eine Methode
, die ich jetzt aufrufen möchte. Bei mir hat sich
was geändert, also soll jetzt die UI
sich aktualisieren
Toll. Ein Mariana-Prinzip, weil die habe ich noch nicht
geschrieben. Ich sage nur, die schreibe ich noch.
Das mache ich morgen, so ungefähr.
Okay, das lässt sich jetzt natürlich nicht übersetzen.
Also muss ich hier irgendwie jetzt erstmal dieses aktualisiere,
das mache ich Privates, also nur eine private Hilfsmethode,
Methode, Private Void aktualilisiere UI.
So, und was soll die machen?
Ja, die soll, was soll die machen?
Wer wirft mir mal irgendwas an den Kopf?
Wie kann man sich das jetzt vorstellen
Jetzt passieren? Was kann die jetzt eigentlich nur machen?
Wir wollen, ja. Genau, die Label neu setzen,
das heißt an der UI-Klasse jetzt, die Label,
die Label neu mit Text versehen.
Wir können jetzt entweder neue Label da reinsetzen, das ist aber relativ unschön,
weil diese GUI ja irgendwie schon so vom Layout da ist und so.
Also was wir machen können ist,
wir können jetzt bei der UI-Klasse sagen,
gib mir mal den Label,
ich muss mal eben den Text da drauf ändern
Weil die halt so eng miteinander sind, kann man das so machen.
Das heißt, wir gehen jetzt hier ganz stumpf in die
UI-Klasse und lassen uns jetzt, implementieren uns verschiedene Ghetter.
Also ich sage zum Beispiel hier, Public, J Frame, Get Frame.
So, und da mache ich nichts weiter als Return,
den Frame, den das UI-Klassiker irgendwie intern hält.
So, das kann ich jetzt hier übersetzen. Der Ghetter ist da,
jetzt kann ich bei der anderen Klasse diesen Ghetter benutzen.
Ich kann also jetzt hier UI, Get Frame.
Und dann Set Title. Und jetzt kann ich mir
natürlich mal so ein bisschen was kopieren.
Also hier, da Zähler, Get Ereignisart.
Das möchte ich natürlich jetzt bei dem Zähler entsprechend setzen.
Gut. Das müsste jetzt eigentlich funktionieren, kann ich das übersetzen?
Kann ich übersetzen. Das heißt, jetzt haben wir schon den Titel aktualisiert.
Dann brauche ich als nächstes auch noch die beiden Label,
die muss ich mir irgendwie auch geben lassen.
Also muss ich wieder in die andere Klasse rein und
da jetzt diese lästigen Ghetter schreiben. Das ist was,
was man bei Java-Programmierungen relativ häufig macht, lästige Ghetter schreiben muss.
Man könnte jetzt argumentieren, die beiden Klassen liegen dicht beieinander.
Macht doch einfach diese Exemplarvariablen, hier diese,
die im Private sind, an die die andere Klasse ja nicht rankommt,
die könnte ich jetzt ja Paket, sich Paket öffentlich machen.
Das heißt, ich schreibe hier einfach nichts davor und
dann kann die andere Klasse direkt auf die Exemplarvarianen zugreifen.
Das ist unschöner Stil, deswegen mache ich es lieber mit Ghettern.
Wir haben es auch in unseren Entwurfsregeln so gefordert,
deswegen mache ich es jetzt auch hier mit Ghettern,
nur dass ihr einfach euch klar seid, man kann es auch technisch anders machen.
Also sage ich jetzt hier, Public J Label, Get Zeit, Label.
Naja, das ist natürlich auch wieder völlig uninteressant.
Einfach nur Return-Zeit-Label, müsste es schon gewesen sein.
Und dann mache ich hier auch noch das nochmal mit dem
Zähllabel, den lasse ich mir auch rausgeben.
Und damit kann jetzt die Werkzeugklasse auf diese Dinge zugreifen und auch die Texte neu setzen.
Das heißt, hier kann ich jetzt schreiben, Wupps,
you I get zeit, Label, Set, Text.
Ja, und natürlich wieder das, was da oben steht.
Okay. Und das Gleiche natürlich dann auch mit UI get zähl.
Label. Zertext. Du, du, du,
du. Und jetzt lasse ich mir hier wieder,
kopiere ich mir auch dieses ganze Gehubere hier wieder
So. Okay. Das müsste übersetzbar sein, ist es auch.
Das heißt, jetzt können wir ganz schnell testen, ob das auch funktioniert.
Ich mache mir wieder ein Ereigniszähler, sage, scharf über Zaun,
dann übergebe ich, mache ich ein neues Werkzeug, sage,
da ist dein Material, da ist scharf über Zaun.
Und jetzt, wenn wir jetzt einen weiteren Ereigniszähler bauen,
Koala fällt runter und jetzt bei diesem Werkzeug sagen, hallo,
ändere mal dein Material, Sollte da oben jetzt stehen,
Koala fällt runter und die Zeit hat sich auch geändert.
Okay, also das hat tatsächlich funktioniert. Wir haben jetzt
diesen Zusammenhang hergestellt. Das heißt, wenn sich das Material
ändert, dann können wir dieses aktualisiere UI aufwürfen.
Funktioniert wunderbar. Okay, soweit so gut. Was wir jetzt schon gesehen haben,
ist, dass darauf achten müssen, dass irgendwie die Fachlichkeit,
die wir in unseren fachlichen Klassen haben,
visualisiert in der Oberfläche an, die immer mich darum kümmern,
dass die richtigen Informationen in der UI,
in den richtigen Labeln und so weiter auftauchen.
Was wir jetzt aber auch noch bauen wollen, ist ja,
wenn man drauf klickt auf so einen Button,
dass dann tatsächlich auch die andere Richtung funktioniert.
Nicht, wenn sich hier unten was ändert,
die Google soll es anzeigen, sondern wenn an der Gui irgendwas passiert,
jemand manipuliert an der Gummi was, das soll durchschlagen auf die Materialien.
Und das ist etwas, das ist, ja, das,
was man bei grafischen Benutzungsoberflächen zentral verstanden haben muss, nämlich,
dass tatsächlich diese Verarbeitung, wie ihr sie klassisch von Java-Programmen kennt,
ein bisschen auf den Kopf gestellt ist.
Das heißt, was ihr traditionell kennt, ist irgendwie,
ihr startet ein Programm, eine Main-Methode,
da wird irgendwas reingesetzt und was reingegeben, Eingabeverarbeitung,
Ausgabe,
das ist das EFA-Prinzip
Irgendwas wird, auch Algorithmen sind meistens so oft geworden.
Man hat eine Eingabe für einen Algorithmus,
der Algorithmus arbeitet und er spuckt irgendwas aus.
Das ist klassisch die Sichtweise, eine klassische Sichtweise in der Informatik.
Und so haben auch früher irgendwelche Betriebssysteme gearbeitet. Das heißt also,
üblicherweise irgendwie sowas, solange das noch nicht zu Ende ist,
mach irgendwas, Input, Process, Output und bla bla
bla, vollständige Kontrolle des Programms ist beim Anwendungsentwickler.
Das ist wunderbar. Wir wollen ja sozusagen unsere Programme
so schreiben, dass wir wissen, was da passiert.
Und man kann sehr effizient die Programme entwickeln, was nachteilig ist,
ist, dass man eine sehr enge Kopplung hat zwischen dem,
wie es irgendwie dargestellt wird und dem,
was wirklich berechnet wird und was wirklich passiert.
Was wir ja wollen, sind ja eher solche Systeme hier
in eine wunderbare alte Folie.
Es ist ein altes, alte Meckintosh-Oberfläche. Ikonen,
Icons, also Ikonen vielleicht nicht ganz so toll übersetzt.
Auf dem Bildschirm warten darauf, irgendwie mit Doppelklick aktiviert zu werden.
Das heißt, die sind dann reaktiv. Das heißt,
wir wollen reaktive Systeme bauen. Das sind Systeme,
wo nicht klar ist, Eingabeverarbeitung, Ausgabe,
sondern hier weiß man ja nicht, wo der Benutzer als nächstes hinklickt.
Das Betriebssystem weiß es nicht. Das Betriebssystem kriegt nur
irgendwelche Ereignisse und kann dann irgendwie die weiterleiten an jemanden,
der sich für diese Ereignisse interessiert
Und das ist eigentlich das Grundprinzip von grafischen Benutzungsoberflächen. Das heißt,
die Steuerung des Kontrollflusses liegt tatsächlich außerhalb des Quelltextes des Anwendungsentwicklers.
Das heißt, wenn ihr ein solches Gummi-Programm schreibt,
dann schreibt ihr nicht mehr den ganzen Kontrollfluss explizit hin.
Ihr wisst nicht immer, wo der Kontrollfluss da ist,
sondern eigentlich ist der Kontrollfluss irgendwo in diesem Gummi-Code und der benachrichtigt euch immer,
wenn irgendwas geklickt wird und dann reagiert ihr mit eurem Benutzer und definierten Code.
Das heißt, man braucht diese Spezifika, wie das Eventing implementiert ist,
muss man nicht kennen, das ist ganz schön.
Und diese Trennung von Gummi- und Applikationsgrund wird erleichtert.
Und das erhöht eben halt auch die Änderbarkeit von Software,
dass man das so sauber trennen kann. Der Nachteil ist,
wenn man mit reaktiven Systemen arbeitet, deswegen stehe ich hier jetzt,
man muss erstmal sich einarbeiten in diese Gui-Logik und muss erstmal Verständnis haben für diese grundlegenden Strukturen.
Okay, also das ist das, was euch klar sein muss. Man hat irgendwie eine Oberfläche,
dahinter steckt irgendein Systemcode, irgendwie Gui-Code,
der in den Java-Bibliotheken steckt und wenn irgend so ein Button geklickt wird,
dann wollt ihr ja darauf reagieren, ihr wollt ja irgendwie,
dass euer Code ausgeführt wird, wenn der Button geklickt wird.
Dann könnt ihr euch vorstellen, dieser Code für den Button
Der ist vor zehn Jahren, vor 15 Jahren geschrieben worden.
Und der weiß nichts von eurem neuen Anwendercode.
Also irgendwie muss man jetzt ja eine Möglichkeit finden,
diesem Systemcode irgendwas unterzuschieben, damit er an dem Bescheid sagen kann,
dass da was passiert ist.
Das ist, das ist das, was wir bei reaktiver Programmierung brauchen.
Und das passiert üblicherweise mit Events. Das heißt, jede Mausbewegung,
jeder Maus-Dink, jeder Tastendruck wird vom Systemkunden einer Guy registriert.
Und dann wird ein sogenanntes Ereignis ein Event erzeugt.
Und das können sehr elementare Aktionen sein,
tatsächlich also Mausbewegungen
Oder es können auch sogenannte High-Level-Events sein. Also sowas wie
auf einen Button klicken. Das kann man als High-Level-Event abfragen
bei einer Gui. Man kann aber auch tatsächlich fragen,
ja, ich gehe mit der Maus rüber über den Button,
dann klicke ich einmal runter und dann lasse ich die Maus wieder los.
Das sind ja tatsächlich mehrere haptische Dinge, die da passieren.
Und die werden aber dann gerne zusammengefasst zu einem High-Level-Event.
Also sowas wie Button Prest bei einem Button. Das braucht man
meistens irgendwie viel häufiger als wirklich diese ganz elementaren Operationen.
Man kann sich aber tatsächlich jede einzelne Mausbewegung auch geben lassen,
sich informieren lassen
Ja, und diese Events werden eben halt an alle Teile
des Anwendungssystems verschickt, die sich dafür interessieren.
Das heißt, man muss sich irgendwie dafür angemeldet haben für so ein Ereignis.
Das heißt, Anbindung der Applikation an die Oberfläche ist,
das Prinzip ist einfach, hier werden Ereignisse ausgelöst.
Die Applikation kann reagieren, indem sie Listen implementiert und dann
durch diesen Benachhaltigungsministerium kann die Oberflächenkomponente von der Applikation verwendet und
die Applikation von der Komponente benachrichtigt werden.
Ohne dass ein direkter Zyklus entsteht. Also der Jay-Button kennt ja die Applikation nicht,
die Applikation, haben wir gerade geschrieben,
erzeugt einen Jay-Button und weiß ganz genau,
das ist der Button,
der für das und das da ist
Aber umgekehrt ist das eben halt, ja,
irgendwie eine Form der Benachrichtigung. So, jetzt haben wir
euch ja in der letzten Woche schon das Beobachtermuster ausführlich vorgestellt.
Das heißt, ich habe jetzt schon eine grobe Vorstellung,
wie das vermutlich laufen wird. Und tatsächlich ist das,
was in den Swing-Framework implementiert ist,
mehr oder weniger genau das, was auch das Beobachtermuster umsetzt.
Nämlich dieses Konzept der Listener. Also es muss Anwendungscode vom Systemcode
aufgerufen werden, also muss der Anwendungscode eine Schnittstelle haben,
die dem System bekannt ist.
Ja, und es gibt eben sogenannte Listener-Interfaces. Wie gut
, dass wir Interfaces ja schon in- und auswendig kennen.
Also Beispiel Actionlistener. Das ist ein Interface,
das hat eine Operation,
die heißt Action performt
Bekommt als Parameter ein Action-Event. Ich kann jetzt als Anwendungsentwickler
in meiner Klasse sagen, diese Klasse implementiert Actionlistener. So,
und Actionlistener ist ein Interface, das der Button kennt,
der Jane Button kennt dieses Interface und sagt, wenn wir jemanden actualisten da reinreicht,
dann sage ich den Bescheid, wenn ich geklickt werde.
Das heißt also, hier, der Anwendungscode hat dann diese entsprechende Klasse,
die actionperformt implementiert und dann muss es bei der entsprechenden Komponente auch angemeldet werden. Das ist hier mal im schematischen Ablauf,
ich habe hier meine Anwendung, das ist sozusagen mein eigener Code,
dann habe ich irgendwo hier eine Klasse in meiner eine Anwendung,
die einen Action-Listner implementiert, also diese Action-Performt-Methode implementiert,
dann sage ich irgendwie UJ Button,
wie wir das eben schon im Beispiel gesehen haben,
der dieser Button wird erzeugt,
das ist so die Initialisierung und ich sage dann auch Ad-Action-Listner und trage dann genau diese Klasse,
die diesen Action-Listner implementiert bei dem Button ein und sage also hier,
sag mal diesem Objekt
Bescheid, wenn du geklickt wirst. So,
das ist die Setup-Zeit und jetzt gibt es irgendwie zur Laufzeit,
wenn das Ding dann läuft,
klickt jemand auf diesen Button,
dann erzeugt der Button ein neues Action-Event und dieses Action-Event
wird dann hier an den Action-Listner übergeben,
der bei dem Button registriert ist
Also entsprechend hier wird dieser Parameter übergeben. Und dann kann
die Anwendung mit dem entsprechenden Code, also in der Methode,
in der Implementation von Action performt, darauf reagieren.
So, das ist eigentlich mehr, alles, was man verstanden haben muss.
Und hier in der Implementation von Action-Lister wird dann dieser Button-Click entsprechend verarbeitet.
Das gucken wir uns gleich live an. Das heißt,
hier dieses Gehubere mit Action-Lister und so weiter,
wenn wir einfach mal live implementieren.
Wir werden also jetzt tatsächlich auch die Anbindung in unserem kleinen Beispielsystem bauen.
Aber vorher würde ich gerne einmal, wenn nicht Fragen sind,
Keine Fragen. Bis jetzt war anscheinend eines einigermaßen nachvollziehbar.
Da würde ich jetzt gerne fünf Minuten Pause machen.
Dann. Dann geht's jetzt weiter. Jetzt gucken wir uns
diesen Spezialmechanismus an, der hier schon angekündigt ist auf der Folie.
Die sogenannten anonymen inneren Klassen, eine wirklich glorreiche Heldentat,
der Java-Designer, die sehr praktisch ist, aber extrem kryptisch daherkommt.
Also etwas, was, sagen wir nicht sofort einsichtig ist,
was da eigentlich genau passiert.
Wir wollen Bei einem Jay-Button uns als Listener anmelden.
Also machen wir das nochmal hier ganz konkret. Als erstes
müssen wir mal diesen Button überhaupt zugänglicher haben. Das heißt,
wenn das Werkzeug sich als Listener anmelden will bei dem Button,
muss es erstmal Zugriff auf den Button haben.
Also müssen wir mal wieder so einen lästigen Ghetter schreiben.
Also schreibe ich hier mal wieder meinen Ghetter, diesmal mit einem Jay-Button,
Get-Button und lasse mir, gebe hier einfach raus, Return
So, das lässt sich übersetzen. Dann sage ich jetzt,
bei dem Zählwerkzeug, so, wie möchte ich das jetzt genau machen?
Ich möchte irgendwie, ja, ich mich jetzt bei diesen, als Listener registrieren.
Das heißt also, wie kann man das jetzt hier schreiben?
Eine ganz schöne Art und Weise ist eigentlich,
dass man hier eine Methode definiert, registriere Wissender.
Ist immer schön aufgeräumt, sieht irgendwie besser aus.
Also ich rufe hier jetzt, habe sozusagen kriege ich mein Material,
dann erzeuge ich meine UI und dann möchte ich noch mich bei diesen entsprechenden Dingen registrieren.
Also registriere Listener. Machen wir doch das doch mal,
dann implementieren wir die auch mal, nachdem man Jana-Prinzip jetzt also private Void registriere.
Wissen wir? Ja, und was macht der?
Der lässt sich von der UI, also von der UI-Klasse,
Get Button wird aufgerufen und an diesem Button wird jetzt aufgerufen,
add Action Listener.
So, das ist auch mehr oder weniger das,
was auf der Folie steht hier.
Also My Button, add Action Listener und jetzt schreibe ich
hier so was Eigenartiges New Action Listener und so weiter.
Das werde ich jetzt mal erläutern. Also New Action Listener.
Das ist ja schon mal lustig. Ihr wisst, Action
Listener ist ein Interface. Ich schreibe jetzt New für einem Interface.
Das kann ja irgendwie Man kann ja keine Exemplare von Interfaces erzeugen.
Das ist genau dieses Konzept von diesen anonymen inneren Klassen.
Ich schreibe nämlich jetzt direkt dahinter den Rumpf einer Klasse, die dieses Interface implementiert.
Und diese Klasse, die hat noch nicht mal einen Namen,
deswegen heißt das Ganze auch anonyme innere Klassen.
Das heißt also, jetzt schreibe ich hierhin geschweifte Klammer auf,
dann geschweifte Klammer zu und ich übergebe ja hier Ad Action
Lister als Parameter dieses Objekt, was ich hier erzeuge.
Also ich definiere nicht nur eine Klasse,
die das Interface implementiert, sondern ich erzeuge auch automatisch gleich
ein Exemplar davon
Das ist also tatsächlich sehr, sehr erstaunlich, was da alles passiert.
Und dann mache ich hier die Klammer wieder zu.
Das heißt also, das ist tatsächlich jetzt der Parameter,
die Parameterübergabe. So, das heißt also,
bei diesem Button habe ich jetzt einen Actionlistener erstmal formal,
also syntaktisch ist das jetzt hier korrekt.
Aber das wird jetzt nicht übersetzbar sein, weil diese anonyme Klasse,
die jetzt hier, man sieht das auch in der,
kann man das auch ein bisschen erkennen, ja,
also hier gelb sind ja immer Methoden und grün sind immer Klassen.
Man sieht hier, dass die ganze Klasse grün ist und
man sieht hier, dass dieser kleine Bereich auch grün ist.
Und jetzt muss ich hier die Methode implementieren und
die heißt Action performt
Void, Action performt und bekommt als Parameter ein Action-Event.
So, und ja, ich kann die tatsächlich jetzt hier einfach direkt implementieren.
So, und was mache ich jetzt da? Also jetzt
an dieser Stelle möchte ich ja jetzt den Code schreiben,
der aufgerufen werden soll, wenn auf den Button geklickt wurde.
Auch das ist wieder schöner, eleganter Stil,
wenn ich jetzt hier nicht seitenweise Code schreibe,
sondern schreibe, reagiere auf Button-Click.
So, also wieder da, ich schiebe das erstmal
eine schöne Methode rein. So, und dann,
naja, wie sieht das jetzt aus
Private, Rea, Private Void, reagiere auf Button-Klick.
Was soll denn der jetzt machen?
Hat mir jemand eine Idee? Was soll denn passieren,
wenn das Werkzeug jetzt mitbekommt, dass ein Button geklickt wurde?
Was soll jetzt passieren? Ja. Genau, also an
Material soll jetzt das Material, soll es verändert werden.
Wir haben jetzt registriert, der Benutzer möchte das Material ändern.
Also ändere ich auch das Material. Das heißt,
ich sage hier jetzt irgendwie Zähler, registriere Ereignis,
glaube ich. So hieß es, glaube ich.
Gucken wir gleich mal, ob das übersetzbar ist.
Ah, okay. Actionlisten, ah, okay. Ja,
Actionlisten, ich kann das nicht übersetzen, weil er den
Actionlistener als Klasse nicht kennt, als Typ nicht kennt.
Also muss ich jetzt hier Import, Java, AWT-Event.stern schreiben.
Damit habe ich hoffentlich jetzt das übersetzbar. Genau,
jetzt ist also der Actionlistener auch bekannt hier im Quelltext.
Und ich kann jetzt tatsächlich sagen, Zähler registriere Ereignis.
Und was muss ich jetzt
hier noch tun
Ja. Ganz genau. Denn jetzt haben wir sozusagen
das Material gerne. Aber wir haben aber eben gesehen,
was passiert, wenn das Material sich ändert.
Die Google muss es ja mitbekommen. Die Google muss aktualisiert
werden. Also rufe ich jetzt meine wunderbare Operation auf.
Aktu-Alli-Siere UI, die habe ich ja schon.
Toll. Und damit bin ich schon fertig.
Das heißt, jetzt haben wir hier unser Ding fertig.
Ich kann jetzt hier mal Mailing aufrufen,
habe dann diese Noris Rettet die Welt
Werkzeug, kann registrieren und siehe da, der Zähler wird hochgezählt.
Großes Kino und jetzt können wir sozusagen, könnten wir jetzt nochmal testen,
ob das auch funktioniert, wenn ich das Material austausche.
Also wenn ich jetzt Set-Material aufrufe, das Material austausche und dass
es dann immer noch funktioniert, aber das wird funktionieren. So,
das heißt, was wir hier jetzt gesehen haben,
ist dieses sehr eigenartige Konzept von, ich,
an dieser Stelle sage ich New Actions,
also on the fly in dieser kleinen Stelle an dieser Aufrufstelle baue ich eine Klasse und die hat keinen Namen und ich mache auch gleich ein Exemplar davon.
Und da gibt es wirklich eigentlich nur darum,
so ein kleines Stück Code zu haben, so ein Hook,
damit dann, wenn der Button geklickt wird, dieser Code aufgerufen wird,
der dann irgendwie in meiner Anwendung irgendwas Schlaues anstößt.
Gut, ja, das sind also diese komischen anonymen inneren Klassen.
Erinnert euch ja, ich hatte schon erzählt,
dass es in Java die Möglichkeit gibt, in Klassen,
in Klassen zu schachteln.
Diese statisch geschachtelten Klassen, die hatten wir schon gesehen.
Es gibt auch drei Arten von geschatteten Klassen,
die die inneren Klassen genannt werden.
Und da gibt es also die normalen inneren Klassen,
dann gibt es die lokalen inneren Klassen.
In einer Methode kann ich eine lokale Klasse definieren,
wer es braucht
Und dann eben halt als dritte Variante diese anonymen inneren Klassen.
Und da ist es immer so, dass ein Exemplar dieser
inneren Klasse immer ein Exemplar der umgebenden Klasse braucht.
Man kann also nicht ohne ein Wirtsobjekt, ein Parasitobjekt haben.
Und das ist tatsächlich eine sehr enge Beziehung zwischen so einem geschachtelten,
zwischen so einer inneren Klasse und einer Wirtsklasse.
Das heißt, die können gegenseitig sich wirklich auf die privaten Methoden zugreifen.
Das sehen wir auch tatsächlich hier in dem Code.
Wenn ihr das mal genau seht, dann seht ihr,
dass diese Klasse, die hier ja geschachtet ist,
ruft ja Reagiere auf Button-Click auf und reagiere auf Button-Click,
ist privat in der umgebenden Klasse.
Das ist eine Methode der Wirtsklasse. Das ist eine Methode
der Parasitklasse und die kennen sich sehr gut, die sind sozusagen sehr eng miteinander vertraut.
Da gibt es also keine Geheimnisse, privat alles zugreifbar.
Das ist eine Frage. Ja, Bruder, entscheidest du,
wo abfüllen sie, wie du eigentlich offen bist?
Ich habe jetzt die Vanillefantaschien-Sphäre eingetragen. Ja,
das ist tatsächlich eine, also ich wiederhole die Frage,
wonach entscheidet sich jetzt, an welchen Stellen ich aktualisiere, UI aufrufen muss?
Ganz einfach, sobald sich irgendetwas fachlich Relevantes ändert,
an den Materialien, am Zustand der Material, am Zustand des Services,
am Zustand des Werkzeuges, muss ich, aktualisiere UI aufrufen.
Das heißt, aktualisiere UI, muss aufgerufen werden,
wenn sie das Material ändert. Also wenn das Material ausgetauscht wird,
oder wenn auf dem Buttonclick reagiert wird,
weil dann ist vermutlich auch, wird da sich irgendwas ändern.
Man könnte jetzt der Vollständigkeit halber auch hier noch ein aktualisiere UI machen,
weil es sozusagen da ja auch so ein,
damit das einen definierten Anfangszustand hat.
Kann man machen, aber wir wissen ja hier,
dass sozusagen diese Initialisierung auch hier stattfindet. Aber tatsächlich,
sobald irgendetwas fachlich relevant ist. Also eigentlich ist die Daumenregel,
sobald irgendwas, was für die Oberfläche relevant ist,
sich ändert, muss ich dieses aktualisiere UI aufrufen.
Das ist hier jetzt eine relativ kleine Geschichte. Ihr werdet
dann in größeren Systemen merken, dass man nicht immer alles aktualisieren will.
Wenn ihr eine große Gummi habt, mit ganz vielen Gumm-Elementen,
dann wollt ihr teilweise nicht das alles neu aktualisiert wird.
Da muss man dann eben halt sehr spezifisch auf die Fachlichkeit gucken.
Okay. Okay. So, was wollten wir jetzt eigentlich
noch machen? Wir haben uns jetzt das Neo angeguckt mit
diesen anonymen inneren Klassen, einfach,
dass ihr es
mal gesehen habt
Und dann kann man eben halt hier noch weitere,
also wenn man sich jetzt zwingend genauer anguckt,
sieht man eben halt,
es gibt sowas wie Listen da beim J Radio-Button,
also zum Beispiel nicht nur ein Action-Listender im Sinne von,
der Button ist geklickt worden, sondern auch,
es ist irgendwie eine Auswahl getroffen worden bei einem Radio-Button.
Oder bei einer J-List auch wieder der Action-Listender. Irgendwie ist es
auf so ein Item doppelt geklickt worden. Aber auch,
es ist einfach die Auswahl in einer Liste geändert worden.
List Selection-Listender, das ist in dem Kino-Kartensystem zum Beispiel so gebaut.
Oder bei einer J-Combo-Box ist da irgendwie auch wieder ein Item
gewählt worden und so weiter.
Also da gibt es verschiedene Listener,
relativ viele Interfaces
Es gibt dann auch entsprechende Eventklassen, die damit verschickt werden.
Wir haben ja gesehen, es wird ja hier ein Action-Event
als Parameter übergeben bei dieser Operation Action performt.
Und aus diesem, aus diesem Action-Event kann man teilweise noch
wieder Informationen bekommen, wer da, geht das Mikro weg?
Nee, ne? Hört sich gerade so an. Wer
hat eigentlich das Ereignis ausgelöst? Also mehr Details zum Auslösen
des Events. Also zum Beispiel hier kann man bei manchen IDs,
bei manchen, nee, alle Java-Events verfügen über die Operation
Get Source
Kriegt man die Quellkomponente und Get ID, also so eine Konstante,
so eine symbolische. Viele Events verfügen auch über einen Consume,
um das Event zu verbrauchen im Sinne von, es ist
jetzt verarbeitet worden. Aber das ist sozusagen fortgeschrittenes Zeug.
Ja, und die werden von den angemeldeten Listen verarbeitet.
Und das ist auch das. Und dann sieht man eben halt,
es gibt auch tatsächlich noch weitere Interfaces, also Fokuslistener,
also zum Beispiel, wenn ich jetzt hier so mehrere Fenster habe und naja,
da sind jetzt natürlich große Fenster, nehmen wir mal hier sowas.
Es gibt Betriebssysteme, da kann man tatsächlich sich informieren lassen,
wenn nur der Fokus gewechselt wird.
Also ich gehe jetzt hier aus dem einen Fenster raus,
Focus Gained, dann gehe ich hier raus, Focus Lost,
jetzt kriegt das Fenster hier eine Nachricht, Focus Gained.
Es gibt eben halt einfach Systeme, für die ist sowas wichtig.
Die wollen genau diese Events mit erfassen und das kann man
eben in Java auch mit den entsprechenden Interfaces.
Item Listener, Text-Event, Text-Listner,
ich möchte vielleicht bei einem Textfeld bei jedem einzelnen Tastendruck schon mitkriegen,
dass da was gedrückt wurde.
Nicht erst, wenn da so ein Okay-Button geklickt wird,
den Text vollständig eingetragen ist und so weiter.
Da gibt es eine ganze Menge Zeug,
könnt ihr euch alles in Ruhe angucken.
Das ist relativ einfach jetzt zusammengefasst hier nochmal.
Jede Google-Komponente implementiert für eine bestimmte Art von Ereignisse,
eine Ad-Event-Listner-Methode. Über die Methode kann ich Objekte anmelden.
Und die müssen eben halt dieses Interface implementieren. Und wenn
ein entsprechendes Ereignis ausgeführt wird, dann werden alle angemeldeten Listenobjekte benachrichtigt.
Und dann kann man eben halt mehr Informationen in ihr
eigenes Typen noch über den, aus dem Event rausziehen.
Was wir jetzt gesehen haben, ist hier Bezug auf
die Werkzeugkonstruktion
Das heißt, wir sagen ja, eine UI-Klasse stellt,
die für ihre Werkzeugklasse relevanten EUI-Elemente über Ghetter in ihrer Schnittstelle zur Verfügung.
Das haben wir gerade gesehen. Die ganzen Ghetter mussten wir jetzt alle bauen.
Und die Werkzeugklasse erzeugt für diese UI-Widgets Listener, haben wir auch gesehen,
in unserer Werkzeugklasse haben wir den Listener implementiert, der die passende Aktion ausführt.
Und registriert den auch an den Widgets. Die Werkzeugklasse gibt,
die anzuzeigende Materialien oder Fachwerte in die UI,
dass tatsächlich also hier die Werkzeugklasse holt sich von der UI-Klasse ein Widget und setzt,
bei dem die Angst zu zeigenden Informationen.
Genau wie wir es jetzt gemacht haben,
bei dem Label setze ich den Text,
bei dem Oder bei beiden Labels in diesem Fall,
beim Titel und so weiter.
Was wir auch in den Entwurfsregeln noch mitbehandelt haben,
ist die Frage der Formatierung, also das,
was da angezeigt wird, wie das formatiert ist.
Das ist ein Thema, das auch noch mal ein bisschen
umfangreicher ist, dass ich jetzt hier nicht vertiefen will.
Ich habe da zwar ein Beispielsystem dabei, aber nur ganz kurz gesagt,
viele Gui-Komponenten in Swing können auch textuell etwas anzeigen.
Also so eine Liste zum Beispiel zeigt da
irgendwelche Texte an
Eine Jaylist. Und wenn da mehrere Objekte drin in der Jaylist
abgelegt sind, dann wird einfach an Objekten to String aufgerufen.
Und dieses zu String ist, nicht besonders gut geeignet,
um Dinge fachlich sinnvoll zu beschreiben an einer Oberfläche.
Deswegen sollte man da entsprechende Formatierer einsetzen.
Ich gehe da jetzt an dieser Stelle nicht drauf ein,
weil sonst wir nicht genügend Zeit haben, noch für unsere Layout-Fragen.
Okay, also jetzt kommen wir nochmal zum Thema Layout.
Das ist etwas, was wir bisher noch sozusagen völlig außen
vor gelassen haben. Wir haben erstmal nur überhaupt dafür gesorgt,
dass die Komponenten da sind, dass sie richtig gefachtelt sind.
Und dass ich dann auch auf Komponenten Komponenten aktivieren kann.
Das Zusammenspiel haben wir jetzt gesehen. Aber man kann tatsächlich
ja bei so einem Fenster auch, ja, Layout-Informationen festlegen.
Also einfach die Frage, wie verhält es sich denn,
wenn ich das in seiner Größe verändere?
Zum Beispiel habe ich ja hier mein wunderbares Schaf über Zaun.
Wenn ich jetzt dieses Fenster hier breiter ziehe, dann seht ihr,
dass diese drei Elemente, die ich da eingefügt habe,
diese drei Komponenten, die beiden Label und der Button,
die scheinen irgendwie hier mittig zu bleiben.
So, und wenn ich jetzt das hier noch weiter nach unten aufziehe,
dann seht ihr auch, das klebt irgendwie da oben.
Das ist ja jetzt Sagen wir eine relativ willkürliche Entscheidung.
Aber es ist eben halt tatsächlich hier ein Layout,
das so funktioniert. Ich kann auch noch zeigen,
was passiert, wenn ich das jetzt kleiner mache.
Dann seht ihr nämlich auch den Effekt, dass hier das umbricht.
Das gucken wir uns vielleicht auch nochmal an, wie das zustande kommt.
Aber ihr seht erstmal, dieses Vergrößeren und Verkleinern,
inklusive Inhalt, kann sich ja sehr unterschiedlich auswirken.
Das sieht in diesem Fall jetzt nicht gerade toll aus.
Das ist relativ hässlich. Man möchte ja aber bei bestimmten Fenstern sehen,
dass sie irgendwie, wenn sie sich verändern, auch das sinnvoll verändert wird.
Also wenn ihr zum Beispiel euch hier BlueJ anguckt,
wenn ich hier jetzt das Fenster größer ziehe,
dann wird ja nur Dieser Bereich hier vergrößert.
Alles andere bleibt relativ gleich. Das wird zwar eine Breite
verändert, aber nicht in der Höhe.
Und das bleibt in der Breite auch gleich. Das ist
explizit von den BlueJ-Leuten natürlich so gewollt. Und zuerst mal muss man verstehen,
dass in Swing diese ganzen Container, die ja Komponenten enthalten,
wir haben ja gesagt, diese Komponenten sind ineinander geschachtelt,
bei jeder Container-Komponente gibt es die Möglichkeit, ein Layout-Manager zu setzen.
Ich kann also jedem Container sagen, pass auf,
lege mal die Komponenten, die bei dir reingefügt werden,
Layoute, die mal so wie dein Layout-Manager, die das vorschreibt.
Und dann kann man eben tatsächlich verschiedene Layout-Manager setzen
Order Layout, Grid Layout und Flow Layout. Und das
sind tatsächlich auch die Layouts, die hier entsprechend verwendet werden.
Also zum Beispiel hier diese drei grünen Buttons,
die in dem blauen J. Panel sind,
die sind hier mit einem Flow Layout eingefügt.
Das ist auch genau das, was wir in unserem System verbaut haben.
Also ich kann tatsächlich an jedem Container so einen Layout-Manager setzen,
Set Layout und Layout Mentor Get Layout.
Und das Standard-Layout für den Content-Pain eines J. Frame ist das Border Layout.
Das ist die Stelle, an der ich vorhin ein bisschen geschummelt habe.
Ich habe nämlich explizit einen eigenen Content-Pain gesetzt,
weil ich wusste, dass bei einem J-Panel ein Flow Layout
als Manager gesetzt ist
Man kann auch, wenn man ganz fortgeschritten ist, eigene Layout-Klassen schreiben.
Aber in Java gibt es eben halt da schon eine ganze Menge Layout-Manager,
von dem wir uns jetzt mal ein paar ansehen werden.
Ich kann das hier mal zeigen. Wir gucken uns vielleicht erstmal
diese verschiedenen Layout-Manager an. Wenn ihr euch an die Mediathek erinnert,
da gab es oben mehrere Buttons für die verschiedenen,
für die Verleihansicht, für die Rückgabeansicht und so weiter.
Und da drunter war ein Panel, wo die ganzen Elemente drin lagen.
Aber es war immer so, dass diese mit einem Button-Click
auf die verschiedenen Ansichten wurde das komplett ausgetauscht.
Das ist ein Beispiel für ein Card-Layout. Also tatsächlich,
man sich vorstellen kann, mehrere Karten liegen hintereinander und
es wird immer eine nach vorne geholt
Also ein sehr, sehr praktisches Layout, wenn man so Dinge
so ganz klar immer komplett durch andere Layouts ersetzen will.
Das Flow-Layout haben wir jetzt schon gesehen. Das Border Layout,
ich habe hier einfach auch ein wunderschönes Beispiel, meinem Gucken,
wo haben wir es denn? Hier Layout-Beispiele,
da habe ich mal so ein paar Layouts direkt mal implementiert,
dass man sie auch mal in Aktion sehen kann.
Also ich mache mal hier zum Beispiel von dem Flow-Layout,
mache ich mal ein Beispiel. Wir haben also hier,
ich zeige vielleicht erstmal den Quelltext, das ist vielleicht ein bisschen einfacher erstmal.
Also ich habe einfach nur einen J Frame,
Und bei dem J Frame setze ich als Content-Pain hier,
lasse ich mir den Content-Pain geben und setze hier das entsprechende Flow-Layout und Content-Pain sage Set-Layout-Flow.
Also ich setze an dem Content-Pain das Flow-Layout und dann füge
ich hier einfach mehrere Buttons hin, so ähne Mähne,
Moon, raus bist du.
Und das ist eigentlich schon alles, was da passiert.
Also dann noch hier so ein Frame-Pack und Frame Set Visible und das war's.
Ja, und was dann da rauskommt, ist genau das hier.
Und was man jetzt hier sieht, ist,
ich kann das, haben wir eben schon gesehen,
ich kann das jetzt breiter ziehen,
dann bleibt das mittig und ich kann hier das irgendwie nach
unten ziehen,
dann bleibt das da
oben kleben
Ich kann jetzt aber an dem Layout auch hier sagen,
zum Beispiel hier kann ich jetzt sagen, Flow,
Set Alignment, Flowlay out Left.
Ja, kann ich übersetzen. Und dann kann ich hier mir
entsprechend so ein Flowlayout erzeugen und dann sieht das so aus,
dass wenn ich jetzt das Fenster breiter mache, ist alles links kleben bleibt.
Das kann ich auch genauso rechts machen,
aber es bleibt trotzdem noch da oben kleben.
So. Ganz anders ist das Border Layout. Das sieht so
aus. Man hat genau fünf Kinder, fünf Komponenten,
Norden, Westen, Mitte, Osten und Süden.
Und die ändern sich unterschiedlich, wenn man sie, wenn man das Fenster grüßt.
Wenn ich das breiter mache, dann seht ihr,
Westen und Osten bleiben gleich bereit und die anderen werden in ihrer Breite verändert.
Wenn ich es nach unten aufziehe, werden Norden und Süden
nicht in der Höhe verändert, sondern nur die Mittleren Elemente.
Das ist extrem praktisch und das ist tatsächlich,
wenn ihr auch immer so ein bisschen euch das vorstellt,
wie das hier in Blue Jay ist, darunter seht ihr es ja.
Das ist genau so eine Center-Komponente von einem Border Layout. Und das genau,
man sieht auch hier die Breite, wurde jetzt hier verändert,
haben sich Westen und Osten eigentlich in ihrer Breite nicht verändert,
genau wie sich dieses hier in seiner Breite ja auch nicht verändert.
Das heißt, das ist tatsächlich eine Möglichkeit,
wie man auch relativ schnell recht ansprechende Layouts hinbekommen kann.
Dann gibt es das Gridlayout, das ist etwas,
bei dem man mehrere Komponenten in einer, in einer Tabelle anordnet,
also auch hier vielleicht mal den Code mal zeigen.
Ach ne, vielleicht zeige ich erst mal, sorry,
das Border Layout, wie sieht das denn im Code aus?
Also hier Set Layout, New Border Layout und dann beim Einfügen
muss ich halt dann hier noch so eine Konstante angeben,
Border Layout North,
South Center, Rest East und dann habe ich hier entsprechend
diese Dinger eingefügt
Also das ist einfach eine weitere Parameter, den man da angeben muss.
Und bei dem Gridlayout ist es eben so ähnlich.
Ich kann hier beim Gridlayout sagen, wie viele Zeilen und Spalten
es haben soll, also drei Zeilen, zwei Spalten.
Und dann kann ich hier Elemente hinzufügen und die werden dann
eben einfach entsprechend hier aufgefüllt. Ich habe jetzt hier dreimal zwei,
ist sechs, füge aber nur fünf Elemente hinzu.
Das heißt, wenn ich mir jetzt hier das angucke,
wie das dann aussieht, dann sieht das tatsächlich so aus,
dass da eine Zelle frei bleibt.
Und jetzt ist es so, bei einem Gridlayout,
wenn das entsprechend als Layout Manager gewählt wird für eine Komponente,
dann werden alle gleich breit gelassen.
Und werden auch alle großgezogen. Wer das braucht,
dann ist es praktisch. So sieht es natürlich jetzt beknackt
aus für so ein paar Buttons
Okay, dann gibt es noch das Boxlayout, das ist auch nochmal ganz schön.
Ist eigentlich nichts weiter als ein weiteres Layout.
Auch wieder fünf Elemente, die ich da einfüge.
Und ich kann sagen, an welcher Achse hier das gelayoutet werden soll.
Also wenn ich jetzt mal so ein Boxlayout mir hier erzeuge,
dann sieht das sehr ähnlich aus wie das Flowlayout.
Aber beim Flowlayout war es so wenigstens breiter gezogen habe,
dann sieht man hier, das ist so ähnlich wie das Left-Alignment beim Flowlayout.
Aber wenn ich jetzt hier das runterziehe, dann ist das
tatsächlich hier, dann bleibt das in der Mitte.
Anders als bei dem Flowlayout. Und wenn ich jetzt hier
zum Beispiel bei dem Boxlayout Einfach sage, mach das mal an der Y-Achse.
Dann liegen die Dinger tatsächlich nicht nebeneinander, sondern übereinander.
Weil dann sieht man also, wie das dann hier aussieht.
Also auch da sieht man wieder, ich kann das jetzt größer ziehen,
kann das breiter ziehen, der kümmert sich da gar nicht drum,
macht nichts breiter und so weiter.
Und ihr könnt euch überlegen, dass man mit diesen Layout-Managern,
wenn man die geschickt schachtelt, relativ schlau seine Gui gestalten kann.
Das ist also etwas, was sehr Java-spezifisch ist,
was sehr Swing-spezifisch ist, wenn ihr mit anderen Systemen arbeitet,
ist es oft so, dass man so Gui-Bilder hat,
die dann so selber grafische Oberflächen sind,
wo man sich seine Gui sozusagen zusammenklicken kann.
Da den Code zu verstehen hinterher, ist allerdings ziemlich schwierig.
Ist oft nicht so vorteilhaft. Hier nochmal so ein Beispiel mit dem Flow-Layout.
Was man vielleicht auch nochmal zeigen könnte an dieser Stelle ist,
ich kann zum Beispiel hier in unserem kleinen Beispielsystem sagen,
ich falsch in dem... Hier, da ist ja,
Layout ist immer in der UI-Klasse.
Da habe ich ja gesagt, Set Size 27080 und jetzt kann ich hier sagen,
ups, Frame, Set Resizable, falls.
Und dann kann ich tatsächlich dieses Ding in seiner Größe nicht mehr verändern.
Wenn ich mir also jetzt hier mein Werkzeug erzeuge,
dann seht ihr hier, ich habe das Ding und ich kann hier,
ihr seht, ich gehe mit der Maus hier rüber,
es wird mir gar nicht mehr angeboten,
dieses Fenster größer zu ziehen.
Es ist also tatsächlich einfach abgeschaltet. Also das kann man tatsächlich dann
auch noch hier machen. Und da gibt es dann,
wie gesagt, ganz viele Möglichkeiten, die man diese Layouts noch beeinflussen kann.
Das ist jetzt nur mal der Überblick. Und wie gesagt,
wir haben ganz klar gesagt, die Layout-Sachen sollten alle in der UI-Klasse gekapselt sein.
Niemand anders sollte sich um Layout-Fragen kümmern als die UI-Klassen.
Das heißt, wenn ihr in einem,
nach diesen Entwurfsregeln gebauten System etwas am Layout ändern wollt,
wisst ihr sofort, wo ihr nachgucken müsst.
Das sind so die Vorteile, die man durch solche,
die man sich von solchen Entwurfsregeln verspricht, dass einfach klar ist,
wer ist für was zuständig. Gut. Das heißt,
wir haben jetzt gesehen, grundlegende Techniken zur Konstruktion reaktiver Programme.
Also am Beispiel von ABT. Und ziemlich haben wir gesehen,
dass es sehr unterschiedliche Google-Komponenten geben kann.
Buttons Labels, Listen und so weiter. Dann,
dass mir diese Listener, dieses Listener-Konzept haben,
um Anwendungscode durch Google Code, Übereignisse informieren zu lassen.
Das ist das gleiche Prinzip wie mit dem Beobachtermuster.
Tatsächlich ist es so, dass man sagen kann,
dass die Werkzeugklasse zum einen Services beobachten kann,
wenn einem Service sich was ändert, dann wird entsprechend das Werkzeug benachrichtigt.
Und aber auch eine Werkzeugklasse beobachten kann,
was in der GUI passiert und sich darüber informieren lassen kann.
Also das ist das gleiche Prinzip eigentlich,
dass man mehrere Beobachter haben kann,
Button zum Beispiel können sich natürlich auch mehrere Actionlisten da anmelden.
Das können also verschiedene Komponenten informiert werden. Und zum Schluss
haben wir noch gesehen, dass das Layout an der grafischen Oberfläche
ziemlich flexibel gestaltet werden kann mit diesen Layout-Managern.
Und jetzt kann man damals sozusagen die ersten Desktop-Systeme bauen,
also so Fett-Clients mit Jabba Swing.
Gut, und dann haben wir jetzt noch mal in der
großen Runde die Entwurfsregeln. Wir haben gesagt, vier Entwurfs,
vier Material-Elementtypen, Material in Fachwerte, Services, Werkzeuge.
Die habt ihr in den Systemen in den Übungen
auch gesehen
Und was wir jetzt auch ein bisschen gesehen haben,
ist dieser Entwurf von Materialien, von Fachwert und von Services,
der ist primär fachlich anspruchsvoll.
Da muss ich mir mal so überlegen,
was soll denn fachlich in diesen Dingern drinstecken,
wenn die Konstruktion von Werkzeugen, insbesondere wenn die größer werden,
sehr schnell technisch anspruchsvoll wird.
Also wie reagiere ich wann, was muss aktualisiert werden?
Da kann man ziemlich schnell sich auch ein bisschen kaputtlaufen bei.
So, das war heute alles zum Thema Gui.
Gibt es denn jetzt noch konkrete Fragen?
Da ist eine Frage
Ich hab's nicht verstanden, Sorva. Wenn man mich macht,
es akzeptiert, möchte ich zum Beispiel, oder wer kriegt,
zum Beispiel, der ist jetzt ein mögliches Themenvideo aus meiner Mediathek, was kann das für Werkzeuge daran machen? Ah,
okay, dann die Frage ist, was ist jetzt,
wenn ich in dieser Oberfläche von diesem Werkzeug,
wenn ich jetzt hier unterscheiden möchte,
ob etwas geklickt werden darf oder nicht,
ich möchte diesen Button also aktivieren und deaktivieren,
es gibt inzwingend die Möglichkeit, auch bei einem Button zu sagen,
kann geklickt werden oder nicht,
das kennt ihr ja aus der Mediathek und die Frage war,
an welcher Stelle ist das denn jetzt entschieden,
wo steht denn jetzt diese Entscheidung darüber,
ob das aktiviert wird oder nicht,
hat jemand
eine Antwort
Wenn wir uns diese Szene so angucken, so als Mini-System,
wo würdet ihr jetzt sagen, wer ist zuständig dafür,
den Button zu aktivieren oder zu deaktivieren, ja?
Werkzeug. Was muss ich das Ding machen, was ich
über Alkohol hergetragen habe und deine Entsprechung, ist energetisch zu aufbauen. Genau,
also er sagt, das sollte das Werkzeug sein,
also jetzt etwas konkreter sogar die Werkzeugklasse,
die Werkzeugklasse lässt sich dann von der UI,
dem Button entsprechend geben, die aktiviert den Button und also das heißt,
die Zuständigkeit liegt beim Werkzeug.
Das Werkzeug muss wissen, wann fachlich was sinnvoll ist,
wann bestimmte Buttons geklickt werden können
Meine Stimme geht gerade weg. Keine Fragen mehr jetzt bitte
. Nee, wir hatten noch eine Frage.
Ich kann mich ein bisschen rausmachen. Gibt es noch Fragen
? Keine, dann vielen Dank für heute.