Moderne Bedienkonzepte unter Swing

Java-Toolkits erweitern Swing um plattformspezifische GUI-Objekte, die das Konzept des kleinsten gemeinsamen Nenners durchbrechen.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 19 Min.
Von
  • Thomas Künneth
  • Christian Kirsch
Inhaltsverzeichnis

Microsoft und Apple versuchen immer wieder, die Bedienung ihrer Betriebssysteme und Anwendungen durch neue Komponenten zu vereinfachen. Die aus Office 2007 bekannten Ribbons oder die Seitenleisten des Finders und iTunes können Java-Entwickler auch in Swing-Anwendungen einsetzen.

Die ersten Java-Versionen stellten Entwicklern nur sehr wenige Bedienelemente für den Bau von Benutzeroberflächen zur Verfügung. Das Abstract Window Toolkit (AWT) verwendete hierzu Komponenten des Wirtssystems, damit sich Java-Programme wie ihre nativen Pendants verhielten. Allerdings konnte das AWT nur diejenigen Bedienelemente anbieten, die auf allen damals unterstützten Plattformen verfügbar waren. Zudem erschwerten konzeptionelle Unterschiede eine plattformübergreifende Abbildung, zumal der Funktionsumfang von Komponenten je nach Wirtssystem variierte. Es stellte sich schnell heraus, dass dieser kleinste gemeinsame Nenner nicht ausreichte, um ansprechende und anwenderfreundliche Benutzeroberflächen zu realisieren.

Mit dem zunächst als separaten Download erhältlichen, aber seit Java 1.2 zur Standardklassenbibliothek gehörenden Swing verfolgt Sun deshalb einen anderen Ansatz: Die Klassenbibliothek kontrolliert Aussehen und Verhalten von Bedienelementen vollständig. Somit stehen (aus Sicht des Entwicklers) alle Funktionen und Merkmale einer Komponente auf jeder Plattform zur Verfügung. Das Aussehen von Swing-Komponenten lässt sich durch so genannte Look and Feels beeinflussen. Eine Schaltfläche kann sich so präsentieren, wie ein Windows-, Mac- oder Linux-Anwender es erwarten würde; zumindest theoretisch, denn die Praxis zeigt leider, dass Swing die jeweiligen Originale keineswegs immer optimal nachbildet. Manchmal stimmt der verwendete Zeichensatz nicht, ein andermal werden Farben oder Verläufe nicht richtig umgesetzt. Einige Projekte versuchen deshalb, diese Defizite auszugleichen. Das auf java.net gehostete WinLAF beispielsweise korrigiert zahlreiche Defekte von Suns Implementierung des Windows Look and Feel. Die Projekthomepage gibt einen Überblick über die behobenen Mängel.

Das von Werner Randelshofer programmierte Quaqua verbessert und erweitert nicht nur Apples Java-Version der Benutzeroberfläche Aqua, sondern stellt dem Entwickler zwei neue Komponenten zur Verfügung. Quaqua lässt sich sinnvoll nur unter Mac OS X verwenden. Die Klassenbibliothek wird wahlweise unter der LGPL oder einer modifizierten BSD-Lizenz zur Verfügung gestellt. Um sie in eigenen Programmen zu verwenden, lädt man von der Projekthomepage die Datei quaqua-5.0.nested.zip herunter und entpackt sie in ein beliebiges Verzeichnis. Anschließend fügt man das Archiv dist/quaqua.jar dem Klassenpfad hinzu. Die beiden Dateien libquaqua.jnilib und libquaqua64.jnilib müssen im Pfad für native Bibliotheken enthalten sein. Eclipse und Netbeans machen das Hinzufügen benutzerdefinierter Bibliotheken sehr einfach. Der englischsprachige Artikel The Java Extension Mechanism zeigt den Einsatz von Klassenbibliotheken mit nativen Komponenten außerhalb einer IDE.

Rückfragen, ob der Anwender ein geändertes Dokument speichern oder verwerfen will, erscheinen unter Mac OS X als Dokument-modale Dialoge. So genannte Sheets sind stets an ein Fenster gebunden und werden beim Verschieben ebenfalls bewegt. Abbildung 1 zeigt eine solche Nachfrage durch das Programm TextEdit. Klickt der Anwender auf Sichern, schließt sich das Sheet und wird durch eine Dateiauswahl ersetzt, die ebenfalls als Dokument-modaler Dialog realisiert ist. Quaqua stellt mit der Klasse ch.randelshofer.quaqua.JSheet eine Implementierung dieses Konzepts zur Verfügung. Das in Listing 1 gezeigte Programm QuaquaTestApp1 zeigt die Verwendung von Quaqua und JSheet.

