Главная » Java, Web » Работа с графикой

0

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

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

Для представления изображений в языке Java используется стандартный класс j ava. awt. Image. Каждый объект типа Image содержит информацию о конкретном изображении. Существует два типа объектов image. Один тип — это изображения, хранимые в виде файлов. Другой тип — это изображения, хранимые в памяти компьютера.

Каждое изображение представлено с помощью набора чисел, но представление это может быть произведено не одним-единственным образом. Так, для файлов изображений существует два стандартных способа кодирования изображений, используемых в языке Java. Один способ используется для создания GIF изображений, другой — для создания JPEG-изображений. Со- ответсвующие им файлы имет расширения gif и jpg или jpeg. Тот и другой формат являются сжатыми, в них уменьшен объем памяти, требуемый для хранения изображения.

В классе Applet определен метод getimage, этот метод используется для загрузки изображения, хранимого в виде файла GIF или JPEG, например,

img = getimage(getCodeBase(), "асе.gif");

Эта инструкция приведет к появлению объекта изображения. Второй аргумент в методе — это имя файла с изображением. Первый аргумент — это директория, в которой расположен файл с рисунком, значение getCodeBase () соответствует тому, что файл с рисунком находится в том же каталоге, что и содержащий его апплет. После того как получен объект рисунка, его можно отобразить в любом графическом контексте. Наиболее часто при этом используется метод paintComponent () в компоненте jPanel (или в каком-либо другом компоненте):

g.drawlmage(img, х, у, this);

Эта команда используется для отображения рисунка в компоненте. Параметры х и у — это положение верхнего левого угла рисунка, а размер прямоугольника будет таким, чтобы весь рисунок был отображен в натуральную величину. Четвертый параметр — это компонент, где рисунок будет отображен. При обращении к getimageo запрашиваемый файл не будет скачиваться немедленно. Файл будет запрошен только тогда, когда он должен отобразиться в первый раз. Объект image просто запоминает местонахождение файла. Этот метод начинает скачивание файла, но не дожидается его завершения. Четвертый параметр — это объект, который наблюдает за изображением. После того как рисунок будет полностью получен, система сообщит наблюдателю за изображением о том, что этот рисунок теперь стал доступным. В качестве наблюдателя может использоваться любой компонент jcomponent. Если известно, что рисунок уже загружен, то четвертый параметр можно указать в виде null.

Существуют и другие методы вызова drawimage (). Например, задается размер изображения:

g.drawimage(img, х, у, width, height, this); Можно нарисовать лишь часть изображения:

д.drawimage(img, dest_xl, dest_yl, dest_x2, dest_y2,

source_xl, source_yl, source_x2, source_y2, this);

Здесь координаты source_xl, source_yl, source_x2 и source_y2 задают верхний левый и нижний правый углы той части изображения, которая будет показана. Координаты dest_xl, dest_yl, dest_x2, dest_y2 — это координаты графического контекста. При необходимости будет произведено соответствующее координатам сжатие или растяжение рисунка. Далее мы рассмотрим пример с картами. Этот пример будет использовать только один рисунок для отображения всех 52 карт (рис. 1.23).

Рис. 1.23. Игральные карты на одном рисунке

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

В этом апплете карты отображаются с использованием следующего метода. В переменной типа image и именем cardimages хранится рисунок с изображениями 52 карт (рис. 1.23). Размер каждой карты составляет 40 х 60 пикселов. На основе этого создаются изображения для каждой карты в отдельности (листинг 1.25).

j Листинг 1.25. Функция drawCardO

