# Eigenes Look & Feel machen!



## javaprogger1987 (8. Februar 2005)

So, hier auch mal ein Tipp von mir  :

Die Look & Feel's in Java ermöglichen jedem ein individuelles Aussehen
für sein Programm zu erstellen. Da das aber nicht ganz so einfach hab ich 
mal hier eine kleine Erklärung. Folgendes muss für ein eigenes Look & Feel
gemacht werden. (Hab mal ein Programm geschrieben, dass weite Teile der 
Arbeit übernimmt). Damit es nicht ganz so kompliziert ist, reicht es mit
einem vorgefertigten Look & Feel anzufangen (sehr gut geeignet ist das Metaltheme)
und dieses nur anzupassen. Dazu folgendes Programm: * 

1. Alle untenstehenden Werte anpassen (replaceWhat.. Werte können so gelassen werden)
2. Programm ausführen

Anschließend hat man angegebenen Verzeichnis jede Menge neue Dateien.
Hier die wichtigsten:
- Default...Theme.java (... im Beispiel unten = Test, also DefaultTestTheme.java)
In dieser Klasse werden alle Farben und Schriftarten festgelegt.
Die Schriftarten, Styles und Größen am Anfang des Dokuments (bei der Metal-Vorlage)
Die Farben ab Zeile 96 (bei der Metalvorlage)

Eine berechtigte Frage ist nun, wie soll man wissen, welcher Wert für was verantwortlich ist.
Dazu macht man folgendes:
Nehmen wir mal an, man will zuerst mal die Farben der Scrollbars ändern, mit eines der
wichtigsten Elemente:

Dazu öffnet man die Klasse ...LookAndFeel.java .
Dort sucht man dann die Stelle, an der die Werte für die Scrollbars festgelegt
werden, im Metaltheme wäre das bei Zeile 793.
Beim Hintergrund (Scrollbar.background) wird also der Wert getControl() verwendet.
Nun gibt es folgende Möglichkeiten:
1. Man ersetzt getControl() direkt mit der gewünschten Farbe, z.B. new Color(100,100,100)
2. Man möchte, dass sich alle Komponenten, die diese Farbe haben auch ändern

Beim 2. Punkt macht man folgendes:

1. Die Methode getControl() ausfindig machen (Bei der Metalvorlage 1299)
(Alle die JBuilder benutzen können den Cursor auf getControl() setzen und STRG-Enter drücken)
2. Dort findet man bei der Metalvorlage folgendes vor:
return getCurrentTheme().getControl();
3. Also herausfinden was getCurrenTheme zurückliefert und dort die Methode getControl()
angucken.
4. Dann findet man heraus, das die Methode eine Instanz der Klasse ...Theme zurückgibt, im 
Beispiel also TestTheme.
5. In dieser Klasse findet man dann schließlich, das die Methode abstrakte 
Methode getPrimary3() zuletzt aufgerufen wird.
6. Eine Implementierung dieser Klasse finden wir aber in Default...Theme.java,
d.h. wir suchen nur noch dort nach getPrimary3(), diese liefert die
ColorUIRessource primary3 zurück, welche nun geändert werden kann.
7. Das wars, ähnlich funktioniert es mit Schriftarten etc.

Nun gibt es noch folgende Möglichkeiten:
- Das komplette Aussehen der Komponenten verändern

Um das zu bewerkstelligen, nehme ich wieder das Beispiel Scrollbar.
Möchte man z.B. die beim Metaltheme vorhanden Punkte auf der Scrollbar entfernen,
macht man folgendes:

1. Man sucht sich in der Klasse ...LookAndFeel.java das Feld uiDefaults[] (Bei Metal Z.180)
Dort sucht man dann den Wert für "ScrollBarUI" im Beispiel testPackageName + "TestScrollBarUI"
D.h. wir suchen die Klasse "TestScrollBarUI.java".

2. In dieser Klasse findet man dann auch relativ schnell die Methode "paintThumb",
welche wohl für das zeichnen des bewegbaren Teiles der Scrollbar verantwortlich ist.
Schaut man sich diese Methode genauer an (und versteht sie ) fallen einem die
Zeilen :
bumps.setBumpArea( thumbBounds.width - 6, thumbBounds.height - 7 );
bumps.paintIcon( c, g, 3, 4 );
auf, denn es bleiben keine anderen für das Zeichnen der Punkte übrig,
da nirgendwo eine Schleife vorhanden ist.
Kommentiert man diese beiden Zeilen aus (noch einmal im else-Teil darunter)
werden die Punkte nicht mehr angezeigt (Die Klasse ...Bumps.java ist für die Punkte verantwortlich)

