Bei der Entwicklung von Swing wurde darauf geachtet, dass einerseits ein gemeinsamer Einsatz von AWT- und Swing-Komponenten möglich ist, dass aber anderseits auch die Portierung bestehender Anwendungen von AWT nach Swing möglichst einfach erfolgen kann. Dies wird folgendermaßen erreicht: Die Basisklasse für Swing-Komponenten, die Klasse javax.swing.JComponent, ist abgeleitet von der Klasse java.awt.Container, die wiederum von der Klasse java.awt.Component abgeleitet ist (siehe Abb. 8-10). Da auch AWT-Komponenten wie Checkbox, List, Scrollbar oder Button von dieser Klasse abgeleitet sind, kann eine Benutzeroberfläche sowohl Swing als auch AWT-Elemente enthalten. Alle Swing-Komponenten haben analoge Konstruktoren und Methoden, die dem Programmierer deren Verwendung erlauben, ohne sich explizit mit dem MVC-Konzept (siehe Kapitel 2) beschäftigen zu müssen. Um die Kompatibilität von AWT und Swing zu verdeutlichen, wird im folgenden Beispiel ein Button implementiert, der die Funktion hat, das Datenmodell auf den ursprünglichen Wert zurückzusetzen. JButton resetButton = new JButton("Rücksetzen"); Das derart realisierte JButton-Objekt kann auch durch die nachfolgende Zeile implementiert werden. Button resetButton = new Button("Rücksetzen"); Anstelle der Swing-Komponente JButton wird somit das entsprechende Gegenstück des AWTs benutzt, parallel zur Verwendung der anderen Swing-Komponenten. Die entgegengesetzte Richtung, die Benutzung einzelner Swing-Komponenten in einer AWT-basierten Benutzeroberfläche, ist ebenso einfach. Bei der Umstellung einer bestehenden Applikation von einer AWT-basierten Oberfläche auf Swing kann das Problem auftreten, dass die Model-View-Controller-Architektur nicht ohne größere Strukturänderungen der Applikation implementiert werden kann. So wird bspw. in der MVC-Architektur der Wert eines bestimmten Listeneintrags nicht bei der GUI-Komponente erfragt, die die Liste darstellt, sondern bei der für die Speicherung der Daten zuständigen Instanz der Datenmodellklasse. Bei komplexeren Strukturen innerhalb der Anwendung kann eine komplette Umstellung auf MVC also einen größeren Aufwand bedeuten. Um die Umstellung von AWT auf Swing in derartigen problembehafteten Fällen zu erleichtern, gibt es eine Reihe von zusätzlichen Methoden, die man in zwei Gruppen einteilen kann. Die erste Gruppe besteht aus Konstruktoren, die neben dem eigentlichen GUI-Element auch völlig transparent für den Programmierer eine Instanz der Standardmodellklasse erzeugt, die dann automatisch dazu verwendet wird, um die zur Komponente gehörenden Daten zu speichern. Die zweite Gruppe besteht aus Methoden, mit denen über die GUI-Komponente direkt auf die Daten des Datenmodells zugegriffen werden kann, die zu der Komponente gehören. Diese Methoden sind ebenso wie die zusätzlichen Konstruktoren überflüssig, wenn konsequent mit dem MVC-Konzept gearbeitet wird. Einige dieser Methoden sollten unter Umständen sogar gemieden werden, um die Trennung von Daten und Benutzeroberfläche nicht aufzuweichen. Soll eine bereits bestehende Anwendung an Swing angepasst werden, so sind die Methoden allerdings sehr hilfreich, da sie es erlauben, die meisten Swing-Komponenten fast ebenso zu benutzen wie die entsprechenden AWT-Elemente. Auch wenn Swing intern immer mit MVC arbeitet, muss der Programmierer diese Architektur nicht im Detail kennen. Neben der Portierung bereits bestehender Software von AWT nach Swing können diese redundanten Methoden auch dann benutzt werden, wenn sich der Aufwand, eine MVC-Architektur zu verwenden, nicht lohnt. Beispielsweise wenn nur eine sehr einfache Oberfläche benötigt wird, bei der niemals mehrere Ansichten gleicher Daten benötigt werden, oder wenn aus anderen Gründen eine MVC-Architektur nicht praktikabel ist. Eine Erweiterung des Beispiels ist nachfolgend aufgelistet: //* Beispiel Swing3.java fuer das Buch OpenJava //Java Application, in der drei Views //fuer ein Datenmodell erstellt werden. //Starten mit java Swing3 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; class IntegerToTextAdapter implements ChangeListener { //... //siehe Swing2.java //... } public class Swing3 extends JFrame { BoundedRangeModel myModel = new DefaultBoundedRangeModel(30,1,0,100); //Es wird kein JButton-Objekt verwendet, um die //Kompatibilitaet zwischen Swing und AWT-Komponenten zu //verdeutlichen Button resetButton = new Button("Rücksetzen"); public Swing3() { super("Swing 3"); //... //siehe Swing2.java //... myJPanel.add(resetButton); setContentPane(myJPanel); // Registriere den Listener fuer den resetButton ButtonAction theAction = new ButtonAction(); resetButton.addActionListener(theAction); } // Main Funktion ohne Argumente public static void main(String[] args) { //... //siehe Swing2.java //... } // Innere Klasse als ActionEvent Adapter class ButtonAction implements java.awt.event.ActionListener { public void actionPerformed(java.awt.event.ActionEvent event){ Object theObject = event.getSource(); if (theObject == resetButton) reset_Action(event); } } // Setzt den Wert auf 30 Zurück public void reset_Action(java.awt.event.ActionEvent event) { myModel.setValue(30); } } Einschränkungen Es gibt grundsätzliche Unterschiede zwischen Lightweight- und Heavyweight-Komponenten. Alle AWT-Komponenten sind heavyweight, alle Swing-Komponenten sind dahingegen lightweight, ausgenommen die Top-Level-Komponenten JWindow, JFrame, JDialog und JApplet. Dieser Unterschied macht sich bei Anwendungen bemerkbar, die zwei Komponentenarten mischen. Folgende Unterschiede existieren zwischen Lightweight- und Heavyweight-Komponenten: Eine Lightweight-Komponente kann einen transparenten Hintergrund haben, eine Heavyweight-Komponente ist hingegen immer undurchsichtig. Eine Lightweight-Komponente muss aufgrund der Transparenzeigenschaft nicht unbedingt durch ein Rechteck dargestellt werden. Eine Heavyweight-Komponente wird immer durch ein Rechteck dargestellt. Bei der Überlappung einer Lightweight- und einer Heavyweight-Komponente erscheint die Heavyweight-Komponente immer auf der obersten Schicht im Vordergrund. Aus diesen Unterschieden ergeben sich die folgenden Anwendungsregeln: Lightweight-Komponenten (Swing) und Heavyweight-Komponenten (AWT) dürfen nicht gemischt werden, wenn eine Überlappung der Komponenten nicht auszuschließen ist. Überlappt z. B. ein JPopupMenu-Objekt mit einem java.awt.Button (heavyweight), dann muss die Methode JPopupMenu.setDefaultLightWeightPopupEnabled(false) aufgerufen werden, bevor die JPopupMenu-Komponente instantiiert wird. Eine Heavyweight-Komponente (AWT) darf nicht innerhalb einer JScrollPane-Komponente platziert werden. Wird ein verschiebbarer Bereich gewünscht, so muss die AWT-Komponente ScrollPane benutzt werden. Eine Heavyweight-Komponente (AWT) darf nicht innerhalb eines JInternal-Frame-Objekts platziert werden. Das folgende Beispiel veranschaulicht die Umsetzung dieser Regeln. import java.awt.*; import javax.swing.*; public class MixPopupTest extends JFrame { public MixPopupTest() { super("Mixing Popup Test"); JMenuBar menubar = new JMenuBar(); setJMenuBar(menubar); //Nun wird eine Lightweight-Komponente, JMenu, erstellt JMenu menu = new JMenu("Lightweight Menu"); menu.add("Neu"); menu.add("Oeffnen"); menu.add("quit"); menubar.add(menu); JPopupMenu.setDefaultLightWeightPopupEnabled(fal se); menu = new JMenu("Heavyweight Menu"); menu.add("Neu"); menu.add("Oeffnen"); menu.add("quit"); menubar.add(menu); //Erzeugen einer Heavyweight-Komponente Button heavy = new Button(" Heavyweight Button "); Box box = Box.createVerticalBox(); box.add(Box.createVerticalStrut(20)); box.add(heavy); box.add(Box.createVerticalStrut(20)); getContentPane().add("Center", box); pack(); } public static void main(String[] args) { MixPopupTest mpt = new MixPopupTest(); mpt.show(); } } Im Beispiel wird eine Lightweight-Komponente JMenu erstellt, deren Lightweight-Eigenschaft allerdings ausgeschaltet (disabled) wird. Somit hat diese Komponente die gleichen Eigenschaften wie eine Heavyweight-AWT-Komponente. Das Ergebnis dieses Beispiel ist in den nachfolgenden Abbildungen dargestellt. Abb. 8-29 zeigt, wie eine Heavyweight-Komponente (java.awt.Button) eine Lightweight-Komponente (javax.swing.JMenu) überlappt, und wie dadurch die Auswahl einiger Menüpunkte unmöglich wird. Abb. 8.29: Der Heavyweight-Button überlappt das Lightweight-Menü Abb. 8-30 stellt dar, wie eine Heavyweight-Komponente (javax.swing.JMenu) mit Heavyweight-Eigenschaften versehen werden kann. Hierdurch überlappt sie nicht mit der Heavyweight-Komponente (java.awt.Button) und die Auswahl aller Menüpunkte wird möglich. Abb. 4.30: Keine Überlappung des Heavyweight-Buttons durch das Heavyweight-Menü