Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Hi Forum,
hier eine Anfängerfrage: ich habe inzwischen recht viele JLabels und JTextfields auf diversen Panels und Tabs in einem Frame untergebracht. Ich möchte dem Anwender die Möglichkeit geben, deren Formatierung (im wesentlichen Schrift und Farben) einheitlich zu verändern. Muss ich hierzu im Code jede dieser Komponenten einzeln anfassen, oder gibt es irgend so etwas wie eine Liste aller im Frame enhaltenen Komponenten, auf die man hierzu zugreifen könnte?
Danke für eure Hilfe!
Na ja, jede Klasse, die von "Container" erbt hat die Methode "getComponents()", die dir ein Array von "Component" zurück gibt, die diesem Container mit add() zugeordnet wurden. Jede JComponent (also jede Swing Klasse) hat diese Methode.
Du könntest also mit Hilfe dieser Methode eine rekursive Methode schreiben, die dann die gewünschte Eigenschaften setzt.
Aussehen könnte das zum Beispiel so:
Java:
public final class MySwingUtilities {
public static interface Changer {
/**
* This method will be invoked, if <code>allowChange(Component)</code> returns <code>true</code>.
*
* @param c the <code>Component</code> that should be changed.
*/
public void change(Component c);
/**
* This method will check if an <code>Component</code> might be changed.
*
* @param c an <code>Component</code> that might be changed.
* @return true if the <code>Component</code> should be changed.
*/
public boolean allowChange(Component c);
}
/**
* Change <code>Component</code> recursively. An instance of the <code>Changer</code> Interface
* define which components will be changed.
*
* @param comp the root <code>Component</code>
* @param changer define which <code>Component</code> should be changed
* @param changeRoot if true, then the <code>changer</code> try to change <code>comp</code> too
*/
public static void changeComponentsRecursively(Component comp, Changer changer, boolean changeRoot) {
if (comp == null || changer == null) {
// nothing to do
return;
}
if (changeRoot && changer.allowChange(comp)) {
changer.change(comp);
}
if (comp instanceof Container) {
for (Component c : ((Container) comp).getComponents()) {
changeComponentsRecursively(c, changer, true);
}
}
}
}
Hier ein Anwendungsbeispiel: das wechseln der Hintergrundfarbe zur SystemColor.window Farbe für alle JPanel Objekte.
Java:
JFrame content = new JFrame();
// was zum JFrame hinzufügen
MySwingUtilities.changeComponentsRecursively(
content,
new Changer() {
@Override public void change(Component c) {
c.setBackground(SystemColor.window);
}
@Override public boolean allowChange(Component c) {
return c instanceof JPanel;
}
},
true
);
Kleine Anmerkung noch: Jede Swing Klasse erbt von JComponent, diese wiederrum erbt von der AWT Klasse Container, aber nicht jede AWT Component erbt von dieser Klasse. Beispielsweise hat die AWT Klasse Button nicht die Fähigkeit als Container zu fungieren, die JButton Klasse allerdings schon. D.h. also jede Swing Klasse ist ein Container, auch wenn es wenig Sinn macht. Daher sollte man die "allowChange(Component)" Methode besonders dann umfangreicher implementieren, wenn man bei Swing Klassen wie z.B. JButton die Containerfähigkeit benutzt, aber diese Componenten dann wiederum nicht geändert werden sollen. Unter Umständen könnten auch mehrfaches Casten nötig sein. Dann aber den check mit "instanceof" nicht vergessen.
Ja!!!! Super. Genau die Info, die ich gesucht habe. Und der Beispielcode funktioniert prima. Habs auch getestet für JTextfields und JButtons. Nicht funktioniert hat es allerdings mit JLabels. Liegt das an den von dir oben angesprochenen Vererbungsunterschieden?
Herzlichen Dank für deine Hilfe!
EDIT: Wenn ich oben in Zeile 11 die Bedingung "c instance of ..." weglasse und prinzipiell true returne, um alle Komponenten zu berücksichtigen, werden auch die JLabels erfolgreich verändert. (??)
Ich weiß nun nicht genau was du meinst, aber generell ist es eine gute Idee, wenn die Komponenten, die du ändern willst, bereits angezeigt werden (isVisible() == true) noch ein revalidate() und repaint() bei deinem Top-Level Container hinzufügst. Also i.d.R. bei deinem Frame Objekt.
Und wenn du bei der "allowChange(Component)" immer true zurück gibst, dann ändert er natürlich alle.
generell ist es eine gute Idee, wenn die Komponenten, die du ändern willst, bereits angezeigt werden (isVisible() == true) noch ein revalidate() und repaint() bei deinem Top-Level Container hinzufügst. Also i.d.R. bei deinem Frame Objekt.
Das hat leider nicht funktioniert. Da mein Fenster inzwischen eine sehr verschachtelte Angelegenheit aus mehreren Containern ist, habe ich auch versucht, zu allen übergeordneten Containern und nicht nur für das Top-Level Frame revalidate und repaint hinzu zu fügen. Das hat nichts gebracht. Interessanterweise werden die Labels automatisch mitverändert, wenn ich alle Panels verändere. Die mit den Labels im gleichen Panel liegenden Checkboxen allerdings bleiben unverändert. Vermutlich versteckt sich hinter dieser Ungleichbehandlung irgend eine systematische Logik, die ich noch nicht überblicken kann. Ist aber kein akut dringliches Problem, da ich ja jetzt weiß, wie ich alle Komponenten in einem Rutsch anpassen kann.
Zumindest wären mal Factory-Methods für Buttons und Labels und Co. eine gute Wahl. Dann hast Du schonmal die Erzeugung von diesen Komponenten zentralisiert, kannst Farben etc. setzen, und zwar anwendungsweit gleich.