8.7.5 | Copy-and-Paste |
Textkomponenten in Swing unterstützen von sich aus Copy-and-Paste von Texten, auch über die Grenzen der Virtual Machine hinweg.
Möchte man hingegen andere Objekte zwischen verschiedenen Komponenten hin und kopieren, kann man dies über das Package java.awt.datatransfer bewerkstelligen.
Zu diesem Zweck benutzt man ein Exemplar der Klasse java.awt.datatransfer.Clipboard. Möchte man den Datenaustausch nur innerhalb der Virtual Machine vornehmen, kann man einfach den Konstruktor des Clipboards aufrufen. Möchte man hingegen auch mit Anwendungen außerhalb der Virtual Machine kommunizieren bzw. sich diese Option offen lassen, so erhält man Zugriff auf das globale Clipboard mittels java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().
Neben den reinen Daten werden Metadaten benötigt, die die Art der Daten beschreiben. Neben der Java-Klasse, die den Inhalt bildet, ist das der Mime-Type. Diese Metainformation ist bekannt von Webservern: HTML-Seiten werden mit dem Content-Type text/html geliefert. Diese Informationen werden in der Klasse java.awt.datatransfer.DataFlavor zusammengefasst. Diese verfügt über schon vordefinierte Exemplare, die die meisten Anwendungsgebiete abdecken. Während einige nur JVM-interne Objekte liefern, ist das Exemplar javaFileListFlavor von besonderem Interesse. Sie liefert eine java.util.List mit java.io.File-Exemplaren, die man über die Grenzen der Virtual Machine hinweg austauschen kann. Kopiert man im Windows Explorer Dateien, kann man über dieses DataFlavor darauf zugreifen.
Das auszutauschende Datenelement kann dabei in unterschiedlichen Formaten übertragen werden. Wenn man beispielsweise einen HTML-Text übertragen will, empfiehlt es sich, ihn für Browser als text/html und für einfache Texteditoren (wie z.B. das Notepad) als text/plain anzubieten. Dadurch kann ein Transferable mehrere DataFlavors ausweisen.
Wenn man Daten über die JVM hinweg austauschen möchte, so muss dafür ein passender Mime-Type angegeben werden und ein java.io.InputStream für die Daten bereitgestellt werden.
Drückt der Benutzer bei Windows bspw. Strg-C, so setzt man das entsprechende Objekt mittels der Methode setContents(Transferable contents, ClipboardOwner owner). Während das als zweiter Parameter angegebene Objekt lediglich darüber informiert wird, dass jemand anderes den Inhalt des Clipboards überschrieben hat, befindet sich im ersten Parameter das zu transferierende Objekt, verpackt in der Klasse java.awt.datatransfer.Transferable. Dieses Interface beinhaltet drei Methoden:
- public Object getTransferData(DataFlavor flavor)
Liefert das übertragende Objekt, welche zu dem angegeben Format assoziert wurde.- public DataFlavor[] getTransferDataFlavors()
Liefert alle Formate, die zur Verfügung stehen- public boolean isDataFlavorSupported(DataFlavor flavor)
Liefert die Aussage, ob dem angegebenen Format Daten zugeordnet sind, also ob es unterstützt wird.
Als Beispiel soll in einem JLabel eine Grafik über das System-Clipboard angezeigt werden. Dabei reagiert das JLabel auf direkte Bildinformationen (wenn man also in einem Bildbearbeitungsprogramm einen Teil eines Bildes in die Zwischenablage kopiert) als auch auf eine passende Grafikdatei (wenn man im Explorer z.B. ein GIF auswählt).
final JLabel label = new JLabel (); ActionListener pasteActionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { try { // Die Daten aus dem SystemClipboard holen Transferable data = Toolkit.getDefaultToolkit(). getSystemClipboard().getContents(null); // Die unterschiedlichen Repräsentationen holen DataFlavor[] df = data.getTransferDataFlavors(); for (int i = 0; i < df.length; i++) { // Direkte Grafikinformationen if (df[i].isMimeTypeEqual(DataFlavor.imageFlavor)) label.setIcon(new ImageIcon( (Image) data.getTransferData(df[i]))); // Übergabe durch eine Datei else if (df[i].isFlavorJavaFileListType()) { List fileList = (List) data.getTransferData(df[i]); // Wir unterstützen hier // erstmal nur die erste Datei File firstFile = (File) fileList.get(0); label.setIcon(new ImageIcon( firstFile.getAbsolutePath())); } } } catch (Throwable ta) { ta.printStackTrace (); } } }; // Mit Strg-V bei dem Label mit Fokus mit dem // PasteActionListener reagieren label.registerKeyboardAction(pasteActionListener, "Paste", KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK, false), JComponent.WHEN_FOCUSED);