Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 30 - Menüs

## 30.7 Datenaustausch mit der Zwischenablage

- 30.7 Datenaustausch mit der Zwischenablage
  - 30.7.1 Überblick
  - 30.7.2 Kommunikation mit der Zwischenablage

### 30.7.1 Überblick

Die Zwischenablage ist in grafischen Oberflächen eines der wichtigsten Hilfsmittel, um Daten zwischen Dialogelementen oder über Anwendungsgrenzen hinweg auszutauschen. Seit dem JDK 1.1 gibt es ein allgemeines API für den Datenaustausch, das Funktionen für den Datenaustausch mit der Zwischenablage zur Verfügung stellt. Wir wollen es hier kurz beschreiben, weil es als typisches Element eines Kontextmenüs gut in den Rahmen dieses Kapitels paßt.

Die zugehörigen Klassen und Interfaces befinden sich im Paket `java.awt.datatransfer`. Die für die Kommunikation mit der Zwischenablage interessanten Bestandteile dieses APIs sind:

- Das Interface `Transferable`, das die Schnittstelle von Objekten festlegt, die mit der Zwischenablage ausgetauscht werden können.
- Die Definition der Datentypen, die ausgetauscht werden können. Diese werden in Java als DataFlavors bezeichnet und basieren auf der MIME-Spezifikation (Multi-purpose Internet Mail Extensions), die in RFC 1521 und 1522 beschrieben wird (allgemeine Hinweise zu den RFCs finden sich in Abschnitt 45.1.5).
- Die Klasse `Clipboard`, mit der die Zwischenablage implementiert wird. Neben der systemweiten Zwischenablage können auch benutzerdefinierte Zwischenablagen verwendet werden.

### 30.7.2 Kommunikation mit der Zwischenablage

Wir wollen uns nun ansehen, welche Schritte erforderlich sind, um einen `String` in die Zwischenablage zu kopieren. Zunächst muß ein Objekt erzeugt werden, das das Interface `Transferable` implementiert. `Transferable` spezifiziert die Schnittstelle für den Transportmechanismus von Daten, die über die Zwischenablage ausgetauscht werden können. Es verwaltet eine Liste der in Frage kommenden Datentypen, die es mit `getTransferDataFlavors` auf Anfrage zur Verfügung stellt. Mit `isDataFlavorSupported` kann festgestellt werden, ob ein bestimmter Datentyp unterstützt wird, und `getTransferData` liefert die zu übertragenden Daten:

    public DataFlavor[] getTransferDataFlavors()

    public boolean isDataFlavorSupported(DataFlavor flavor)

    public Object getTransferData(DataFlavor flavor)
      throws UnsupportedFlavorException, IOException
| java.awt.datatransfer.Transferable

|  | Die Initialisierung eines `Transferable`-Objekts ist nicht Bestandteil der Schnittstelle, sondern muß von den implementierenden Klassen in Eigenregie - beispielsweise bei der Instanzierung - vorgenommen werden. |  |
Hinweis

Im AWT gibt es eine vordefinierte Klasse `StringSelection`, die das Interface `Transferable` implementiert. Sie ist in der Lage, Strings auszutauschen, und unterstützt die aus `DataFlavor` abgeleiteten Datentypen `plainTextFlavor` und `stringFlavor`. Beide liefern die Daten als Unicode-kodierte Zeichenkette. Während `plainTextFlavor` sein Ergebnis als `InputStream` zur Verfügung stellt und den MIME-Typ `text/plain` repräsentiert, liefert `stringFlavor` einen String und repräsentiert den MIME-Typ `application/x-java-serialized-object`.

Ein `StringSelection`-Objekt wird initialisiert, indem die zu übertragende Zeichenkette an den Konstruktor übergeben wird. Anschließend kann es an die Zwischenablage übergeben werden, die die Daten durch Aufruf von `getTransferData` übernimmt. Jeder Aufruf von `getTransferData` muß in eine `try`-`catch`-Anweisung eingebunden werden und folgende Fehler abfangen:

- Das `Transferable`-Objekt ist nicht in der Lage, die Daten in dem gewünschten Format zu liefern.
- Da der Rückgabewert vom Typ `Object` ist, muß er in der Regel in den tatsächlich erforderlichen Typ konvertiert werden. Hierbei kann eine Ausnahme des Typs `ClassCastException` auftreten.

