Графические интерфейсы пользователя Java

Тимур Машнин

Эта книга для тех, кто уже знаком с языком программирования Java и хотел бы научиться разрабатывать настольные приложения Java с графическим интерфейсом пользователя.С этой книгой Вы познакомитесь с такими Java библиотеками графического интерфейса пользователя, как AWT, Swing, SWT/JFace и JavaFX.

Оглавление

Java 2D

Как уже было сказано, библиотека AWT была дополнена библиотекой Java 2D API, расширяющей возможности работы с двухмерной графикой и изображениями.

Java 2D API предоставляет единую модель рендеринга для разных типов устройств.

На уровне приложения процесс рендеринга одинаковый, является ли целевое устройство рендеринга экраном или принтером.

Когда компонент должен отображаться, автоматически вызывается его метод paint или update с соответствующим графическим контекстом Graphics.

Java 2D API предоставляет класс Graphics2D, который расширяет класс Graphics, чтобы обеспечить доступ к расширенной графике и функциям рендеринга Java 2D API.

Чтобы использовать функции Java 2D API в приложении, нужно привести объект Graphics, переданный в метод рендеринга компонента, к объекту Graphics2D.

И объект Graphics2D предоставит следующие функции:

Это отображение набора примитивов, реализующих интерфейс Shape.

При этом примитив может быть заполнен цветом и его контуры могут быть нарисованы с указанием определенной толщины и шаблоном штрихов.

Graphics2D позволяет создать композицию примитивов, переместить, масштабировать, повернуть и обрезать форму.

Также Graphics2D позволяет конвертировать текстовую строку в глифы, которые затем могут быть заполнены цветом.

Примитивы — это точки, линии, прямоугольники, эллипсы, дуги, кривые.

Также можно нарисовать произвольную форму с помощью пути рисования GeneralPath.

Контур примитива можно определить с помощью объекта Stroke.

А заполнить примитив цветом можно с помощью объекта Paint.

Java 2D API предоставляет различные возможности для отображения текста, включая установку атрибутов шрифта и выполнения компоновки текста.

Если вы просто хотите нарисовать статическую текстовую строку, проще всего это сделать с помощью метода drawString класса Graphics, указав шрифт методом setFont класса Graphics.

Если вы хотите контролировать качество отображения текста и его компоновку, вы можете использовать Java 2D API.

Java 2D API позволяет контролировать качество отображения с помощью подсказок класса RenderingHints, например, указав сглаживание текста.

Класс TextLayout предоставляет различные возможности для стилизации текста.

Перед тем, как текст может быть отображен, он должен быть правильно сформирован и расположен с использованием соответствующих символов и лигатур.

Этот процесс называется компоновкой текста.

Процесс компоновки текста включает в себя формирование текста с использованием соответствующих глифов и лигатур, упорядочивание текста, измерение и позиционирование текста.

Что касается изображений, Java 2D API позволяет загрузить внешний файл изображения формата GIF, PNG, JPEG во внутреннее представление изображения, используемое Java 2D.

Непосредственно создать 2D Java изображение и отобразить его.

Отрисовать содержимого 2D-изображения Java на поверхности.

Сохранить содержимое 2D Java изображения во внешний файл изображения GIF, PNG или JPEG.

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

И класс BufferedImage, который расширяет класс Image, чтобы приложение могло работать непосредственно с данными изображения, например, извлечение или настройка цвета пикселя.

И приложения могут напрямую создавать экземпляры этого класса.

Класс BufferedImage управляет изображением в памяти и предоставляет методы для хранения, интерпретации и получения данных пикселей.

Так как BufferedImage является подклассом Image, его контент может быть визуализирован с помощью методов Graphics и Graphics2D, которые принимают параметр Image.

Для загрузки изображения из внешнего источника используется Image I/O API, которое поддерживает форматы изображения GIF, PNG, JPEG, BMP.

Соответственно Image I/O API используется и для сохранения объекта BufferedImage во внешний формат изображения.

Для получения изображения из внешнего источника также можно использовать класс Toolkit, как мы видели уже раньше.

Для отрисовки полученного изображения нужен объект Graphics или Graphics2D.

Если мы не используем метод paint или update компонента, получить объект Graphics2D можно вызвав метод createGraphics, но только изображения, которое вы создали сами.

Поэтому, получив изображение из внешнего источника, мы создаем пустое изображение того же размера, получаем из него объект Graphics2D, и используем его для отрисовки нашего изображения.

