WebClub - Всероссийский Клуб Веб-разработчиков
WebClub.RU » Архив » ГРАФИКА В JAVA

ГРАФИКА В JAVA


Дата публикации: 17-03-2013

1) На чем можно рисовать?
На всем, что имеет графическое представление, т.е. на поверхности любого компонента, будь то окно, панель, кнопка или даже такой, компонент, который, казалось бы, не имеет никакого отношения к графике, как TextArea.

2) Что можно рисовать?
А) Графические примитивы, такие как линии, овалы, прямоугольники, многоугольники и ломаные линии - эти графические элементы можно объединить по их общему признаку - все они по своей сути "векторные", т.е. задаются некоторыми точками, между которыми тем и ли иным способом проводятся линии.
Б) Растровые образы - к ним относится класс Image. Объекты этого класса могут получать растровые изображения из графических файлов типа GIF и JPG (но на них, кстати, также можно рисовать и векторные примитивы).

3) Как рисовать?
Рассмотрим простейший способ нарисовать что-нибудь на компоненте. Если посмотреть на методы класса Component, то мы не найдем в нем методов, которые бы напрямую рисовали на поверхности компонента. Дело в том, что рисовать можно не на самом компоненте, а на так называемом "графическом контексте" компонента. Понятие "гра фического контекста" отражает особенности реализации графической системы любой операционной системы, будь то Windows или Macintosh. В частности графический контекст несет в себе такую важную для процесса рисования информацию, как размеры участка экрана, который принадлежит в данный момент компоненте, разрешающая способность, с которой следует рисовать, цвет и толщина линий рисования и т.п. Понятие графического контекста позволяет единообразно обращатся к любому графическому устройству, будь то простейши й компонент интерфейса или принтер.
В Java графический контекст представлен классом Graphics. Он-то и имеет все необходимые для рисования методы. Класс этот абстрактный, его экземпляр нельзя получить оператором new, но это и не надо, т.к. он и так всегда существует для каждого графического устройства.
Итак, первым делом надо получить "графический контекст" компонента. Делается это методом класса Component getGraphics(), возвращающий объект типа Graphics. Затем "на" (или, как обычно говорят, "в") этом объекте можно его методами рисовать, устанавливать цвет, шрифт и т.д. Например, программа могла бы выглядеть так:

//Simplest drawing on applet surface
import java.applet.Applet;
import java.awt.*;

public class SimpleDraw extends Applet {
public void init() {
Graphics gr; //Объявляем переменную типа Graphics
gr = getGraphics(); //получаем графический контекст апплета
gr.drawLine(10,10,190,190); //рисуем линию от точки (10,10)
} //до точки (190, 190)
}

"Могла бы" потому, что реально она не работает. И вот по какой причине: при исполнении метода init() линия на самом деле рисуется, но сам апплет и все его компоненты реально начинают рисоваться только по окончании метода init(). Это приводит к тому, что наш код, рисующий линию, никогда ничего не нарисует, ведь к моменту, когда визуально появится апплет, на котором ему надо рисовать, наш код уже "пройдет". Что ж, обойдем это тем, что введем кнопку, при нажатии на которую будем рисовать линию:

//Simplest drаwing on applet surface
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class SimpleDraw extends Applet implements ActionListener {
Graphics gr;
Button b;

public void init() {
b = new Button("Draw!");
add(b);
b.addActionListener(this);
gr = getGraphics();
}

public void actionPerformed(ActionEvent ae) {
gr.drawLine(10,10,190,190);
}
}

Теперь при нажатии кнопки линия рисуется. НО! Попробуйте изменить размеры окна апплетвьювера - вы увидете, что линия исчезла! Почему? А потому что при изменении размеров окна (равно как и при возвращении из минимизации или когда наше окно будет перекрыто (полностью или частично) другим окном и затем снова появится), окно апплетвьювера, сам апплет и все его компоненты будут заново перерисованы по команде системы. А наш код, рисующий линию, тогда уже не будет исполнен - система о нем не знает! Что же дела ть, чтобы система знала, что ей надо рисовать еще что-то кроме, самих компонентов? Для этого у каждого графического компонента есть метод paint() - он автоматически исполняется каждый раз в после того, как компонент перерисовался. В него-то и можно помес тить весь тот код, который будет рисовать то, что нужно пользователю. По умолчанию он пуст, т.е. не делает ничего. Программа теперь будет выглядить так (кнопку мы удалим, она теперь не нужна):

//Simplest drawing on applet surface
import java.applet.Applet;
import java.awt.*;

public class SimpleDraw extends Applet {
Graphics gr;

public void init() {
gr = getGraphics();
}

public void paint(Graphics g) {
gr.drawLine(10,10,190,190);
}
}

Теперь наша линия восстанавливается каждый раз после перерисовки окна.
Теперь обратим внимание на то, что, у метода paint есть параметр типа Graphics. Зачем он нужен? Дело в том, что система сама передает методу paint объект типа Graphics, который и является тем графическим контекстом, который нам необходим для рисования. Значит, мы можем вообще отказаться от получения графического контеста - система это сделает за нас! Программа теперь будет выглядеть так:

//Simplest drawing on applet surface
import java.applet.Applet;
import java.awt.*;

public class SimpleDraw extends Applet {
public void init(){ //метод init в этом случае можно вообще
} //не определять - он все равно пуст!

public void paint(Graphics g) {
g.drawLine(10,10,190,190); //Рисуем в том контексте, который нам
} //предоставила система
}

Разумеется, метод paint можно вызывать самостоятельно, передавая ему в качестве параметра тот графический контекст, в котором необходимо рисовать в данный момент. Но, как, например в нашем случае, мы будем знать о нем - мы ведь отказались от получения графического контекста, предоставив делать это системе? Для этого существует метод repaint() - в него не надо передавать ссылку на Graphics - он сам вызовет метод paint с необходимым параметром. Напишем еще один пример, в кото зывать repaint(), а в методе paint рисовать случайные линии, так, чтобы получить узор из множество хаотичных линий:

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class SimpleDraw extends Applet implements ActionListener {
Button b;

public void init() {
b = new Button("Draw");
add(b);
b.addActionListener(this);
}

public void actionPerformed(ActionEvent ae) {
repaint();
}

public void paint(Graphics g) {
g.drawLine((int)(Math.random()*200), (int)(Math.random()*200),
(int)(Math.random()*200), (int)(Math.random()*200));
}
}

Все работает, но почему-то линии рисуются каждый раз заново - предыдущая линия исчезает! Дело в том, что между методом repaint и методом paint находится еще один "посредник" - метод update:

repaint() --> update(Graphics) --> paint(Graphics)

Он делает следующие действия:
· очищает компонент, заливая его фоновым цветом;
· устанавливает текущий цвет компонента;
· вызывает метод paint.
Для того, чтобы линии накапливались на экране, необходимо переписать метод update, оставив в нем только вызов метода paint:

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

public class SimpleDraw extends Applet implements ActionListener {
Button b;

public void init() {
b = new Button("Draw");
add(b);
b.addActionListener(this);
}

public void update(Graphics g) {
paint(g);
}

public void actionPerformed(ActionEvent ae) {
repaint();
}

public void paint(Graphics g) {
g.drawLine((int)(Math.random()*200), (int)(Math.random()*200),
(int)(Math.random()*200), (int)(Math.random()*200));
}
}

Теперь мы получим то, что хотели!
Метод repaint имеет еще одно очень важное свойство: он вызывает метод update не немедленно, а как бы "ставит его в очередь", и если система занята выполнение более важных дел, исполняет через некоторое время только самый последний вызов, пропуская осталь ные. Это позволяет экономить системные ресурсы в случае, если вызовы на перерисовку идут непрерывно, например перерисовка связана с движениями мыши - тогда часть вызовов update просто неактуальна - мышь могла уже переместиться в другое место и рисовать некий "промежуточный" рисунок уже нет смысла. Кстати, есть даже разновидность метода repaint, позволяющая задать задержку исполнения метода update в миллисекундах.

Некоторые важные методы класса Graphics:

· public void drawLine(int x1, int y1, int x2, int y2) - рисование линии из точки (х1, y1) до точки (x2,y2);
· public void drawRect(int x, int y, int width, int height) - рисование прямоугольника из точки (х1, y1) шириной width и высотой height;
· public void fillRect(int x, int y, int width, int height) - то же, только прямоугольник залит текущим цветом;
· public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) - то же, только прямоугольник имеет закругленные углы по горизонтали с диаметром arcWidth и по вертикали arcHeight;
· public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) - то же, только залитый;
· public void drawOval(int x, int y, int width, int height) - овал, охватывающий прямоугольник которого задан параметрами х, y, width, height;
· public void fillOval(int x, int y, int width, int height) - то же, только залитый текущим цветом;
· public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) - рисует дугу - часть овала, охватывающий прямоугольник которого задан параметрами х, y, width, height, начало дуги (в градусах) - startAngle и продолжительность дуги (в градусах) - arcAngle. Нулевой угол дуги отсчитывается от "3-х часов". Положительное направление - против часовой стрелки.
· public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) - то же, только рисуется залитый сектор (не сегмент!) дуги.
· public void drawPolyline(int xPoints[], int yPoints[], int nPoints) - ломаная линия, проходящая через точки, заданные массивами xPoints[] и yPoints[];
· public void drawPolygon(int xPoints[], int yPoints[], int nPoints) - то же, только линия сама замыкается на первую точку, образуя замкнутый полигон;
· public void fillPolygon(int xPoints[], int yPoints[], int nPoints) - то же, только полигон залит текущим цветом;
· public void drawString(String str, int x, int y) - рисует строку текста str начиная с точки (x, y). Следует учитывать, что эти координаты указывают на базовую линию текста начиная с левого нижнего края.
· public void setClip(int x, int y, int width, int height) - устанавливает "прямоугольник отсечения" - область в которой только будут происходит последуюшие рисования;
· public void setColor(Color c) - устанавливает текущий цвет рисования;
· public void setFont(Font font) - устанавливает текущий шрифт;
· public void setPaintMode() и setXORMode (Сolor c1) - устанавливает режимы рисования (обычный или XOR);
· public boolean drawImage(Image img, int x, int y, ImageObserver observer) и другие разновидности этого метода - рисует растровый рисунок, находящийся в объекте img;