Die Anweisung UIManager.setLookAndFeel(QuaquaManager.getLookAndFeel()); setzt Quaqua als Look and Feel, gewährleistet also, dass die Anwendung von den Korrekturen und Verbesserungen der Klassenbibliothek profitiert. Sie sollte möglichst früh im Code stehen. Ebenfalls sehr interessant ist das folgende Quelltextfragment. Es kennzeichnet Fenster mit nicht gesicherten Änderungen:

frame.getRootPane().putClientProperty("Window.documentModified",
Boolean.TRUE);

Client Properties wie diese versorgen Komponenten mit zusätzlichen Informationen, die beispielsweise durch Look-and-Feel-Implementierungen ausgewertet werden können. Quaqua macht ausgiebig Gebrauch von diesem Konzept. So legt die Eigenschaft Quaqua.OptionPane.destructiveOption fest, welche Schaltfläche einer JOptionPane[code] eine destruktive Aktion auslöst. Unter Aqua erscheint sie leicht versetzt. [code]JSheet.showSheet() zeigt ein Sheet an. Solange es sichtbar ist, blockiert es Eingaben in das ihm zugeordnete Fenster. Um seinen Rückgabewert zu erfragen, müssen Anwendungen einen SheetListener installieren.

Der Finder des Mac kennt eine Form der Listendarstellung, in der er Unterverzeichnisse spaltenweise von links nach rechts anordnet. Quaqua stellt die Komponente ch.randelshofer.quaqua.JBrowser zur Verfügung, mit der sich solche Anzeigen bequem realisieren lassen. Sie arbeitet mit Instanzen von javax.swing.tree.TreeModel, ist also (wie sein natives Vorbild, die Cocoa-Komponente NSBrowser) flexibel einsetzbar, das heißt nicht auf Dateien und Verzeichnisse beschränkt. Das folgende Quelltextfragment zeigt das Erzeugen der Listendarstellung in Abbildung 2.

private Component createContent() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultTreeModel treeModel = new DefaultTreeModel(root);
for (int i = 1; i <= 3; i++) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(
Integer.toHexString(i));
for (int j = 1; j <= i; j++) {
DefaultMutableTreeNode child = new DefaultMutableTreeNode(
Integer.toString(j));
child.add(new DefaultMutableTreeNode(Integer.toString(i * j)));
node.add(child);
}
root.add(node);
}
JBrowser browser = new JBrowser(treeModel);
return browser;
}

Die zurück gegebene Instanz von JBrowser kann beispielsweise einem JPanel hinzugefügt werden: frame.getContentPane().add(createContent());

Auch das auf code.google.com gehostete Projekt macwidgets stellt Swing-Entwicklern einige neue Bedienelemente aus Mac OS X zur Verfügung. Die Komponenten zeichnet die unter der LGPL veröffentlichte Klassenbibliothek selbst. Dabei greift sie allerdings auf auf Ressourcen zu, die nur unter Mac OS X 10.5 (Leopard) vorhanden sind. Um macwidgets auszuprobieren, lade man die aktuelle Version (beispielsweise mac_widgets-0.9.2.zip) herunter und füge die enthaltenen .jar-Archive mac_widgets.jar und forms-1.2.1.jar (JGoodies Forms) dem Klassenpfad hinzu. Die Dokumentation der Bibliothek ist derzeit nur online verfügbar. Quelltexte sowie Demoanwendungen stellt ein Subversion-Repository bereit.

Das in Listing 2 dargestellte Programm MacWidgetsDemoApp1 zeigt die Verwendung einiger durch die Klassenbibliothek zur Verfügung gestellten Bedienelemente: eine Seitenleiste, eine Fußzeile sowie die Mac-typische Toolbar. Nach dem Instantiieren und Parametrisieren liefert getComponent() stets eine Swing-Komponente, die Sie beliebigen Containern hinzufügen können. Auf ein paar Spezialitäten sei besonders hingewiesen. Ausdrücke wie