Используя возможность получения графического контекста из изображения, можно, например, создать свое изображение, рисуя в нем с помощью объекта Graphics или Graphics2D.

Работа с изображениями

AWT предоставляет некоторые возможности для управления изображениями с помощью пакета java.awt.image.

Как мы уже говорили, получить изображение из внешнего источника можно с помощью объекта Toolkit.

Затем с помощью BufferedImage мы можем получить объект графического контекста и нарисовать изображение.

Далее вы можете масштабировать это изображение.

Если вы хотите что-то нарисовать на своем изображении, вы можете получить графический объект и делать все что захотите.

Java была разработана для загрузки изображения во время работы программы.

Таким образом, вы можете вызвать методы getWidth и getHeight до того, как Java узнает размер изображения.

В этом случае размер изображения будет установлен в — 1.

Это основная проблема, когда вам нужно знать размер изображения.

Решение этой проблемы заключается в том, чтобы ваша программа дождалась загрузки изображения.

Сделать это можно с помощью класса MediaTracker, предназначенного для отслеживания состояния изображений.

Мы добавляем изображение для отслеживания и вызываем метод waitForID, который начинает загрузку изображения, отслеживаемого этим медиа-трекером, с указанным идентификатором.

Этот метод ожидает завершения загрузки изображения с указанным идентификатором.

Отслеживать загрузку изображения также можно с помощью интерфейса ImageObserver, который реализуется классом Component.

ImageObserver — это интерфейс, используемый для приема уведомлений о том, как генерируется изображение.

ImageObserver определяет только один метод: ImageUpdate ().

Использование наблюдателя изображения позволяет выполнять (параллельно с загрузкой изображения) другие действия, такие как показ индикатора хода работы или дополнительного экрана, который информирует о ходе загрузки изображения.

Многие из разработчиков Java находили интерфейс ImageObserver слишком сложным для понимания и управления загрузкой множественных изображений.

Поэтому был создан класс MediaTracker, который позволяет параллельно проверять состояние произвольного числа изображений.

Для многих реальных задач обработки изображений необходимо получить массив с пикселями изображения.

Здесь показан код, который позволяет сделать это.

В этом коде мы предполагаем, что изображение полностью загружено.

Сначала мы получаем размер изображения.

Затем создаем массив для пикселей изображения.

Далее создаем объект PixelGrabber, который с помощью метода grabPixels позволяет извлечь пиксели в массив, указанный при создании объекта PixelGrabber.

После получения массива пикселей изображения, его можно обработать и создать новое изображение.

Для создания изображения из массива пикселей используется вспомогательный класс MemoryImageSource и объект Toolkit.

И наконец полученное изображение можно нарисовать.

На слайде показано, как создаются данные изображения за сценой.

Производитель изображения — это объект, который реализует интерфейс ImageProducer, и создает необработанные данные для объекта изображения Image.

Производитель изображения предоставляет эти данные потребителю изображения — объекту, который реализует интерфейс ImageConsumer.

Если вам не нужно манипулировать или создавать пользовательские изображения, вам обычно не нужно знать о производителе изображения и потребителе изображения.

AWT автоматически использует производителя и потребителя изображения за сценой.

При создании экземпляра класса Image требуется наличие производителя изображений.

Код глубоко внутри AWT создает производителя изображений.

Как альтернатива программист может предоставить создателя изображения, при создании объекта изображения Image.

При рисовании экземпляра класса Image методом draw, глубоко внутри AWT создается потребитель изображения.

Здесь показано, как при создании пользовательского компонента, можно с помощью метода createImage класса Component создать пользовательское изображение, реализуя собственные ImageProducer и ImageConsumer, и нарисовать это изображение в методе paint компонента.

Java позволяет «фильтровать» изображения с помощью класса ImageFilter или его подклассов.

AWT поддерживает обработку изображений, позволяя вставлять фильтры изображений между производителем изображения и потребителем изображения.

Фильтр изображения представляет собой объект ImageFilter, который находится между производителем и потребителем изображения, изменяя данные изображения до того, как потребитель получит его.

ImageFilter реализует интерфейс ImageConsumer, поскольку фильтр изображения перехватывает сообщения, которые производитель отправляет потребителю.

Для использования фильтра, создается объект фильтра.

Далее нужно создать объект класса ImageProducer.

Этот объект создается при помощи конструктора класса FilteredImageSource.

В качестве первого параметра мы передаем конструктору ссылку на источник данных исходного изображения, полученный методом getSource, а через второй — ссылку на свой фильтр.

Затем мы можем создать новое изображение методом createImage.