Bevor die Zwischenablage die Daten aus dem `Transferable`-Objekt entnehmen kann, muß dieses natürlich erst einmal an die Zwischenablage übergeben werden. Eine Zwischenablage ist immer eine Instanz der Klasse `Clipboard` oder einer ihrer Unterklassen. Zwar ist es möglich, anwendungsspezifische Zwischenablagen anzulegen, wir wollen uns aber nur mit der systemweit gültigen Zwischenablage des Betriebssystems beschäftigen.

Im `Toolkit` gibt es eine Methode `getSystemClipboard`, mit der ein Objekt für die systemweite Zwischenablage beschafft werden kann:

    public Clipboard getSystemClipboard()
| java.awt.Toolkit

Sie stellt im wesentlichen einen Konstruktor und drei Methoden zur Verfügung:

    public String getName()

    public Transferable getContents(Object requestor)

    public void setContents(
       Transferable contents, ClipboardOwner owner
    )
| java.awt.datatransfer.Clipboard

Mit `getName` kann der Name der Zwischenablage ermittelt werden, `getContents` liefert den Inhalt der Zwischenablage, und mit `setContents` kann der Zwischenablage ein neues Objekt zugewiesen werden. Ein Aufruf von `getContents` liefert null, wenn die Zwischenablage leer ist. Der Rückgabewert ist ein `Transferable`-Objekt, dessen Daten mit `getTransferData` abgefragt werden können. Beim Aufruf von `getContents` muß zusätzlich ein Objekt `requestor` übergeben werden, das derzeit keine Funktion hat.

Ein Objekt, das den Inhalt der Zwischenablage ändern will, tut dies über den Aufruf der Methode `setContents`. Als erstes Argument ist ein `Transferable`-Objekt zu übergeben, das die Daten enthält. Als zweites muß ein Objekt übergeben werden, das das Interface `ClipboardOwner` implementiert. Da die Zwischenablage von verschiedenen Objekten verwendet wird, ist es unter Umständen wichtig zu wissen, wann die übergebenen Daten verworfen und durch ein neues Objekt ersetzt werden. Dazu definiert `ClipboardOwner` die Methode `lostOwnership`, die aufgerufen wird, wenn der Inhalt der Zwischenablage verändert wird:

    public void lostOwnership(
       Clipboard clipboard, Transferable contents
    )
| java.awt.datatransfer.ClipboardOwner

Nach diesen Vorüberlegungen wollen wir uns ein Beispiel ansehen. Dazu soll die Methode `actionPerformed` des vorigen Beispiels erweitert werden, um die beiden Menüeinträge »Kopieren« und »Einfuegen« mit Funktionalität zum Datenaustausch auszustatten. Zusätzlich implementiert das Beispielprogramm das Interface `ClipboardOwner` und definiert dazu die Methode `lostOwnership`:

    001 /* clpbrd.inc */
    002
    003 public void actionPerformed(ActionEvent event)
    004 {
    005   Clipboard clip = getToolkit().getSystemClipboard();
    006   String cmd = event.getActionCommand();
    007   if (cmd.equals("Kopieren")) {
    008     String s = "Es ist " + System.currentTimeMillis() + "Uhr";
    009     StringSelection cont = new StringSelection(s);
    010     clip.setContents(cont, this);
    011   } else if (cmd.equals("Einfuegen")) {
    012     Transferable cont = clip.getContents(this);
    013     if (cont == null) {
    014       System.out.println("Zwischenablage ist leer");
    015     } else {
    016       try {
    017         String s = (String) cont.getTransferData(
    018           DataFlavor.stringFlavor
    019         );
    020         System.out.println(s);
    021       } catch (Exception e) {
    022         System.out.println(
    023           "Zwischenablage enthält keinen Text"
    024         );
    025       }
    026     }
    027   }
    028 }
    029
    030 public void lostOwnership(Clipboard clip, Transferable cont)
    031 {
    032   System.out.println("Inhalt der Zwischenablage ersetzt");
    033 }
| clpbrd.inc

Listing 30.7: Kommunikation mit der Zwischenablage

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de