new ImageIcon(Toolkit.getDefaultToolkit().getImage(
"NSImage://NSDotMac").getScaledInstance(
16, 16,Image.SCALE_SMOOTH));

erzeugen Icons unmittelbar aus Mac OS X-Ressourcen. Die Seite System-Provided Images auf Apples Developer Connection zeigt, welche Symbole zur Verfügung stehen. Allerdings stimmen die Konstantennamen nicht mit der URL bei getImage() übereinstimmen. So entspricht die Konstante NSImageNameDotMac dem String NSDotMac. Aus NSImageNameComputer wird NSComputer. Der Parameter für [getImage() lautet demnach "NSImage://NSComputer".

Um einem Fenster den typischen, in Abbildung 3 gezeigten Leopard-Look zu verpassen, sollte das Programm die Methode makeWindowLeopardStyle() aufrufen. Da sich Fenster unter Mac OS X auch durch Klicken in den Toolbarbereich verschieben lassen, ist es ferner ratsam, mit installWindowDraggerOnWindow() einen entsprechenden Maushandler zu installieren.

Auch Microsoft feilt beständig an seiner Benutzeroberfläche. Einer Revolution gleich kam die in Office 2007 praktizierte Abkehr von der klassischen Menüleiste und der Toolbar. Alle Funktionen einer Office-Anwendung stehen stattdessen über ein komplexes Bedienelement zur Verfügung, das als Streifen die komplette Breite des Programmfensters einnimmt. Abbildung 4 zeigt ein solches Ribbon aus Microsoft Excel 2007.

Obwohl es sich primär auf das Erweitern bestehender Office-Ribbons bezieht, liefert das Microsoft-Papier 2007 Office System Document: UI Style Guide for Solutions and Add Ins doch einen ersten Einblick in die Ideen und Konzepte, die diesem Bedienelement zugrunde liegen. Wie wichtig Microsoft die neue Bedienphilosophie ist, zeigen konkrete Pläne des Softwarekonzerns, Ribons auch in dem für das Jahr 2010 erwarteten Vista-Nachfolger einzusetzen.

Die auf java.net gehostete Flamingo Swing Component Suite stellt Java-Versionen von einigen neuen Bedienelementen aus Windows Vista und Office 2007 zur Verfügung, unter anderem Ribbons. Die Klassenbibliothek steht unter der BSD-Lizenz und ist ab Java SE 6.0 lauffähig. Um Flamingo in eigenen Programmen einzusetzen, lädt man von der Projekthomepage das Archiv flamingo-all.zip der aktuellen Version herunter und entpackt es in ein beliebiges Verzeichnis. Das Archiv enthält die Quelltexte, fertig übersetzte und als Jar gepackte Klassen sowie die vollständige Dokumentation.

Das in Listing 3 gezeigte Programm FlamingoTestApp1 gibt einen ersten Einblick in den Realisierung von Ribbons in Swing. Um es ausführen zu können, muss das Archiv drop\flamingo.jar im Klassenpfad stehen.

Die Klasse org.jvnet.flamingo.ribbon.JRibbonFrame realisiert ein Swing-Toplevel-Fenster (JFrame) mit bereits eingebettetem Ribbon. Die Methode getRibbon() konfiguriert und befüllt diese Instanz von org.jvnet.flamingo.ribbon.JRibbon. Abbildung 5 zeigt einige konzeptionelle Bausteine dieser Komponente. Ein Taskbar genannter Bereich enthält häufig benutzte Befehle. Word und Excel platzieren hier beispielsweise die Funktion zum Speichern eines Dokuments. addTaskbarComponent() fügt einem Ribbon eine Taskbar-Komponente hinzu.

Logische Funktionsblöcke heißem RibbonTask. FlamingoTestApp1 enthält eine solche aus zwei Ribbon-Bändern bestehende Task. Die Anweisung

RibbonTask task1 = new
RibbonTask("Allgemein", ribbonBand1, ribbonBand2);

erzeugt die Task "Allgemein" und fügt ihr zwei Instanzen der Klasse org.jvnet.flamingo.ribbon.JRibbonBand hinzu. Ribbon-Bänder sind grundlegende Bausteine eines Ribbons. Sie können so genannte Command Buttons, klassische Swing-Komponenten und Galerien enthalten. Ein Ribbon-Band wird auf folgende Weise erzeugt: JRibbonBand ribbonBand2 = new JRibbonBand("Ansicht", getIcon());

Flamingo setzt an zahlreichen Stellen auf in ihrer Größe veränderliche Symbole und führt hierzu das Interface org.jvnet.flamingo.common.icon.ResizableIcon ein. Die Klasse FlamingoTestApp1 zeigt eine Trivialimplementierung. Richtige Anwendungen könnten auf Icons in einem Vektorformat setzen. Die Bibliothek bietet hierfür Unterstützung in Gestalt der Klasse org.jvnet.flamingo.svg.SvgBatikResizableIcon, deren Methode getSvgIcon() SVG-Dateien (Scalable Vector Graphics) liest.

Die derzeit in Entwicklung befindliche Version 4 von Flamingo wird einige noch vorhandene Unterschiede zu Microsofts Implementierung ausgleichen. Beispielsweise können Ribbons dann die aus Office 2007 bekannten runden Anwendungsschaltflächen erhalten, die ein großflächiges Menü erscheinen lassen. Auch die Position der Taskbar wird sich dem Original nähern.

Sowohl Microsoft als auch Apple haben ihre Bedienoberflächen in den letzten Jahren um wichtige neue Konzepte erweitert. Die nächsten Jahre werden zeigen, wie konsequent Redmond in seiner Abkehr von der klassischen Kombination aus Menüleiste und Toolar wirklich ist. Die Oberfläche von Windows 7 und seinen Anwendungen wird hierfür ein erster Test sein. Interessierten Java-Entwicklern stehen schon jetzt entsprechende Klassenbibliotheken zur Verfügung. Allerdings darf man bei aller Euphorie über neue Bedienelemente nicht vergessen, dass Sun einst mit dem Motto "Write once, run everywhere" angetreten ist. Der Einsatz von Bibliotheken, die Anwendungen zumindest optisch an eine Plattform binden, sollte daher reiflich überlegt sein.

Thomas Künneth
arbeitet als Spezialist für Client-Technologien im Team Anwendungsarchitektur einer großen Bundesbehörde. Neben zahlreichen Artikeln hat er zwei Bücher über Java und Eclipse veröffentlicht.

package com.thomaskuenneth.quaqua;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.UIManager;

import ch.randelshofer.quaqua.JSheet;
import ch.randelshofer.quaqua.QuaquaManager;
import ch.randelshofer.quaqua.SheetEvent;
import ch.randelshofer.quaqua.SheetListener;

public class QuaquaTestApp1 {

private static final String SAVE = "Sichern ...";
private static final String DONT_SAVE = "Nicht sichern";
private static final String CANCEL = "Abbrechen";

private JFrame frame;

public QuaquaTestApp1() {
// Look and Feel setzen
try {
UIManager.setLookAndFeel(QuaquaManager.getLookAndFeel());
} catch (Exception e) {
}
// Fenster erzeugen
frame = new JFrame("Quaqua Demo");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.getContentPane().add(
new JLabel("Bitte schlie§en Sie das Fenster."));
frame.setBounds(100, 50, 400, 300);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
quit();
}
});
// anzeigen, dass Änderungen am Dokument vorgenommen wurden
frame.getRootPane().putClientProperty("Window.documentModified",
Boolean.TRUE);
// Fenster anzeigen
frame.setVisible(true);
}