Чтобы дождаться процесса завершения формирования изображения, используйте класс MediaTracker.

После этого изображение готово и доступно для рисования методом drawImage.

Все фильтры изображений должны быть подклассами класса ImageFilter.

Если ваш фильтр изображения изменяет цвета или прозрачность изображения, вы можете создать подкласс класса RGBImageFilter, который расширяет класс ImageFilter.

Здесь показан простой фильтр изображения, который отфильтровывает отдельные цветовые компоненты (красный, зеленый и синий) изображения.

Класс ColorFilter расширяет класс RGBImageFilter и содержит три логические переменные, которые определяют, какие цвета должны быть отфильтрованы из изображения.

Эти переменные задаются параметрами, переданными в конструктор.

Переменная canFilterIndexColorModel, унаследованная от RGBImageFilter, установлена в значение true, чтобы указать, что записи цветовой карты могут быть отфильтрованы, если входящее изображение использует модель индексированного цвета.

В Java цвета пикселей управляются через цветовые модели.

Цветовые модели Java обеспечивают важную абстракцию, которая позволяет Java работать с изображениями разных форматов единым образом.

Цветовая модель представляет собой объект Java, который предоставляет методы для перевода значений пикселей в соответствующие красные, зеленые и синие цветовые компоненты изображения.

Это может показаться тривиальной задачей, зная, что компоненты цвета пикселей аккуратно упакованы в 32-битное значение.

Тем не менее, существуют различные типы цветовых моделей, отражающие различные методы определения цветов пикселей.

Двумя типами цветовых моделей, поддерживаемых Java, являются прямая цветовая модель и модель индексированных цветов.

Прямая цветовая модель работает со значениями пикселей, которые представляют цвет RGB и альфа-информацию отдельно, которые упакованы для каждого пикселя в одно значение.

Модель индексированных цветов поддерживается 8-битными изображениями, содержащими не более 256 цветов.

Эта модель работает с картой цветов изображения, в которой хранятся и индексируются цвета, используемые в изображении.

Эта позволяет уменьшить размер файла изображения, при этом сохраняя качество изображения.

Вернемся к нашему примеру.

Помимо конструктора, класс ColorFilter реализует только один метод filterRGB, который является абстрактным методом, определенным в классе RGBImageFilter.

Метод filterRGB принимает три параметра: положение x и y пикселя внутри изображения и 32-битное (целочисленное) значение цвета.

Единственный параметр, которым вы занимаетесь, является значение цвета, rgb.

Стандартная цветовая модель RGB помещает красные, зеленые и синие компоненты в нижние 24 бита 32-битного значения цвета.

И каждый из них можно извлечь, сдвигая параметр rgb.

Эти отдельные компоненты хранятся в локальных переменных r, g и b.

Обратите внимание, что здесь каждый компонент цвета смещается только в том случае, если он не фильтруется.

Для фильтрованных цветов, компонент цвета установлен в 0.

Новые цветовые компоненты затем переносятся обратно в 32-битное значение цвета и возвращаются из метода filterRGB.

Обратите внимание, что альфа-компонент значения цвета не изменяется.

Для этого используется маска 0xff000000, потому что альфа-компонент находится в верхнем байте значения цвета.

Помимо обработки изображений, с помощью вставки фильтров изображений между производителем изображения и потребителем изображения,

Java поддерживает фильтрацию изображений с помощью интерфейса BufferedImageOp.

Метод filter интерфейса BufferedImageOp принимает объект BufferedImage как вход (исходное изображение) и выполняет обработку данных изображения, создавая другой объект BufferedImage (конечное изображение).

Напомним, что класс BufferedImage расширяет класс Image, обеспечивая доступ к буферу данных изображения.

Java 2D API предоставляет набор реализаций интерфейса BufferedImageOp.

AffineTransformOp — преобразует изображение геометрически.

ColorConvertOp — выполняет по-пиксельное преобразование цвета в исходном изображении.

ConvolveOp — выполняет свертку, математическую операцию, которая может использоваться для размытия, изменения резкости или другой обработки изображения.

LookupOp — изменяет отдельные составляющие цвета.

RescaleOp — изменяет интенсивность изображения.

Здесь показан пример применения фильтра RescaleOp, изменяющего интенсивность цвета.

В этом примере сначала создается исходный объект BufferedImage на основе изображения, затем создается пустой объект BufferedImage.

Который заполняется отфильтрованными данными исходного изображения, с помощью метода filter созданного объекта RescaleOp.

Смотрите также

а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ э ю я