Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Графика в Java
Лекция 7
18 октября 2021 г.
1 / 34
Содержание
1
Пакеты
2
Наследование, абстрактные классы и интерфейсы
3
Графический пользовательский интерфейс
4
Векторная графика
5
Графический контекст (поверхность для рисования)
2 / 34
Содержание
1
Пакеты
2
Наследование, абстрактные классы и интерфейсы
3
Графический пользовательский интерфейс
4
Векторная графика
5
Графический контекст (поверхность для рисования)
3 / 34
Пакеты
Пакет — это множество классов и других типов.
Пакеты организованы в виде дерева.
java
awt
base
io
lang
util
color
geom
image
Если узел x является потомком узла y, то говорят,
что пакет x вложен в пакет y.
Важно: то, что x вложен в y, не означает, что x ⊆ y.
Пакеты аналогичны каталогам, а классы — содержащихся в них
файлам.
Множество файлов подкаталога не является подмножеством
множества файлов каталога.
4 / 34
Полное имя класса
Имена пакетов состоят из строчных букв.
Полное имя пакета состоит из имен всех пакетов, в которые он
вложен.
Полное имя класса состоит из имени класса и полного имени
содержащего его пакета.
Пример: Класс Ellipse2D в пакете geom.
geom вложен в awt, а тот вложен в java.
Полное имя класса: java.awt.geom.Ellipse2D.
Компании, выпускающие классы, помещают их в пакет с именем,
построенным из доменов своего сайта в обратном порядке.
Пример: android.mycompany.com
7→
com.mycompany.android.
5 / 34
Структура пакетов = структура каталогов
Пакеты, являющиеся частью Java, начинаются с java или javax.
Структура каталогов, содержащих файлы с классами, совпадает со
структурой пакетов.
Пример: класс graphics.shapes.Point содержится в файле
graphics\shapes\Point.java
Важные пакеты:
• java.lang: основные классы. Подключается по умолчанию;
• java.util: массивы и коллекции (список, очередь и т.д.);
• java.awt: графический интерфейс (устаревший), события и
пиксельная графика;
• java.awt.geom: векторная графика;
• javax.swing: графический интерфейс (который будем
использовать).
6 / 34
Импорт пакетов и классов
• Чтобы включить класс в пакет package_name, нужно в первой
строчке файла с этим классом написать
package package_name;
• Чтобы использовать классы из другого пакета без указания
полного имени
import java.awt.geom.Line2D;
или
import java.awt.geom.*; // все классы пакета
• Поскольку вложенность не означает подмножества,
import java.awt.*;
не подключает java.awt.geom.
• Если нет инструкции package, то класс помещается в пакет по
умолчанию.
7 / 34
Пакеты и путь к классам
Компилировать и запускать файлы нужно из каталога, являющегося
базовым для пакета.
Текущий каталог + имя пакета = путь к классу.
Пример
Хотим скомпилировать или запустить класс graphics.shapes.Test.
Предположим, класс находится в
C:\Users\Username\java\graphics\shapes\Test.java.
Нужно быть в каталоге C:\Users\Username\java.
8 / 34
Компиляция и запуск класса
Пусть класс graphics.shapes.Test находится в
C:\Users\Username\java\graphics\shapes\Test.java.
Компиляция:
C:\Users\Username\java> javac graphics\shapes\Test.java
Запуск:
C:\Users\Username\java> java graphics.shapes.Test
Важно:
Аргументом javac является имя файла.
Аргументом java является полное имя класса, включая имя пакета.
Компилировать можно из каталога, содержащего файл, но если Test
использует другие классы того же пакета, они не будут найдены.
9 / 34
Переменная CLASSPATH
Чтобы компилировать и запускать файлы из любого каталога,
можно установить переменную CLASSPATH (путь к классам).
Рассмотрим класс: graphics.shapes.Test с методом main.
Находится в C:\Users\Username\java\graphics\shapes\Test.java.
Если CLASSPATH включает C:\Users\Username\java, то
компилировать и запускать класс можно из любого каталога.
Естественно, при компиляции нужно указать полное имя файла.
C:\> javac C:\Users\Username\java\graphics\shapes\Test.java
C:\> java graphics.shapes.Test
Установка CLASSPATH в командной строке.
C:\> set CLASSPATH=C:\Users\Username\java
Или непосредственно в аргументе команд java и javac
C:\> java -cp C:\Users\Username\java graphics.shapes.Test
10 / 34
Переменная CLASSPATH
Если CLASSPATH определена или указана в аргументе, но не
содержит текущий каталог ., то файлы .class в текущем каталоге
не будут найдены.
Это случается, когда инсталляторы программ устанавливают
CLASSPATH под себя и не включают текущий каталог.
Примеры добавления текущего каталога
C:\> set CLASSPATH=.;C:\Users\Username\java
C:\> java -cp .;C:\Users\Username\java graphics.shapes.Test
Резюме
Если java или javac не находят ваш класс в текущем каталоге,
проверьте, к какому пакету он принадлежит и перейдите в
родительский каталог этого пакета.
Если java или javac не находят классы пакета по умолчанию в
текущем каталоге, добавьте аргумент -cp .
C:\Users\Username\java> java -cp . MyClass
11 / 34
Содержание
1
Пакеты
2
Наследование, абстрактные классы и интерфейсы
3
Графический пользовательский интерфейс
4
Векторная графика
5
Графический контекст (поверхность для рисования)
12 / 34
Абстрактные классы
Любой класс можно объявить абстрактным с помощью ключевого
класса abstract.
Нельзя создать объекты абстрактного класса, но можно объявить
подклассы.
Абстрактный класс — это «пересечение» функциональности своих
подклассов.
Абстрактные методы имеют только сигнатуру.
abstract void abstractMethod(int argument);
Если есть хотя бы один абстрактный метод, то класс должен быть
объявлен абстрактным.
13 / 34
Интерфейсы
Интерфейс: похож на абстрактный класс, у которого все методы
абстрактные.
Может иметь константы (static final).
По умолчанию члены интерфейса открытые (public).
Для подкласса интерфейса вместо extends используется
implements («реализует»).
Важно: класс может реализовывать несколько интерфейсов.
Выступает как тип
interface Figure { ... }
class Square extends Rectangle2D.Double implements Figure {...}
Figure f = new Square(100, 100, 50, Color.BLUE);
14 / 34
Содержание
1
Пакеты
2
Наследование, абстрактные классы и интерфейсы
3
Графический пользовательский интерфейс
4
Векторная графика
5
Графический контекст (поверхность для рисования)
15 / 34
Пакеты AWT и Swing
• Пакет AWT (Abstract Window Toolkit): java.awt
I
I
I
Более ранний
Использует элементы интерфейса операционной системы
Программа под разными ОС выглядят по-разному
• Пакет Swing: javax.swing
I
I
I
I
Широко использует AWT
Рисует свои собственные элементы интерфейса
Программа под разными ОС выглядит одинаково
Имеет несколько стилей оформления
• Пакет JavaFX: современная замена Swing
(не будем рассматривать)
16 / 34
Пакеты AWT и Swing
Object
AWT
Component
Container
Window
Frame
Dialog
JFrame
JDialog
JComponent
JPanel
JLabel
Swing
JAbstractButton
JButton
17 / 34
Компоненты
Каждому элементу интерфейса (окно, кнопка) соответствует класс.
Элементы интерфейса Swing:
• контейнеры верхнего уровня, тяжеловесные компоненты
(имеют свое собственное окно):
I
I
I
JFrame (окно, фрейм);
JDialog;
JApplet.
• легковесные компоненты (рисуются внутри окна):
подклассы JComponent.
Некоторые компоненты являются контейнерами.
Пример: JPanel (панель).
Каждый компонент должен в итоге принадлежать контейнеру
верхнего уровня.
18 / 34
Создание окна
private static void createAndShowGUI() {
JFrame frame = new JFrame("Рисунок");
// Сделать так, чтобы при закрытии окна программа закончилась.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Создать панель. Чтобы на ней рисовать, нужно создать.
// подкласс JPanel (см. далее)
JPanel panel = new JPanel();
/* Установить размер панели. */
panel.setPreferredSize(new Dimension(500, 500));
// Добавить панель к окну.
frame.add(panel);
// Сделать так, чтобы панель помещалась в окне.
frame.pack();
// Показать окно.
frame.setVisible(true);
}
19 / 34
Минимальная программа
import
import
import
import
java.awt.Dimension;
javax.swing.JFrame;
javax.swing.JPanel;
javax.swing.SwingUtilities;
public class Drawing {
private static void createAndShowGUI() {
...
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Drawing::createAndShowGUI);
}
}
20 / 34
Подкласс JPanel
Каждый компонент (подкласс JComponent) имеет метод
void paintComponent(), который рисует этот компонент.
У JPanel этот метод закрашивает панель цветом фона,
если она непрозрачна.
Поэтому программа выше рисует пустую панель.
Чтобы на ней что-то нарисовать, нужно переопределить
paintComponent().
Это можно сделать только в подклассе.
При этом перед методом очень желательно писать @Override,
чтобы убедиться, что вы его действительно переопределили,
а не написали метод с похожей сигнатурой.
21 / 34
Подкласс JPanel
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class DrawingPanel extends JPanel {
public DrawingPanel() {
setBackground(Color.WHITE);
setOpaque(true);
// Два способа установить размер панели:
// 1. setPreferredSize(new Dimension(500, 500));
// в конструкторе или createAndShowGUI()
// 2. переопределить getPreferredSize ниже
}
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
@Override
protected void paintComponent(Graphics g) { ... }
}
22 / 34
Содержание
1
Пакеты
2
Наследование, абстрактные классы и интерфейсы
3
Графический пользовательский интерфейс
4
Векторная графика
5
Графический контекст (поверхность для рисования)
23 / 34
Пакеты java.awt и java.awt.geom
Пакет java.awt
• экранная система координат;
• пиксельная графика;
• координаты типа int.
Пакет java.awt.geom
• мировая (пользовательская) система координат;
• векторная графика;
• координаты типа float или double.
24 / 34
Недостатки пиксельной графики
• Невозможность изменить ширину и стиль линии.
• Отсутствие методов для рисования кривых, кроме дуг эллипсов.
• Невозможность нарисовать эллипс, повернутый на угол, не
кратный 90◦ .
• Погрешность из-за того, что координаты являются целыми
числами.
• Отсутствие представления сложной фигуры как единого целого.
• Необходимость явного преобразования координат из
пользовательского пространства (например, из сантиметров)
в пиксели.
25 / 34
Классы фигур
Пакет jawa.awt.geom содержит классы, представляющие фигуры в
мировых координатах.
Point2D.Double(x, y)
Line2D.Double(x1, y1, x2, y2) // Концы отрезка
Rectangle2D.Double(x, y, w, h)
// Координаты угла, ширина, высота
Ellipse2D.Double(x, y, w, h) // Габаритный прямоугольник
Arc2D.Double(x, y, w, h, start, extent, type)
QuadCurve2D.Double(x1, y1, xc, yc, x2, y2)
CubicCurve2D.Double(x1, y1, xc1, yc1, xc2, yc2, x2, y2)
Составное имя, например, Arc2D.Double, можно воспринимать как
один идентификатор.
Есть также соответствующие классы .Float, в которых координаты
имеют тип float.
26 / 34
Дуга эллипса
x
(x, y)
β
α
(x + w, y + h)
y
Arc2D.Double(x, y, w, h, α, β, Arc2D.OPEN)
Углы отсчитываются в направлении, противоположном направлению
вращения оси x к y.
Углы измеряются в градусах.
α, β — величины параметра t в параметрическом задании эллипса
x = (w/2) cos t, y = (h/2) sin t.
Последний аргумент может также быть Arc2D.CHORD (концы дуги
соединены хордой) или Arc2D.PIE (концы соединены с центром).
27 / 34
Кривые Безье
(x2 , y2 )
(xc2 , yc2 )
(xc1 , yc1 )
(x1 , y1 )
(xc , yc )
QuadCurve2D.Double
(x1 , y1 , xc , yc , x2 , y2 )
(x1 , y1 )
(x2 , y2 )
CubicCurve2D.Double
(x1 , y1 , xc1 , yc1 , xc2 , yc2 , x2 , y2 )
Отрезки являются кривыми Безье первого порядка.
На самом деле, кривая Безье n-го порядка — это параметрическая
кривая (x(t), y(t)), где x(t) и y(t) — полиномы n-го порядка.
Особенность состоит в том, что полиномы заданы не в степенном
базисе (1, t, t2 , . . .), а в некотором другом базисе.
28 / 34
Классы фигур
Точности float хватает, но
• нужно писать f после констант: 3.14f;
• часто нужно приводить тип из double в float:
float x = (float) p.getX();
Все эти классы, кроме Point2D.Double, реализуют интерфейс Shape.
public interface Shape {
// Проверяет, содержит ли фигура точку (x, y)
boolean contains(double x, double y);
// Проверяет, пересекается ли фигура с прямоугольником
boolean intersects(double x, double y, double w, double h);
...
}
Нужно создавать объекты классов Line2D.Double и т.п.
Полиморфизм: аргументам методов следует давать типы Line2D
(принимает также Line2D.Float) или Shape (все фигуры).
29 / 34
Содержание
1
Пакеты
2
Наследование, абстрактные классы и интерфейсы
3
Графический пользовательский интерфейс
4
Векторная графика
5
Графический контекст (поверхность для рисования)
30 / 34
Графический контекст Graphics
protected void paintComponent(Graphics g) { ... }
определен в классе JComponent и наследуется всеми компонентами.
Вызывается автоматически, когда компонент нужно перерисовать.
Чтобы рисовать на панели, нужно написать подкласс JPanel и
переопределить этот метод.
Не требуется стирать старую информацию, нужно просто
нарисовать все заново.
Аргумент метода — объект класса ava.awt.Graphics — содержит
следующую информацию:
• окно, в котором происходит рисование,
• текущий цвет,
• текущий шрифт,
• начало координат,
• и т.д.
31 / 34
Графический контекст Graphics2D
Graphics2D является подклассом Graphics (оба класса
абстрактные).
Аргумент метода paintComponent(Graphics g) является на самом
деле объектом подкласса Graphics2D.
Кроме информации в Graphics, содержит AffineTransform
(аффинное отображение) и Stroke (перо).
Некоторые методы класса Graphics2D:
void setStroke(Stroke s)
void draw(Shape s)
// Рисует любую фигуру, реализующую интерфейс Shape
void fill(Shape s)
// Заполняет текущим цветом любую фигуру, реализующую Shape
32 / 34
Графический контекст Graphics2D
Метод paintComponent(Graphics g) в классе JPanel закрашивает
панель цветом фона.
В переопределенном методе в подклассе нужно вызвать
super.paintComponent(g);
Затем, чтобы иметь возможность пользоваться методами
Graphics2D, следует привести g к типу Graphics2D
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// Рисование
}
33 / 34
Пример paintComponent()
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int w = getWidth(); // возвращает ширину панели в пикселях
int h = getHeight(); // возвращает высоту панели в пикселях
Ellipse2D.Double ellipse =
new Ellipse2D.Double(w/4, h/4, w/2, h/2);
g2.draw(ellipse);
w/4
x
}
h/4
h/2
y
w/2
34 / 34