Artikel

 
August 2009 | Artikel

Swing mit Substanz Fortsetzung, Teil 2

Teil 1   Teil 2   Teil 3   

Skinning: Painters, Button Shaper und Watermarking
Betrachtet man sich eine der zuvor vorgestellten LookAndFeel-Klassen im Sourcecode, wird man feststellen, dass sie lediglich die abstrakte Oberklasse org.jvnet.substance.SubstanceLookAndFeel erweitern und dieser im Konstruktor eine Implementierung der (ebenfalls abstrakten) Klasse org.jvnet.substance.api.SubstanceSkin übergeben. So wird beispielsweise in SubstanceOfficeBlue2007LookAndFeel eine Instanz von OfficeBlue2007Skin verwendet. Die eigentliche LAF-Logik befindet sich also in der Skin-Implementierung. Ein Skin besteht intern aus mehreren Farbschemata (intern als Implementierung des Interfaces SubstanceColorScheme realisiert) und einer Reihe sogenannter Painter (Gradient-, Decorator-, Highlight- und Border-Painter), welche das Zeichnen einzelner Bereiche der Oberfläche übernehmen. So kommt zum Beispiel der Gradient Painter immer dann zum Einsatz, wenn es darum geht, den inneren Bereich diverser Swing-Komponenten (Buttons, Checkboxes, Tables und so weiter) zu zeichnen. Decorator Painter sind für das Zeichnen spezieller Bereiche (Decoration Areas) innerhalb von Frames und Dialogen zuständig. Decoration Areas, um die sich also ein Decorator Painter kümmert, sind Bereiche wie die Titelzeile eines Fensters, die Menüzeile, den Toolbar-Bereich und noch einige mehr. Wichtig in einem Skin sind auch die Border Painter, denn diese stellen das einheitliche Zeichnen der äußeren Konturen diverser Swing-Komponenten wie Buttons, Check Boxes, Radio Buttons, Progress Bars, Tabs und Scrollbars sicher.

Mit Hilfe von Button Shapern kann man in einem Skin optional festlegen, ob ein Button eckig oder abgerundet gezeichnet werden soll. In der Default-Einstellung verwendet Substance die Klasse ClassicButtonShaper und zeichnet eckige Kanten. Will man dagegen, dass abgerundete Buttons gezeichnet werden, verwendet man stattdessen eine Instanz von StandardButtonShaper. In der Klasse MistAquaSkin, die den von Mac OS X bekannten Aqua-Look imitiert, wird beispielsweise der StandardButtonShaper zum Zeichnen der abgerundeten Buttons verwendet.

Unter "Watermarking" versteht man bei Substance die Möglichkeit, Hintergründe in einer Swing-Anwendung mit Mustern oder Bildern zu versehen. Bereits mitgeliefert wird mit dem SubstanceStripeWatermark ein Wasserzeichen, welches horizontale Linien in den Hintergrund zeichnet. Mit SubstancePlanktonWatermark ist eine weitere beispielhafte Implementierung des SubstanceWatermark-Interfaces enthalten, das ein planktonartiges Muster in den Hintergrund zaubert. Von besonderem Interesse dürfte in diesem Zusammenhang auch die Klasse SubstanceImageWatermark sein, mit der man in der Lage ist, Hintergrundbilder in eine Anwendung zu setzen. In Abbildung 2 sieht man das auf Swing basierende, bekannte Werkzeug Apache TCPMon mit einem modifizierten Office2007BlueSkin und dem JAXenter-Logo als Hintergrundbild. Die Implementierung des modifizierten Skins in Listing 3 zeigt, wie einfach es geht. Die Klasse MySkin erbt von Office2007BlueSkin, stellt den Button Shaper um, damit runde Buttons gezeichnet werden, und setzt schließlich das Wasserzeichen mit einer zuvor konfigurierten Instanz von SubstanceImageWatermark. Dabei nimmt SubstanceImageWatermark über seinen Konstruktur den Pfad zum Bild entgegen und bietet mit Hilfe der Methode setKind() eine Möglichkeit, die Anordnung des Bildes zu steuern. Die einzelnen Einstellmöglichkeiten finden sich im ImageWatermarkKind-Enum. Die Deckkraft des Hintergrundbildes stellt man über die Methode setOpacity() ein. Der Wert steht in der Defaulteinstellung auf 0.2f.

Im Zusammenhang mit Watermarks ist es außerdem wichtig zu wissen, dass in bestimmten Swing-Komponenten (Textfelder, Table, Tree) das Watermarking per Default deaktiviert ist. Will man beispielsweise das Wasserzeichen auch auf einem Textfeld darstellen, so muss dieses über eine entsprechende Client Property explizit eingeschaltet werden (siehe in Abbildung 2 das Textfeld "Target Port"). Gesetzt wird die Client Property wie folgt:

textTcpPort.setClientProperty(SubstanceLookAndFeel.WATERMARK_VISIBLE, Boolean.true)

Auch ist es derzeit nicht möglich, mehr als ein Watermark in einer Maske zu verwenden.

Im separat erhältlichen Substance Extras Pack [5] finden sich noch viele weitere Farbschemata, Skins und Watermark-Implementierungen. Auch sind hier einige zusätzliche Button Shaper enthalten, die das Erstellen von teilweise sehr ausgefallenen Buttons ermöglichen (zum Beispiel einen Button in Form eines Dinosauriers) und demonstrieren, wie vielfältig die Möglichkeiten mit Substance sind.