Класс Image

Абстрактный класс Image является "вместилищем", или лучше сказать "полотном" для рисования на нем или рисования его самого в ином графическом контексте. Проще можно представлять Image, как растровую картинку, находяшуюся "за экраном", невидимую до тех пор, пока ее не нарисовали в каком либо графическом контексте.
Из немногочисленных методов самого класса Image наиболее интересны следующие:
· public int getHeight(ImageObserver observer) и getWidth(ImageObserver observer) - позволяют получить ширину и высоту картинки;
· public Image getScaledInstance(int width, int height, int hints) - возвращает "масштабированную" картинку с новыми размерами width и height, а параметр hints позволяет задать алгоритм масштабирования;
· public Graphics getGraphics() - этот метод позволяет получит графический контекст картинки, на котором затем можно рисовать.

Но главные методы для работы с Image находятся в других классах.
Во-первых, это метод createImage(int width, int height) класса Component - он позволяет создать "пустую" картинку с заданными размерами (в пикселях);
Во-вторых, это два метода класса Applet - getImage(URL url) и getImage(URL url, String name). Они позволяют загрузить картинку из растрового файла, находящегося по адресу в Интернете (а также и из локальной файловой системы).

Примеры программ, работающих с Image:
//painting images on applet
//Size 400x400
import java.applet.Applet;
import java.awt.*;
import java.net.*;

public class Images1 extends Applet {
Image im[];
URL url;
int count;
Image empty;

public void init() {
setLayout(null);
im = new Image[8];
empty = createImage(200,200);
try {url = new URL("file:///c:\\jdk116\\bin\\images\\");}
catch(MalformedURLException murle){}
for (int i=0; i<8; i++) im[i] = getImage(url,"arrow"+i+".gif");
Counter counter = new Counter();
Thread t = new Thread(counter);
t.start();
}

public void update(Graphics g) {
paint(g);
}

public void paint(Graphics g) {
//g.drawImage(empty,100,100,200,200,this);
g.drawImage(im[count],100,100,200,200,this);
}

class Counter extends Thread {
public void run() {
count = 0;
while (count<8) {
repaint();
try {Thread.sleep(100);}
catch(InterruptedException ie) {}
count++; if (count==8) count=0;
}
}
}
}

//painting images on applet without flicks
//Size 400x400
import java.applet.Applet;
import java.awt.*;
import java.net.*;

public class Images2 extends Applet {
Image im[];
URL url;
int count;
Image tmpI;
Graphics tmpG;

public void init() {
//setLayout(null);
im = new Image[8];
tmpI = createImage(200,200);
tmpG = tmpI.getGraphics();
try {url = new URL("file:///c:\\jdk116\\bin\\images\\");}
catch(MalformedURLException murle){}
for (int i=0; i<8; i++) im[i] = getImage(url, "arrow"+i+".gif");
Counter counter = new Counter();
Thread t = new Thread(counter);
t.start();
}

/* public void update(Graphics g) { paint(g); }*/

public void paint(Graphics g) {
tmpG.drawImage(im[count],0,0,200,200,this);
g.drawImage(tmpI,100,100,200,200,this);
}

class Counter extends Thread {
public void run() {
count = 0;
while (count<8) {
repaint();
try {Thread.sleep(100);}
catch(InterruptedException ie) {}
count++; if (count==8) count=0;
}
}
}
}

Популярное

Не так давно в сети появился новый сервис, под названием Dead Man Zero. Этот сервис сделал...
Рынок социальных площадок уже давно стал стабильным. Несмотря на то, что время от времени...
Artisteer 4 – единственный в своем роде продукт, позволяющий автоматизировать работу над созданием...
Март 2017 (1)
Февраль 2017 (3)
Январь 2017 (1)
Август 2016 (1)
Май 2016 (2)
Ноябрь 2015 (1)

Карта сайта: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41

Друзья сайта

Хотите продать свой сайт?
- Мы быстро и удобно для Вас сможем его купить:
  • Заявка на продажу сайта
  • Раcсматриваем цены на каждый сайт в индивидуальном порядке.

    Случайная цитата

    Alan J. Perlis:

    "Когда кто-то говорит: «Я хочу язык программирования, который может делать все, что ему скажу», то я даю этому человеку леденец."

    Опрос

    Ваша техника?

    Настольный компютер
    Ноутбук
    Смартфон
    iPad
    iPhone
    другое