void drawCard(Graphics g, Card card, int x, int y) { if (card == null) { // описание карты рубашкой вверх g.setColor(Color.blue); g. f illRect (x, y, 4 0, 60) ; g.setColor(Color.white); g.drawRect(x+3,y+3,33,53); g.drawRect(x+4,y+4,31,51);

else {

int row =0; // определение ряда, в котором нарисована текущая карта switch (card.getSuit()) { case Card.CLUBS: row = 0; break; case Card.HEARTS: row = 1; break; case Card.SPADES: row = 2; break;

case Card.DIAMONDS: row = 3; break; }

int sx, sy; // координаты верхнего левого угла карты

//в заданном рисунке sx = 4 0*(card.getValue() — 1); sy = 60*row;

g.drawlmage(cardimages, x, y, x+40, y+60, sx, sy, sx+40, sy+60, this);

}

Далее приводится программный код, состоящий из четырех файлов. Основная программа — Cards.java. Кроме нее потребуется наличие файлов Card.java, Hand.java, Deck.java (листинги 1.26, 1.27 и 1.28).

Листинг 1.26. Файл Cards.java

Простая карточная игра «Угадай, что дальше»

impo гt j ava.awt.*; impo rt j ava.awt.event.*; import javax.swing. *; public class Cards extends JApplet { java.awt.Image cardlmages; public void init() { cardlmages = getImage(getCodeBase(), "smallcards.gif"); setBackground(new Color (130,50,40)); HighLowCanvas board = new HighLowCanvas(); getContentPane().add(board, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); buttonPanel.setBackground(new Color(220,200,180)); getContentPane().add(buttonPanel, BorderLayout.SOUTH); JButton higher = new JButton("Starshe"); higher.addActionListener(board); buttonPanel.add(higher); JButton lower = new JButton("Mladshe"); lower.addActionListener(board); buttonPanel.add(lower);

JButton newGame = new JButton("New Game"); newGame.addActionListener(board);

buttonPanel.add(newGame); }

public Insets getlnsetsO {

return new Insets(3,3,3,3); }

class HighLowCanvas extends JPanel implements ActionListener { Deck deck; // колода карт

Hand hand;                // сбрасываемая карта

String message;           // сообщение

boolean gamelnProgress; // состояние игры Font bigFont;     // шрифт отображения сообщения

Font smallFont;           // шрифт для отображения карт

HighLowCanvas() { setBackground(new Color(0,120,0)); setForeground(Color.green);

smallFont = new Font("SansSerif", Font.PLAIN, 12); bigFont = new Font("Serif", Font.BOLD, 14); doNewGame ();

}

public void actionPerformed(ActionEvent evt) { String command = evt.getActionCommand(); if (command.equals("Starshe")) doHigher();

else if (command.equals("Mladshe")) doLower(); else if (command.equals("New Game"))

doNewGame (); }

void doHigher () {

if (gamelnProgress == false) { message = "Click Y’New GameV first!"; repaint();

return; }

hand.addCard(deck.dealCard()); int cardCt = hand.getCardCount(); Card thisCard = hand.getCard(cardCt — 1); // описание предыдущей карты Card prevCard = hand.getCard(cardCt — 2); if (thisCard.getValue() < prevCard.getValue()) { gamelnProgress = falser-

message = "Vy proigrali!"; }

else if (thisCard.getValue() == prevCard.getValue()) { gamelnProgress = falser-

message = "Ploho poluchilos!"; }

else if (cardCt ==4) { gamelnProgress = falser-

message = "OK! Vy Vyuigrali!"; }

else {

message = "Pravilno! Popytajtes " + cardCt + "."; }

repaint();

}

void doLower() {

if (gamelnProgress == false) { message = "Snachala nazhmite "New Game" !"; repaint();

return; }

hand.addCard(deck.dealCard()); int cardCt = hand.getCardCount(); Card thisCard = hand.getCard(cardCt — 1); Card prevCard = hand.getCard(cardCt — 2); if (thisCard.getValue() > prevCard.getValue()) { gamelnProgress = falser-

message = "Vy proigrali!"; }

else if (thisCard.getValue() == prevCard.getValue()) { gamelnProgress = falser-

message = "Ne verno."; }

else if (cardCt ==4) { gamelnProgress = false;

message = "Zamechatelno! Vy vyigrali!"; }

else {

message = "Pravilno! Popytites " + cardCt + "."; }

repaint();

}

void doNewGame() {

if (gamelnProgress) { message = "Zavershite igru!"; repaint();

return; }

deck = new Deck();

hand = new Hand(); deck.shuffle();

hand.addCard(deck.dealCard());

message = "Ugadaite, starshe ili mladshe sleduyuschaya karta?"; gamelnProgress = true; repaint();

}

public void paintcomponent(Graphics g) { super.paintcomponent(g); g.setFont(bigFont);

g.drawstring(message,10,getSize().height-10); g.setFont(smallFont); int cardCt = hand.getCardCount(); for (int i = 0; i < cardCt; i++) drawCard(g, hand.getCard(i), 30 + i * 70, 10); if (gamelnProgress)

drawCard(g, null, 30 + cardCt * 70, 10); }

void drawCard(Graphics g, Card card, int x, int y) { if (card == null) { g.setColor(Color.blue); g.fillRect(x,y, 40, 60) ; g.setColor(Color.white) ; g.drawRect(x+3,y+3,33,53); g.drawRect(x+4,y+4,31,51);

}

else { int row = 0;

switch (card.getSuit ()) { case Card.CLUBS: row = 0; break; case Card.HEARTS: row = 1; break; case Card.SPADES: row = 2; break;

case Card.DIAMONDS: row = 3; break; }

int sx, sy;

sx = 4 0*(card.getValue() — 1); sy = 60*row;

g.drawlmage(cardimages, x, y, x+40, y+60, sx, sy, sx+40, sy+60, this);

}

} }

Внешний вид апплета показан на рис. 1.24.

Рис. 1.24. Игра "Угадай, что дальше?" Класс card описывает отдельную карту.

Листинг 1.27. Код класса Card, java

Отдельная карта

public class Card {

public final static int SPADES =0, // значения мастей HEARTS = 1, DIAMONDS = 2,

CLUBS = 3;

public final static int ACE =1,        // старшинство карт

JACK = 11, QUEEN = 12, KING = 13;

private final int suit; // один из вариантов:

// SPADES, HEARTS, DIAMONDS, CLUBS

private final int valued-

public Card(int theValue, int theSuit) { value = theValue;

suit = theSuit; }

public int getSuit () {

return suit; }

public int getValue() {

return value; }

public String getSuitAsString() { switch (suit) {

case SPADES: return "Spades"; case HEARTS: return "Hearts"; case DIAMONDS: return "Diamonds"; case CLUBS: return "Clubs"; default:   return "??";

}

}

public String getValueAsString() { switch (value) { case 1: return "Ace"; case 2: return "2"; case 3: return "3"; case 4: return "4"; case 5: return "5"; case 6: return "6"; case 7: return "7";

case 8: return "8"; case 9: return "9"; case 10: return "10"; case 11: return "Jack"; case 12: return "Queen"; case 13: return "King"; default: return "??";

}

public String toStringO {

return getValueAsString() + " of " + getSuitAsString();

Код класса Hand приводится далее (листинг 1.28). Он описывает сдаваемую карту или набор карт. Одновременно может быть сдано несколько карт, по умолчанию используется значение 5.

Листинг 1.28. Файл Hand.java

import java.util.Vectors- public class Hand {

private Vector hand; // сдаваемые карты public Hand() {

hand = new Vector(); }

public void clear() {

hand. removeAHElements () ; }

public void addCard(Card c) { if (c != null)

hand.addElement(c); }

public void removeCard(Card c) {

hand.removeElement(c); }

public void removeCard(int position) { if (position >= 0 && position < hand.sizeO)

hand.removeElementAt(position); }

public int getCardCount() {

return hand.size() ; }

public Card getCard(int position) { if (position >= 0 && position < hand.size())

return (Card)hand.elementAt(position); else

return null; }

public void sortBySuit() { Vector newHand = new Vector(); while (hand.size() >0) { int pos = 0;

Card с = (Card)hand.elementAt(0); for (int i = 1; i < hand.size(); i++) { Card cl = (Card)hand.elementAt(i); if (cl.getSuit () < c.getSuitO ||

(cl.getSuit() == c.getSuitO && cl.getValue() < с.getValue())) { pos = i;

с = cl; }

}

hand.removeElementAt(pos); newHand.addElement(c);

}

hand = newHand; }

public void sortByValue() { Vector newHand = new Vector(); while (hand.size() >0) { int pos = 0;

Card с = (Card)hand.elementAt(0); for (int i = 1; i < hand.size(); i++) { Card cl = (Card)hand.elementAt(i); if (cl.getValue() < c.getValue() II

(cl. getValue () == c. getValue () && cl.getSuit () < c.getSuitO)) { pos = i; с = cl;

}

hand.removeElementAt(pos); newHand.addElement(c);

hand = newHand; }

Кроме этого необходим класс, описывающий все 52 карты (листинг 1.29). Листинг 1.29. Файл Deck.java

public class Deck {

private Card[] deck; private int cardsUsed; public Deck() { deck = new Card [52]; int cardCt = 0;

for (int suit = 0; suit <= 3; suit++) { for (int value = 1; value <= 13; value++) { deck[cardCt] = new Card(value,suit);

cardCt++; }

cardsUsed = 0;

public void shuffle() {

for (int i = 51; i > 0; i—) {

int rand = (int)(Math.random()*(i+1));

Card temp = deck[i];

deck[i] = deck[rand];

deck[rand] = temp;

cardsUsed = 0;

public int cardsLeftO { return 52 — cardsUsed;

public Card dealCard() { if (cardsUsed = 52)

shuffle() ; cardsUsed++;

return deck[cardsUsed — 1]; }

}

Источник: Будилов В. А. Интернет-программирование на Java. — СПб.: БХВ-Петербург, 2003. — 704 е.: ил.

По теме:

  • Комментарии