Материал: Портянкин И. Swing

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Глава 18. Круговорот данных

Эта глава будет посвящена самому драгоценному сокровищу пользователей, которое они с трепетом доверяют нашему приложению, — данным, результатам их, без сомнения, трудной и кропотливой работы. Способность приложения не только помогать в обработке данных, но и обеспечивать их обмен с другими приложениями и системой, а также отказ от случайных изменений многократно повышает удобство программы и привязанность к ней пользователей. Все эти возможности библиотека Swing любезно предоставляет сама или с помощью AWT, а нам остается только правильно их использовать.

Обмен данными

Самое неприятное, что вы можете сделать в своем приложении, это заставить пользователя выполнять одну и ту же работу снова и снова, не предоставляя в этом никакой помощи. Что может быть тоскливее и неприятнее, чем набирать вновь один и тот же текст и нажимать те же кнопки. Поэтому обмен данными настолько популярен, особенно в форме копирования и вставки, — пользователь получает возможность быстро переместить данные туда, где они ему требуются, и вам для этого не нужно продумывать каждый его шаг и вставлять повсюду собственные кнопки и меню для копирования и импорта похожих данных. Достаточно предоставить универсальный механизм перемещения данных в приложении.

Благодаря моделям, данные в Swing отделены от визуального представления, и их копирование и особенно совместное использование очень просты. Однако было бы слишком наивно полагать, что пользователи применяют только ваше приложение, и им не захочется скопировать текст из внешней электронной почты в Java-приложение. Необходимо обеспечить взаимодействие со всеми возможностями базовой операционной системы.

На данный момент все операционные системы позволяют своим пользователям перемещать данные между своими приложениями. В основном применяются универсальные операции копирования данных (copy), вставки их в приложение (paste), или «вырезание» (cut) данных, попросту говоря, перемещение. По первым буквам этих трех слов операции эти еще называют CCP. Данные, полученные в результате таких операций, хранятся в буфере обмена (clipboard), где они доступны любым приложениям.

Существует и более приятный глазу и интуитивно понятный процесс перетаскивания (drag), когда объект, видимый на экране, перетаскивается в другое место экрана и волшебным образом оказывается в новом месте , когда объект этот там бросают (drop). Эти операции еще называют DnD (drag and drop). Суть операций CCP и DnD одинакова, различается лишь метод. Когда пользователь перетаскивает данные, они не попадают в буфер обмена и доступны только непосредственно в момент перетаскивания.

Все операции обмена данными: и CCP, и DnD, доступны нашим Java-приложениям. Начнем с того, что посмотрим, как получить доступ к системному буферу обмена.

Буфер обмена Clipboard

Итак, как мы уже упомянули, операции по обмену данных используют общее системное хранилище, так называемый буфер обмена, который позволяет приложениям обмениваться данными друг с другом. Для Java-приложений буфер обмена представ-

Круговорот данных

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-приложение имеет свои форматы данных, даже простых строк, и их необходимо представить так, чтобы

Источник: https://studfile.net/preview/15935977/