Will man das Look & Feel nun für sein Programm verwenden, kompiliert man alles und
sorgt dafür, dass das Package im Classpath vorhanden ist.

In eigenen Programm baut man folgende Methode ein:
(Packagenamen anpassen)

private void switchLookAndFeel(Container f) {
try {
UIManager.setLookAndFeel(
"de.tv.testui.test.TestLookAndFeel");
}
catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace(System.out);
}
catch (IllegalAccessException ex) {
ex.printStackTrace(System.out);
}
catch (InstantiationException ex) {
ex.printStackTrace(System.out);
}
catch (ClassNotFoundException ex) {
ex.printStackTrace(System.out);
}
SwingUtilities.updateComponentTreeUI(f);
}
und ruft nach erzeugen des Frames (oder was sonst) die Methode
mit switchLookAndFeel(jFrame1); auf.

Hoffe das klappt so bei mir gings 



```
/**
* <p>Überschrift: Look & Feel Preparer</p>
* <p>Beschreibung: </p>
* <p>Copyright: Copyright (c) 2005</p>
* <p>Organisation: None</p>
* @author Tobias Viehweger
* @version 1.0
* 
*/
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class LookAndFeelRename {
//Hier ändern ----------------- 
String pathToFiles = "C:\\Programme\\Java\\j2sdk1.4.2\\src\\javax\\swing\\plaf\\metal";
 
//Sollte mit package übereinstimmen
String outputPath = "C:\\myprojects\\de\\tv\\testui\\test";
//Name des Ursprungs-Look-And-Feel (hier z.B. MetalLookAndFeel.java)
String replaceWhat1 = "Metal";
String replaceWhat2 = "metal";
String replaceWhat3 = "METAL";
//Name des neuen Look-And-Feels
String replaceWith1 = "Test";
String replaceWith2 = "test";
String replaceWith3 = "TEST";
//Package-Namen (Wichtig Nicht package davorschreiben, und auch das ; weglassen)
String oldPackage = "javax.swing.plaf.metal";
String newPackage = "de.tv.testui.test";
//----------------------------
public LookAndFeelRename() {
	//Dateien kopieren, Variablen ersetzen, und umbennen -----
	//Ausgabeverzeichnis erstellen
	File outDir = new File(outputPath);
	outDir.mkdirs();
	//Dateien kopieren
	File inDir = new File(pathToFiles);
	File[] files = inDir.listFiles();
	for (int i = 0; i < files.length; i++)
	{
	 copyFile(files[i], outDir);
	 //Ausgabe
	 System.out.println("Konvertiere Datei "+files[i].getName()+ " um...");
	}
	//---------------------------------------------------------
}
private void copyFile(File src, File outDir)
{
	String outFile = outDir.getPath() + "\\";
	outFile += src.getName().replaceAll(replaceWhat1, replaceWith1);
	try
	{
	 RandomAccessFile rafIn = new RandomAccessFile( src, "r" );
	 RandomAccessFile rafOut = new RandomAccessFile( outFile, "rw" );
	 String line = rafIn.readLine();
	 while (line != null)
	 {
		line = replace(line);
		rafOut.writeBytes(line + "\r\n");
		line = rafIn.readLine();
	 }
	 rafIn.close();
	 rafOut.close();
	}
	catch ( IOException ex )
	{
	}
}
private String replace(String where)
{
	String ret = where;
	//Packagenamen und alles andere ersetzen
	if (ret.indexOf(oldPackage) != -1)
	 ret = ret.replaceFirst(oldPackage, newPackage);
	if (ret.indexOf(replaceWhat1) != -1)
	 ret = ret.replaceAll(replaceWhat1, replaceWith1);
	if (ret.indexOf(replaceWhat2) != -1)
	 ret = ret.replaceAll(replaceWhat2, replaceWith2);
	if (ret.indexOf(replaceWhat3) != -1)
	 ret = ret.replaceAll(replaceWhat3, replaceWith3);
	return ret;
}
public static void main(String[] args) {
	LookAndFeelRename lookAndFeelRename1 = new LookAndFeelRename();
}
}
```