private void quit() {
JOptionPane pane = new JOptionPane(
"<html>"
+ UIManager.getString("OptionPane.css")
+ "<b>Möchten Sie die Änderungen am Dokument sichern?</b><p>"
+ "Ihre Änderungen werden verworfen, wenn Sie sie nicht sichern.",
JOptionPane.WARNING_MESSAGE);
Object[] options = { SAVE, CANCEL, DONT_SAVE };
pane.setOptions(options);
pane.setInitialValue(SAVE);
pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
new Integer(2));
JSheet.showSheet(pane, frame, new SheetListener() {
public void optionSelected(SheetEvent evt) {
Object value = evt.getValue();
if (CANCEL.equals(value)) {
frame.setEnabled(true);
} else if (DONT_SAVE.equals(value)) {
System.exit(0);
} else if (SAVE.equals(value)) {
save();
}
}
});
}

private void save() {
final JFileChooser fileChooser = new JFileChooser();
JSheet.showSaveSheet(fileChooser, frame, new SheetListener() {
public void optionSelected(final SheetEvent evt) {
if (evt.getOption() == JFileChooser.APPROVE_OPTION) {
File file = evt.getFileChooser().getSelectedFile();
System.err.println(file);
System.exit(0);
}
}
});
}

public static void main(String[] args) {
new QuaquaTestApp1();
}
}
package com.thomaskuenneth.macwidgets;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;