Listing 3:
  1. package net.teufel.substance;
  2. import org.jvnet.substance.api.SubstanceConstants.ImageWatermarkKind;
  3. import org.jvnet.substance.shaper.StandardButtonShaper;
  4. import org.jvnet.substance.skin.OfficeBlue2007Skin;
  5. import org.jvnet.substance.watermark.SubstanceImageWatermark;
  6. public class MySkin extends OfficeBlue2007Skin {
  7. public MySkin() {
  8. super();
  9. SubstanceImageWatermark watermark
  10. = new SubstanceImageWatermark("c:\\jaxenter_watermark.jpg");
  11. watermark.setKind(ImageWatermarkKind.APP_TILE);
  12. watermark.setOpacity(0.4f);
  13. this.buttonShaper = new StandardButtonShaper();
  14. this.watermark = watermark;
  15. }
  16. }
Listing 3 : Einen Skin modifizieren

Skin über API-Aufruf aktivieren
Um den modifizierten Skin nun zu aktivieren, könnte man eine Klasse MyLookAndFeel schreiben, die von BasicLookAndFeel erbt und MySkin verwendet (Listing 4). Diese neue LookAndFeel-Klasse könnte man dann auf einem der bereits beschriebenen Wege aktivieren.

Listing 4:
  1. package net.teufel.substance;
  2. import org.jvnet.substance.SubstanceLookAndFeel;
  3. public class MyLookAndFeel extends SubstanceLookAndFeel {
  4. public MyLookAndFeel() {
  5. super(new MySkin());
  6. }
  7. }
Listing 4: Ein eigenes, einfaches LookAndFeel

Es geht jedoch noch einfacher. Mit API-Aufrufen ist man nämlich in der Lage, einen Skin direkt anzusteuern und hat so die Möglichkeit, gänzlich auf LAF-Klassen zu verzichten. Die API-Aufrufe werden von der Klasse SubstanceLookAndFeel gekapselt. Ruft man auf dieser Klasse die statische Methode setSkin() auf und übergibt entweder eine Instanz des zu aktivierenden Skins bzw. den Klassennamen des Skins (als String), dann erzeugt Substance im Hintergrund ein entsprechendes LAF und startet dieses über den UIManager. Es ist wichtig zu verstehen, dass dieses Verfahren auch dann funktioniert, wenn man vorher keine der LookAndFeel-Klassen aus Substance bemüht hat. Das Entwicklerteam von Substance empfiehlt, diese Methode zum Aktivieren von LAFs bzw. Skins immer den Vorrang zu geben, weil setSkin() insbesondere auch dafür sorgt, dass beim Umstellen alle Fenster auf höchster Ebene neu gezeichnet werden (mittels SwingUtitlities.updateComponentTreeUI).

Teil 1   Teil 2   Teil 3   

Anzeige

Kommentare

Gravatar RPR 18.08.2009
um 21:41 Uhr
Vielen Dank für diesen informativen Artikel!:-) #zitieren
Gravatar Aljoscha Rittner 19.08.2009
um 07:51 Uhr
Moin!

Der Artikel und die Arbeit eines Freundes brachten mich dazu ein Substance Plugin für die NetBeans Platform zu entwickeln. Das Substance-Team hat ja ihr eigenes Plugin für NB aufgegeben. Zusätzlich wird der Einstaz erschwert, weil hard-coded eine Exception wirft, wenn man nicht im EDT das GUI erzeugt oder ändert (siehe Infos hier: http://www.pushing-pixels.org/?p=368). Ich bin zwar auch für ein Early-Fail, aber hard-coded hat man bei so großen Anwendungen wie NetBeans kaum eine Chance überhaupt aus den Sumpf der Stacktraces herauszukommen, um irgendwas zu fixen. Es wäre schön gewesen, wenn man dazu ein Legacy-Flag gehabt hätte. So musste ich die Substance-Sourcen patchen.
Ich werde mich aber dafür einsetzen, dass mal ein Blick auf die Problembereiche geworfen werden, so dass in Zukunft Substance ungepatcht auf mit NetBeans und der NetBeans Platform läuft. Hier das Plugin: http://tinyurl.com/substancenbplugin

Toni Epple (ebenfals NB Dream Team Member und Consulter) arbeitet parallel an Verbesserungen, damit wir in NB UI-Delegates haben. Damit können dann Tab und andere spezielle Swing-Komponenten besser von den Skins manipuliert werden.

Beste Grüße,
Josch.
#zitieren
Gravatar Toni Epple 19.08.2009
um 23:18 Uhr
Hallo Marc, danke für den guten Artikel.
Substance ist wirklich eines der besten Swing Look & Feels.

Hi Josch, als ich das "Moin!" in den Kommentaren gelesen habe, war mir schon klar, wer hier schreibt ;-). Ich bin schon gespannt auf die nächsten News zu Deinem Projekt! Ich werde auch mein bestes versuchen damit NetBeans 6.8 wieder mehr Substanz erhält...

--Toni
#zitieren
Gravatar Claudi 09.02.2010
um 16:55 Uhr
Hi,
erstmal vielen Dank für diesen informativen Artikel.
Ich hab bzw. sagen wir mal wollt nachdem ich das gelesen hatte mit Flamingo arbeiten. Bin aber leider nicht weit gekommen. Im Prinzip, um es kurz zu machen möchte ich auf diese Weise jemanden suchen der mir zu dem Thema ein bisschen was erklären kann. Wenn sich irgendwer dazu bereit erklärt, kann er/sie sich ja bei mir unter sulli@spamavert.com melden (werde in nächster Zeit die Spamadresse täglich checken).
#zitieren

Anzeige

zurück zum Seitenanfang