----------



## Thomas Darimont (8. Februar 2005)

Hallo!

Das ist doch schon mal was  
Prima Tobias! Aber du solltest in deinen Programmen nicht davon ausgehen das jeder das src.zip entpackt... ;-)

Gruß Thomas


----------



## javaprogger1987 (9. Februar 2005)

Ups das hab ich wohl vergessen zu erwähnen...
Also -> erst noch die src.zip entpacken ;D


----------



## Thomas Darimont (12. Februar 2005)

Hallo!

Auch nett:
http://www-106.ibm.com/developerworks/java/library/j-synth/

Gruß Tom


----------



## javaprogger1987 (12. Februar 2005)

Thomas Darimont hat gesagt.:
			
		

> Hallo!
> 
> Auch nett:
> http://www-106.ibm.com/developerworks/java/library/j-synth/
> ...


 Ja, aber dafür braucht der Nutzer die JRE in der Version 5 oder Die ist noch nicht so sonderlich verbreitet glaub ich, und ich brauchte das für ein Webprojekt. Nur wenige Nutzer würden sich dann das ganze JRE neu laden..
Davon mal abgesehen ist das natürlich sehr praktisch, weil man dann auch wahrscheinlich bald Editor die das unterstützen finden wird.


----------



## jal1976 (17. Januar 2010)

ich weiß das dieser Thread sschon "etwas" älter ist, mich würde aber trotzdem interessieren da ich im Moment nicht die Zeit habe mir das genauer anzuschauen ob man auch z.B. die Form der Buttons so verändern kann. Also anstatt rechteckig dann z.B. abgerundet...

lg
jal1976


----------



## DeKugelschieber (17. Januar 2010)

das würde mich auch mal interessieren


----------



## zeja (18. Januar 2010)

Am einfachsten geht das heute wohl mit dem Synth Look And Feel: http://www.ibm.com/developerworks/java/library/j-synth/


----------



## Jellysheep (22. Januar 2010)

Hi, 
ich hab den Code von Javaer mal ausprobiert, er funktioniert wunderbar! 
Was mich allerdings stört, sind JButton & JTextField ect, sie haben keinen Rahmen/Border mehr. 
Hat Sun die Border aus dem src.zip-Ordner entfernt? Oder wie bekommt man die Border wieder dazu?
Wenn man in AbcLookAndFeel.java zum Beispiel diese Zeile ändert:

```
Object buttonBorder = 
                new SwingLazyValue("javax.swing.plaf.abc.AbcBorders",
                      "getButtonBorder");
//in die hier ändern:
Object buttonBorder = 
                new SwingLazyValue("javax.swing.plaf.metal.MetalBorders",
                      "getButtonBorder");
```
Dann erscheint der Border auch. Woran liegt das?


----------



## Jellysheep (22. Januar 2010)

Die Lösung ist ganz einfach, man muss nur das hier einfügen:

```
b.setBorder(new AbcBorders.ButtonBorder());
```


----------



## SpySpooKy (15. März 2010)

Jellysheep hat gesagt.:


> Die Lösung ist ganz einfach, man muss nur das hier einfügen:
> 
> ```
> b.setBorder(new AbcBorders.ButtonBorder());
> ```



Hi Jellysheep,
habe das selbe Problem, wo genau hast du das eingefügt?

Viele Grüße, Mo


----------



## SpySpooKy (15. März 2010)

Okay, wo du das eingefügt hast ist mir jetzt klar, aber das ist ja eine schlechte Lösung des Problems.
Eigentlich sollte das innerhalb des LookAndFeels geschehen, zB. hast du auf die ButtonBorder einer JOptionMessage keinen Einfluss, die bleiben dann weiterhin ohne Rahmen.


Habe das Problem jetzt folgendermaßen gelöst:

```
Object buttonBorder = new SwingLazyValue("abc.ABCBorders", "getButtonBorder");
```
durch den direkten Aufruf ersetzen

```
Object buttonBorder = ABCBorders.getButtonBorder();
```
oder:

```
Object buttonBorder = new ABCLazyValue("abc.ABCBorders", "getButtonBorder");
```

keine Ahnung, was man da jetzt besser nimmt, bin noch am testen 

Viele Grüße, Mo


----------