import com.explodingpixels.macwidgets.BottomBarSize;
import com.explodingpixels.macwidgets.MacButtonFactory;
import com.explodingpixels.macwidgets.MacIcons;
import com.explodingpixels.macwidgets.MacUtils;
import com.explodingpixels.macwidgets.MacWidgetFactory;
import com.explodingpixels.macwidgets.SourceList;
import com.explodingpixels.macwidgets.SourceListCategory;
import com.explodingpixels.macwidgets.SourceListControlBar;
import com.explodingpixels.macwidgets.SourceListItem;
import com.explodingpixels.macwidgets.SourceListModel;
import com.explodingpixels.macwidgets.TriAreaComponent;
import com.explodingpixels.widgets.PopupMenuCustomizerUsingStrings;
import com.explodingpixels.widgets.WindowUtils;

public class MacWidgetsDemoApp1 {

private JFrame f;

public MacWidgetsDemoApp1() {

// Fenster erzeugen
f = new JFrame("MacWidgets-Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MacUtils.makeWindowLeopardStyle(f.getRootPane());
WindowUtils.createAndInstallRepaintWindowFocusListener(f);

// Inhaltsbereich füllen
f.setContentPane(createGUI());

// Fenster anzeigen
f.pack();
f.setLocation(100, 50);
f.setVisible(true);
}

private Container createGUI() {
JPanel cp = new JPanel(new BorderLayout());
cp.add(createToolbar(), BorderLayout.NORTH);
cp.add(createSourceList(), BorderLayout.CENTER);
cp.add(createBottomBar(), BorderLayout.SOUTH);
return cp;
}

private Component createToolbar() {
// Toolbar erzeugen
TriAreaComponent toolBar = MacWidgetFactory.createUnifiedToolBar();


// Fenster kann durch Anklicken der Toolbar verschoben werden
toolBar.installWindowDraggerOnWindow(f);


// zwei Icons erzeugen
Icon preferences = new ImageIcon(Toolkit.getDefaultToolkit().getImage(
"NSImage://NSPreferencesGeneral").getScaledInstance(32, 32,
Image.SCALE_SMOOTH));
Icon gear = new ImageIcon(Toolkit.getDefaultToolkit().getImage(
"NSImage://NSAdvanced").getScaledInstance(32, 32,
Image.SCALE_SMOOTH));

// der Toolbar hinzufügen
toolBar.addComponentToLeft(MacButtonFactory
.makeUnifiedToolBarButton(new JButton("Preferences",
preferences)));
toolBar.addComponentToRight(MacButtonFactory
.makeUnifiedToolBarButton(new JButton("Advanced", gear)));
return toolBar.getComponent();
}

private Component createSourceList() {

// zwei Icons erzeugen
Icon blueGlobeIcon = new ImageIcon(Toolkit.getDefaultToolkit()
.getImage("NSImage://NSDotMac").getScaledInstance(16, 16,
Image.SCALE_SMOOTH));
Icon greyGlobeIcon = new ImageIcon(Toolkit.getDefaultToolkit()
.getImage("NSImage://NSNetwork").getScaledInstance(16, 16,
Image.SCALE_SMOOTH));

// eine Kategorie erzeugen
SourceListCategory categoryOne = new SourceListCategory("Kategorie 1");

// vier Elemente erzeugen
SourceListItem itemA = new SourceListItem("Element A", blueGlobeIcon);
SourceListItem itemB = new SourceListItem("Element B", greyGlobeIcon);

// Zähler setzen
itemA.setCounterValue(1);

// Modell erzeugen
final SourceListModel model = new SourceListModel();

// Kategorien und Elemente hinzufügen
model.addCategory(categoryOne);
model.addItemToCategory(itemA, categoryOne);
model.addItemToCategory(itemB, categoryOne);

// Kontrolleiste erzeugen
SourceListControlBar controlBar = new SourceListControlBar();
controlBar.createAndAddButton(MacIcons.PLUS, null);
controlBar.createAndAddButton(MacIcons.MINUS, null);
controlBar.createAndAddPopdownButton(MacIcons.GEAR,
new PopupMenuCustomizerUsingStrings(null, "Element 1",
"Element 2", "Element 3"));

// Seitenleiste erzeugen
SourceList sourceList = new SourceList(model);
sourceList.installSourceListControlBar(controlBar);

// Inhaltsbereich
JSplitPane splitPane = MacWidgetFactory.createSplitPaneForSourceList(
sourceList, new JLabel("Mac Widgets for Java"));
controlBar.installDraggableWidgetOnSplitPane(splitPane);
return splitPane;
}

private Component createBottomBar() {
TriAreaComponent bottomBar = MacWidgetFactory
.createBottomBar(BottomBarSize.SMALL);
bottomBar.addComponentToCenter(MacWidgetFactory
.createEmphasizedLabel("Hallo iX"));
return bottomBar.getComponent();
}

public static void main(String[] args) {
new MacWidgetsDemoApp1();
}
}
package com.thomaskuenneth.flamingo;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.UIManager;

import org.jvnet.flamingo.common.JCommandButton;
import org.jvnet.flamingo.common.icon.ResizableIcon;
import org.jvnet.flamingo.ribbon.JRibbon;
import org.jvnet.flamingo.ribbon.JRibbonBand;
import org.jvnet.flamingo.ribbon.JRibbonFrame;
import org.jvnet.flamingo.ribbon.RibbonElementPriority;
import org.jvnet.flamingo.ribbon.RibbonTask;

public class FlamingoTestApp1 {

private JRibbonFrame f;

public FlamingoTestApp1() {
f = new JRibbonFrame("Flamingo-Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createAndFillRibbon();
f.getContentPane().add(
new JLabel("Ich bin der eigentliche Inhaltsbereich"),
BorderLayout.CENTER);
f.setBounds(100, 50, 600, 200);
f.setVisible(true);
}

private void createAndFillRibbon() {
JRibbon ribbon = f.getRibbon();

// JRibbonBands sind Bestandteile von RibbonTasks
JRibbonBand ribbonBand1 = new JRibbonBand("Bearbeiten", getIcon());
ribbonBand1.addCommandButton(new JCommandButton("Ausschneiden",
getIcon()), RibbonElementPriority.TOP);

// Swing-Komponenten werden in einem JPanel gekapselt
JPanel panel = new JPanel();
panel.add(new JButton("Schaltfläche"));
panel.add(new JCheckBox("Checkbox"));
ribbonBand1.addPanel(panel);

// ein zweites JRibbonBand
JRibbonBand ribbonBand2 = new JRibbonBand("Ansicht", getIcon());
ribbonBand2.addCommandButton(new JCommandButton("Seitenansicht",
getIcon()), RibbonElementPriority.LOW);

// eine RibbonTask erzeugen
RibbonTask task1 = new RibbonTask("Allgemein", ribbonBand1, ribbonBand2);
ribbon.addTask(task1);

// Elemente zur Taskbar hinzufügen
ribbon.addTaskbarComponent(new JLabel("Speichern"));
ribbon.addTaskbarComponent(new JSeparator(JSeparator.VERTICAL));
ribbon.addTaskbarComponent(new JLabel("Verwerfen"));
}

private ResizableIcon getIcon() {
ResizableIcon icon = new ResizableIcon() {

int width = 32;
int height = 32;

public void revertToOriginalDimension() {
}

@Override
public void setDimension(Dimension newDimension) {
setWidth(newDimension.width);
setHeight(newDimension.height);
}

@Override
public void setHeight(int height) {
this.height = height;
}

@Override
public void setWidth(int width) {
this.width = width;
}

@Override
public int getIconHeight() {
return height;
}

@Override
public int getIconWidth() {
return width;
}

@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(Color.darkGray);
g.fillRect(x, y, getIconWidth(), getIconHeight());
g.setColor(Color.green);
g.drawRect(x, y, getIconWidth(), getIconHeight());
g.drawLine(x, y, x + getIconWidth() - 1, y + getIconHeight() - 1);
g.drawLine(x, y + getIconHeight() - 1, x + getIconWidth() - 1,
y);
}
};
return icon;
}

public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Throwable thr) {
// im Fehlerfall belassen wir das Standard-Look and Feel
}
new FlamingoTestApp1();
}
} (ck)