Круговорот данных |
571 |
лен классом с очевидным названием Clipboard, класс этот находится в пакете java.awt. datatransfer, который, как легко судить по названию, хранит все инструменты для работы с обменом данных.
Напрямую буфер обмена Clipboard обычно не создается (хотя это возможно), да в этом и нет смысла, как правило, нас интересует системный буфер обмена данными. Чтобы получить к нему доступ, используется фабрика классов AWT Toolkit, метод которой getSystemClipboard() возвращает системный буфер. С его помощью можно получать данные из буфера или передавать их туда. Однако данные у каждого приложения свои, и необходимо предоставить способ их распознавания. Для этого служат типы данных для обмена.
Типы данных для обмена
Современные системы позволяют хранить в буфере обмена все что угодно, будь то простой текст или изображения огромных размеров. Прежде чем что-то получить из буфера, особенно если это что-то получено из другого приложения, нам необходимо понять, как именно представлены данные и каким образом их можно обработать. Существует много разных способов описать данные, но есть и стандарт под названием MIME (MultiPurpose Internet Mail Extenstions), возникший после того, как к сообщениям электронной почты стало возможным присоединять данные разных типов. Для того чтобы как-то определить, что за данные присоединены к почте и как с ними обращаться, была введена классификация типов MIME. Грубо говоря, тип описывается как совокупность базового типа (это может быть текст, видео или что-то еще) и его конкретного типа. В итоге описание типа выглядит как строка вида «text/html». Именно такое описание типов используют классы для обмена данными в Java.
Нам не придется углубляться в детали спецификации MIME, потому что основную часть работы выполняет вспомогательный класс DataFlavor из все того же пакета java.awt.datatransfer. Он сопоставляет описание типа MIME и Java-класс, который может представить этот тип. Данный класс позволяет создавать и свои уникальные типы данных, которые вы можете описать в формате MIME, но, как правило, хватает и стандартных типов. Они описаны как поля-константы класса DataFlavor и представляют собой конкретные объекты этого класса:
Таблица 18.1. Основные типы данных для обмена
Стандартный тип |
Предназначение |
|
|
DataFlavor.stringFlavor |
Основа из основ, тип данных для строки языка Java String, кото- |
|
рая, как известно, представляет собой набор символов Unicode. |
|
Как правило, большая часть данных при обмене может быть |
|
представлена в виде строки |
DataFlavor. javaJVMLocal- |
Тип данных для любого объекта в вашем Java-приложении, но |
ObjectMimeType |
именно в вашем приложении, между разными виртуальными |
|
машинами объекты этого типа не передать. Этот тип данных |
|
хорош для обмена данными между компонентами внутри Java- |
|
приложения, однако данные такого типа не сможет понять ни |
|
одно системное или любое другое приложение, так что в допол- |
|
нение к ним можно представить, к примеру, строковое представ- |
|
ление объекта |
DataFlavor.imageFlavor |
Описывает всевозможные изображения, данные при этом пред- |
|
ставлены как класс изображений AWT Image. |
572 |
ГЛАВА 18 |
|
Таблица 18.1 (продолжение) |
||
|
|
|
Стандартный тип |
Предназначение |
|
|
|
|
DataFlavor.javaFileListFlavor |
Представляет собой список файлов, выбранных в файловой си- |
|
|
стеме. Такие данные, к примеру, могут быть переданы в буфер об- |
|
мена различными файловыми приложениями, когда пользователь
копирует файл в буфер или «вырезает» его из текущей директо-
рии. Данные представлены как список List, в котором находятся
объекты, представляющие файлы (или директории) File.
В абсолютном большинстве случаев вполне достаточно стандартных типов данных, более того, из других приложений вы можете получить только описанные данные описанных выше типов. В своем же приложении вы вольны заполнять буфер локальными объектами Java и работать с ними как обычно, мы уже видели, что для этого есть свой тип данных. Никто не запрещает данным иметь и два, и даже больше типов. Пример этого мы вскоре рассмотрим.
Теперьмы,наконец,можемначатьработусбуферомобмена.Длятогочтобывыяснить, что же хранится в буфере, класс Clipboard предоставляет метод getAvailableDataFlavors(), который возвращает массив всех типов для данных, находящихся в буфере в текущий момент. Обнаружив в типах то, что мы умеем обрабатывать или показывать, мы можем получить данные. Посмотрим, как это происходит:
//ClipboardContents.java
//Доступ к содержимому буфера обмена import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.datatransfer.Clipboard;
import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.io.IOException;
import javax.swing.*;
public class ClipboardContents extends JFrame { public ClipboardContents() {
super("ClipboardContents");
//выход при закрытии окна setDefaultCloseOperation(EXIT_ON_CLOSE);
//добавим кнопку получения содержимого
JButton getButton = new JButton("Получить");
//текстовое поле для вывода данных
final JTextArea textArea = new JTextArea(); getButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { try {
// буфер обмена
Круговорот данных |
573 |
Clipboard clipboard = Toolkit.getDefaultToolkit(). getSystemClipboard();
// выведем все типы данных for (DataFlavor next:
clipboard.getAvailableDataFlavors()) { textArea.append(next.toString() + "\n"); // попытка получить сами данные textArea.append(clipboard.
getData(next).toString() + "\n");
}
}catch (UnsupportedFlavorException ex) { ex.printStackTrace();
}catch (IOException ex) { ex.printStackTrace();
}
}
});
add(new JScrollPane(textArea)); add(getButton, "South");
// выведем окно на экран setSize(400, 300); setVisible(true);
}
public static void main(String[] args) { SwingUtilities.invokeLater(
new Runnable() {
public void run() { new ClipboardContents(); } });
}
}
Как и всегда, пример максимально прост, так что мы сможем сконцентрироваться на том, что происходит с данными внутри буфера обмена. Мы создаем окно, в центре которого располагается текстовая область в панели прокрутки, так что она сможет показать нам текст любого размера. Внизу окна мы добавили кнопку, при нажатии которой происходит анализ содержимого системного буфера обмена.
При нажатии кнопки мы получаем ссылку на системный буфер обмена, а также все доступные на текущий момент типы данных, которые находятся в буфере. Чтобы получить их, вызываем уже известный нам метод getAvailableDataFlavors(). Для каждого поддерживаемого данными типа мы выводим строковое представление типа на экран, а также с помощью метода getData() пытаемся получить объект, которые представляет эти данные в Java-приложении.Мы не рассчитываем на конкретный тип данных, поэтому не можем преобразовать полученный объект во что-то более ценное, и просто выводим в текстовую область его строковое представление. Обратите внимание, что нам приходится учитывать исключения, которые могут возникнуть при невозможности получить данные запрошенного типа (в нашем примере это невозможно, так как мы
574 |
ГЛАВА 18 |
получаем данные типа, который точно поддерживается ими) или ошибке при считывании этих данных (IOException). Запустив приложение, скопируйте что-нибудь в буфер обмена системы, например файлы или просто текст, и нажмите кнопку, чтобы изучить содержимое и типы объектов, которыми оно представлено.
На указанном снимке экрана приложения видно, как сначала в буфер попал список файлов, описанный как прекрасно всем нам знакомый список элементов List. Cписок выводится на экран в виде распечатки всех своих элементов, объектов File с их полными путями в файловой системе.
Далее ситуация становится еще более интересной. В буфер был скопирован текст из внешнего редактора («привет из блокнота!»), казалось бы, он будет представлен только как объект String, но не тут-то было. Если для нас в Java-приложении действительно хватает строки String, то для системных приложений этого мало, и более того, они могут воспринимать строки по-разному. Здесь система обмена данными выполняет за нас всю нудную работу — она представляет строку в виде множества комбинаций, в различных кодировках, в виде набора байтов, в виде потока данных, и много другого, вы все сможете увидеть, запустив приложение. Ну а в Java-приложении остается лишь получить строку String, в универсальном формате Unicode, и оценить свои преимущества — в таких ситуациях универсальность Java окупает себя как никогда.
Итак, задача получения данных, хоть и влечет за собой анализ типа этих данных и преобразование к соответствующему объекту, который представляет данные, все же несложна, и встроить в приложение получение из системного буфера строк, изображений или файлов можно всего несколькими строками кода. Однако это лишь одна сторона медали, приложение должно также позволять пользователям копировать свои данные и переносить их в другие приложения. Сделать это просто, требуется один лишь метод setContents() класса Clipboard, но вот сами данные при этом придется подготовить для выхода «на люди». Посмотрим, как это делается.
Адаптация данных
Платформа Java создана работать одинаково на всех операционных системах и аппаратных комбинациях, однако при обмене данными с приложениями «родной» системы встает вопрос понимания друг друга. В предыдущем разделе мы узнали, как нам понять, что же лежит в системном буфере обмена и как эти данные перевести в понятные нам объекты Java. С другой стороны, очевидно, что наше Java-приложение имеет свои форматы данных, даже простых строк, и их необходимо представить так, чтобы