Создание собственных компонентов

 

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

Если надо скомбинировать несколько компонентов в один, новый, компонент, то достаточно расширить класс Panel, расположив компоненты на панели.

Если же требуется создать совершенно новый компонент, то AWT предлагает две возможности: создать «тяжелый» или «легкий» компонент. Для создания собственных «тяжелых» компонентов в библиотеке AWT есть класс canvas — пустой компонент, для которого создается свой peer-объект графической системы.

 

Компонент Canvas

 

Компонент canvas — это пустой компонент. Класс canvas очень прост — в нем только конструктор по умолчанию Canvas о и пустая реализация метода paint(Graphics g).

Чтобы создать свой «тяжелый» компонент, необходимо расширить класс canvas, дополнив его нужными полями и методами, и при необходимости переопределить метод paint ().

Например, как вы заметили, на стандартной кнопке Button можно написать только одну текстовую строку. Нельзя написать несколько строк или отобразить на кнопке рисунок. Создадим свой «тяжелый» компонент — кнопку с рисунком.

В листинге 10.7 кнопка с рисунком — класс FiowerButton. Рисунок задается методом drawFiower (), а рисуется методом paint (). Метод paint (), кроме того, чертит по краям кнопки внизу и справа отрезки прямых, изображающих тень, отбрасываемую «выпуклой» кнопкой. При нажатии кнопки мыши на компоненте такие же отрезки чертятся вверху и слева — кнопка «вдавилась». При этом рисунок сдвигается на два пиксела вправо вниз — он «вдавливается» в плоскость окна.

Кроме этого, в классе FiowerButton задана реакция на нажатие и отпускание кнопки мыши. Это мы обсудим в главе 12, а пока скажем, что при каждом нажатии и отпускании кнопки меняется значение поля isDown и кнопка перечерчивается методом repaint (). Это достигается выполнением методов mousePressed() И mouseReleased().

Для сравнения рядом помещена стандартная кнопка типа Button того же размера.

 

Листинг 10.7. Кнопка с рисунком 

import j ava.awt.*;

import j ava.awt.event.*;

class FiowerButton extends Canvas implements MouseListener{ 

private boolean isDown=false; 

public FiowerButton(){

super();

setBackground(Color.lightGray);

addMouseListener(this); 

}

public void drawFlower(Graphics g, int x, int y, int w, int h){ 

g.drawOvalfx + 2*w/5 — 6, y, w/5, w/5);

g.drawLine(x + w/2 — 6, у + w/5, x + w/2 — 6, у + h — 4); 

g.drawOvalfx + 3*w/10 -6, у + h/3 — 4, w/5, w/5) ; 

g.drawOval(x + w/2 — б, у + h/3 — 4, w/5, w/5); } 

public void paint(Graphics g){

int w = getSizeO.width, h = getSize().height; 

if (isDown){

g.drawLine(0, 0, w — 1, 0) ; 

g.drawLined, 1, w — I, I); 

g.drawLine(0, 0, 0, h — 1); 

g.drawUne (1, 1, 1, h — 1); 

drawFlower(g, 8, 10, w, h); 

}

else

{

g.drawLine(0, h — 2, w — 2, h — 2); 

g.drawLined, h — 1, w — I, h — I); 

g.drawLinefw — 2, h — 2, w — 2, 0); 

g.drawLinefw — 1, h — 1, w — 1, 1); 

drawFlower (g, 6, 8, w, h) ; } }

public void mousePressed(MouseEvent e){ 

isDown=true; repaint(); }

public void mouseReleased(MouseEvent e){ 

isDown=false; repaint(); }

public void mouseEntered(MouseEvent e){} 

public void mouseExited(MouseEvent e) {} 

public void mouseClicked(MouseEvent e){) 

}

class DrawButton extends Frame{ 

DrawButton(String s) { 

super (s) ; 

setLayout(null);

Button b = new Button(«OK»); 

b.setBounds(200, 50, 100, 60); add(b);

FlowerButton d = new FlowerButton(); 

d.setBounds(50, 50, 100, 60); add(d);

setSize(400, 150); 

setVisible(true);

}

public static void main(String[] args){

Frame f= new DrawButton(» Кнопка с рисунком»); 

f.addWindowListener(new WindowAdapter()(

public void windowClosing(WindowEvent ev){

System.exit(0);  

}

}); 

}

 

Создание «легкого» компонента

 

«Легкий» компонент, не имеющий своего peer-объекта в графической системе, создается как прямое расширение класса component или Container. При этом необходимо задать те действия, которые в «тяжелых» компонентах выполняет peer-объект.

Например, заменив в листинге 10.7 заголовок класса FlowerButton строкой 

class FlowerButton extends Component implements MouseListener{

а затем перекомпилировав и выполнив программу, вы получите «легкую» кнопку, но увидите, что ее фон стал белым, потому что метод

setBackground(Color.lightGray) не сработал.

Это объясняется тем, что теперь всю черную работу по изображению кнопки на экране выполняет не peer-двойник кнопки, а «тяжелый» контейнер, в котором расположена кнопка, в нашем случае класс Frame. Контейнер же ничего не знает о том, что надо обратиться к методу setBackground о, он рисует только то, что записано в методе paint (). Придется убрать метод setBackground о из конструктора и заливать фон серым цветом вручную в методе paint о, как показано в листинге 10.8.

«Легкий» контейнер не умеет рисовать находящиеся в нем «легкие» компоненты, поэтому в конце метода paint () «легкого» контейнера нужно обратиться к методу paint () суперкласса: 

super.paint(g);

Тогда рисованием займется «тяжелый» суперкласс-контейнер. Он нарисует и лежащий в нем «легкий» контейнер, и размещенные в контейнере «легкие» компоненты.

Совет

Завершайте метод paint () «легкого» контейнера обращением к методу paint () суперкласса.

Предпочтительный размер «тяжелого» компонента устанавливается peer-объектом, а для «легких» компонентов его надо задать явно, переопределив метод getPreferredSize(), иначе некоторые менеджеры размещения, например FiowLayout (), установят нулевой размер, и компонент не будет виден на экране.

Совет

Переопределяйте метод getPref erredSize () .

Интересная особенность «легких» компонентов — они изначально рисуются прозрачными, не закрашенная часть прямоугольного объекта не будет видна. Это позволяет создать компонент любой видимой формы. Листинг 10.8 показывает, как можно изменить метод paint о листинга 10.7 для создания круглой кнопки и задать дополнительные методы.

 

Листинг 10.8. Создание круглой кнопки ;

public void paint(Graphics g){

int w = getSize().width, h = getSize().height;

int d = Math.min(w, h);      // Диаметр круга

Color с = g.getColor();      // Сохраняем текущий цвет

g.setColor(Color.lightGray); // Устанавливаем серый цвет

g.fillArc(0, 0, d, d, 0, 360); // Заливаем круг серым цветом

g.setColor(с);               // Восстанавливаем текущий цвет

if (isDown)(

g.drawArc(0, 0, d, d, 43, 180);

g.drawArcd, 1, d — 2, d — 2, 43, 180);

drawFlower(g, 8, 10, d, d);

}else{

g.drawArc(0, 0, d, -d, 229, 162);

g.drawArcd, 1, d — 2, d — 2, 225, 170);

drawFlower(g, 6, 8, d, d); 

public Dimension getPreferredSize(){

return new Dimension(30,30); 

}

public Dimension getMinimumSize()

{

return getPreferredSize(); } 

public Dimension getMaximumSize(){

return getPreferredSize(); 

}

Сразу же надо дать еще одну рекомендацию. «Легкие» контейнеры не занимаются обработкой событий без специального указания. Поэтому в конструктор «легкого» компонента следует включить обращение к методу enabieEvents () для каждого типа событий. В нашем примере в конструктор класса FiowerButton полезно добавить строку

enabieEvents(AWTEvent.MOUSE_EVENT_MASK);

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