Национална академия по разработка на софтуер



страница11/14
Дата25.07.2016
Размер2.68 Mb.
#6706
1   ...   6   7   8   9   10   11   12   13   14

Java аплети


В следващите няколко теми ще разгледаме технологията на Java аплетите, която ни позволява в HTML документи да вграждаме Java програмен код, който се изпълнява от Web-браузъра на потребителя при разглеждане на HTML документа. Поради факта, че тази технология бавно и лека полека започва да губи позиции за сметка на някои по-нови технологии (като например .NET Windows Forms Controls, Macromedia Flash и SVG контролите), ще си позволим да не й обърнем прекалено голямо внимание.

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

По-нататък ще продължим с изясняване на жизнения цикъл на аплетите.

След това ще направим кратък преглед на средствата, които Java платформата предоставя за създаване на прозоречно-ориентиран графичен потребителски интерфейс като обърнем внимание на някои от най-основни елементи на библиотеката AWT. Няма да си поставяме за цел да разгледаме цялата библиотека AWT нито нейните основни концепции и програмният й модел, защото това са специфични знания, които не са прекалено необходими на един Интернет разработчик. Очаква се читателите или да имат някакви основни познания по AWT или да разполагат със специализиран редактор за AWT-базиран графичен потребителски интерфейс, който да им помогне бързо да навлязат в материята, без да има нужда да я познават добре.

В последната част на темата за аплетите ще обясним какви са ограниченията, които са им наложени от съображения за сигурност. Ще видим как въпреки ограничените права, с които аплетите се изпълняват, можем да ги използваме за асинхронна сокет-базирана комуникация със сървъра, която стандартно не се поддържа във Web среда.

1.8.Въведение в Java аплетите


В първите години след като Java се появи, беше силно разпространено схващането, че този език служи единствено за създаване на аплетчета, които разширяват стандартните възможности на HTML и JavaScript и правят Web-страничките „по-раздвижени”. По това време такова схващане беше в голяма степен правилно, защото Java първоначално се използваше точно за това и масовото му използване за по-общи задачи започна по-късно. В следващите няколко години Java платформата постепенно се наложи като основен играч в софтуерната индустрия и в световен мащаб се утвърди като една от най-предпочитаните платформи за разработка на сложни корпоративни приложения.

Какво представляват Java аплетите


Аплетът е компилирана програма на Java, която се вгражда като обект в обикновена Web-страница и се изпълнява от Web-браузъра по време на разглеждането на тази страница. Аплетите се вграждат в Web-страниците по начин много подобен на вграждането на картинки, но за разлика от тях, те не са просто графични изображения, а програми, които използват правоъгълната област, която браузърът им дава, за графичния си потребителски интерфейс. Аплетите притежават почти цялата мощ която ни дава Java платформата, но с известни ограничения, наложени главно от съображения за сигурност. Те представляват компилирана Java програма във вид на .class файл или съвкупност от компилирани Java класове, записани в .jar архив.

Както знаем, всички Java програми се изпълняват от Java виртуална машина (JVM) и затова всички браузъри, които поддържат аплети, имат или вградена в себе си или допълнително инсталирана виртуална машина. При отварянето на HTML документ, съдържащ аплет, браузърът зарежда Java виртуалната си машина и стартира аплета в нея.

За да се осигури безопасността на потребителите аплетите се изпълняват с понижени права. Те нямат достъп до локалната файлова система, не могат да комуникират свободно по мрежата, не могат да изпълняват и да си комуникират с други програми, не могат да изпълняват системни функции, не могат да извличат информация за обкръжаващата ги среда и не могат да правят още много други действия, които застрашават по някакъв начин сигурността на потребителя или безопасността на неговите лични данни.

Как се създават Java аплети


Най-често Java аплетите наследяват класа java.applet.Applet и припокриват методите му за инициализация и за изчертаване върху екрана – съответно init() и paint(). В метода paint() аплетът изобразява графично на екрана текущото си състояние използвайки стандартните средства на Java за създаване на графичен потребителски интерфейс – AWT (Abstract Window Toolkit). Тези средства се намират в пакета java.awt и ще бъдат разгледани малко по-късно. Да се спрем за начало на един съвсем прост пример за аплет:

HelloWorldApplet.java

import java.applet.Applet;

import java.awt.Graphics;

public class HelloWorldApplet extends Applet {

public void paint(Graphics g) {

g.drawString("Hello world!", 50, 25);

}

}


Единственото, което прави аплетът от този пример, е в метода си за изобразяване на екрана да чертае текст в областта, която му е дадена от браузъра на позиция (50, 25) с шрифта по подразбиране.

Как се изпълняват Java аплети


Създаването на аплета HelloWorldApplet.java и компилирането му до .class файл не е достатъчно за да може той да се изпълни. За разлика от нормалните Java програми аплетите не е задължително да имат main() метод. За да видим резултата от нашия аплет трябва да направим Web-страница, в която да го вмъкнем като обект. Една възможност да направим това е следната::

HelloWorld.html

<html><body>

<p align="center">This is the applet:<br><br>

<applet code="HelloWorldApplet.class"

width="150" height="50">

applet>p>

body>html>

Използвахме HTML тага , в който зададохме името на класа, който искаме да вмъкнем като обект, както и размерите на областта от Web-страницата, която му се предоставя. Ако запишем този HTML код във файла HelloWorld.html и отворим този файл с Internet Explorer, ще получим резултат подобен на следния:

Друг начин да изпълним аплета ни дава програмата appletviewer, която е включена към стандартната инсталация на JDK. С нея също можем да изпълняваме аплети, но за разлика от стандартния браузър, appletviewer дава много повече права на аплета. Като параметър appletviewer приема име на HTML файл, който съдържа аплет.


Класът java.applet.Applet


Класът java.applet.Applet е базов клас за всички Java аплети и е наследник на класа java.awt.Panel. Той представлява стандартен AWT контейнер и следователно в него могат да се поставят различни AWT компоненти с цел изграждане на потребителски интерфейс. Освен за поставяне на компоненти, пространството на един аплет може да се използва и за директно рисуване със средствата на AWT, както това е направено в горния пример. Директното рисуване във вътрешността на аплета трябва да се прави само от метода paint(), защото иначе има риск да се наруши целостта на нарисуваното изображение ако то бъде застъпено от някакъв друг прозорец. Методът paint() се извиква винаги, когато аплетът има нужда да се пречертае.

Жизнен цикъл на аплетите


Класът java.applet.Applet дава базовата функционалност на аплетите и предоставя на наследниците си методи за взаимодействие с браузъра и външния свят. Нека се опитаме да проследим какво се случва от момента на зареждане на HTML-страницата с аплета до момента, в който се затвори браузърът или се премине на друга страница. Първоначално браузърът чете HTML документа и намира таговете. За всеки от тях намира и зарежда клас файла, който е указан, инстанцира го в Java виртуалната си машина и започва да го изпълнява.

Нека разгледаме жизнения цикъл на един аплет:



Както се вижда от диаграмата, изпълнението на аплет включва няколко отделни етапа: Първоначално се извиква се init() метода, а след него и start() метода. Докато аплетът работи, браузърът му подава всички събития, предназначени за него и го оповестява, когато е необходимо да се пречертае поради някаква причина. Събитията, отнасящи се до аплета, като кликване с мишката, натискане на клавиш и други такива се подават на метода handleEvent(), който извършва необходимото те да се обработят от AWT контролата, за която са предназначени. Събитията за пречертаване възникват когато се промени видимата част от аплета, например при скролиране на документа или при засичане на аплета с друг прозорец. Обработчикът по подразбиране на тези събития предизвиква извикване на метода paint(), при изпълнението на който аплетът е длъжен да се пречертае. При приключване на изпълнението на аплета, браузърът извиква последователно методите stop() и destroy().

Методът init() се извиква еднократно след като аплетът е инстанциран, т.е. е създаден като обект във виртуалната машина на браузъра. В него аплетът може да създаде контролите от потребителския си интерфейс, да направи някои инициализации и всичко останало, което трябва да се изпълни еднократно, преди аплетът да е стартиран. Методът start() се вика след инициализацията и след рестартиране на аплета. За разлика от init(), методът start() може да се извика и повече от веднъж. Методът stop() се извиква, когато браузърът напуска страницата, в която е зареден аплета. След stop() всички нишки на аплета минават в състояние на пауза. При връщане обратно в страницата с аплета, се вика start(). Поради липсата на точна спецификация различните Web-браузъри реализират по различен начин start() и stop() методите и затова използването им трябва да става внимателно, а при възможност да се избягва. Методът destroy() се извиква еднократно преди аплетът да се унищожи от браузъра. Може да се използва за освобождаване на ресурси.

Библиотеката AWT


AWT представлява платформено-независима библиотека от класове, която позволява създаване на графичен потребителски интерфейс с Java и дава цялостен компонентно-ориентиран framework за създаване на приложения, които взаимодействат активно с потребителя. Този framework ни предоставя стандартен начин за работа с графични контроли, като например прозорци, диалози, менюта, бутони, текстови полета, картинки, текст и др., а също и механизъм за обработка на събитията възникнали в резултат от взаимодействието между потребителя и програмата, като щракване с мишката, вход от клавиатурата и др.

Работата с AWT не е толкова проста и интуитивна, както при някои други компонентно-ориентирани библиотеки за създаване на графичен потребителски интерфейс, като например VCL библиотеката в Delphi и Windows Forms библиотеката в Microsoft .NET. Заради стремежът си да бъде мощна, универсална и лесно преносима библиотека AWT е станала сложна за използване и доста тромава, заради което вина има и самата архитектура на Java виртуалната машина, заради която повечето Java приложение са традиционно няколко пъти по-бавни от аналогични native приложения. Наистина едно от най-бавните неща в Java платформата са стандартните й средства за работа с графичен потребителски интерфейс – библиотеките AWT и Swing.


Архитектура Model-View-Controller


В архитектурно отношение AWT налага програмния модел MVC (model-view-controller) – модел, при който има строго разделение между данните (model), контролите, които ги визуализират (view) и логиката, която управлява извършените от потребителя действия (controller). Например една таблица в AWT е визуална контрола (view), която за да работи, изисква клас, който да й подава данните за визуализация (model) и клас, който да управлява извършените от потребителя действие (controller).

Аплетите и AWT


Координатната система на аплет с размери sizeX и sizeY започва от позиция (0,0), която отговаря на горния му ляв ъгъл и завършва в позиция (sizeX-1, sizeY-1), която отговаря на долния му десен ъгъл. Изобразяването на графични обекти във вътрешността на аплет става чрез класа java.awt.Graphics. Обекта от този клас, който съответства на аплета, се подава автоматично при всяко извикване на paint() метода му. Всеки Graphics обект има своя собствена координатна система и всеки AWT графичен компонент има свой собствен Graphics обект, чрез който той реализира визуализацията си. Класът Graphics ни дава методи за чертане на основните графични обекти, като линии, правоъгълници, елипси, запълнени многоъгълници, текст с различни шрифтове и много други. Описания на методите, с които се чертаят тези обекти, като drawLine(), drawRect(), fillRect(), clearRect(), drawOval(), fillOval(), drawArc(), fillArc(), drawPolygon(), fillPolygon() и др. могат да се намерят в документацията на JDK.

Използване на картинки от аплет


Освен директното чертане на геометрични фигури, AWT позволява и изобразяване на картинки, заредени от GIF или JPEG файлове. За целта се използва класа java.awt.Image и метода на класа Graphics drawImage(), който има няколко варианта с различни входни параметри. Най-лесният начин за зареждане на картинка в Image обект се дава от метода getImage() на класа Applet, който приема URL като параметър. Ето един пример как можем да заредим картинка:

URL imageURL = new URL("http://www.nakov.com/images/dot.jpg");

java.awt.Image img = this.getImage(imageURL);



За да начертаем върху аплета заредената картинка можем да използваме следния код:

public void paint(Graphics g) {

g.drawImage(img, 20, 10, this);

}


Ако искаме да начертаем картинката с променени размери, можем да използваме същия метод drawImage(), но с други параметри:

g.drawImage(img, 0, 0, img.getWidth(this)/4,

img.getHeight(this)/4, this);


Тънкости при работата с картинки в AWT


Внимателният читател вероятно е забелязал, че методът drawImage() приема един параметър, за който в нашите примери даваме стойност this. Това съвсем не е случайно и се обяснява с архитектурата на AWT и начина, по който се работи с картинки. Методът drawImage() приема като последен параметър обект, който реализира интерфейса ImageObserver. Зареждането на картинка в AWT винаги става асинхронно, т.е. извършва се паралелно с работата на програмата. Това е съвсем обосновано, като се има предвид, че зареждането на картинка от Интернет отнема известно време, а програмата може да го използва за други цели, вместо да чака. По идея методът drawImage() не изчаква картинката да бъде заредена и тогава да я начертае, а чертае само тази част от нея, която вече е заредена и веднага връща управлението на извикващия метод. Когато картинката се зареди напълно, се извиква методът imageUpdate() на интерфейса ImageObserver, който трябва да обработи ситуацията по подходящ начин. Най-често реализацията на метода imageUpdate() пречертава картинката, т.е. извиква метода drawImage().

Стандартно класът java.awt.Component, който е прародител на класа java.applet.Applet реализира интерфейсът ImageObserver и в метода си imageUpdate() пречертава областта от екрана, която е обхваната от картинката, която се е завършила своето зареждане. Използвайки тази базова функционалност на класа Applet, можем винаги, когато зареждаме картинки от аплет, да подаваме за ImageObserver самия аплет, т.е. обекта this.

Когато зареждаме картинки винаги трябва да внимаваме да не разчитаме, че дадена картинка ще се зареди веднага. Картинките винаги се зареждат асинхронно и затова трябва да се грижим да ги чертаем едва след като са заредени или поне да ги пречертаваме след това.

За изчакване на асинхронното зареждане на картинка в AWT има специален клас java.awt.MediaTracker, на който чрез метода addImage(…) може да му се подават картинки, които са в процес на зареждане, след което може да се изчака приключването на зареждането на всички картинки чрез метода waitForAll().


Пример за аплет за анимация


Да разгледаме един цялостен пример за аплет, който използва картинки и реализира проста анимация чрез допълнителна нишка. Да си поставим за задача направата на Java аплет, в който една топка постоянно се движи и се отблъсква в стените на аплета при удар (както при игра на билярд). Едно възможно решение на задачата е следното:

BallApplet.java

import java.awt.*;

import java.applet.*;

public class BallApplet extends Applet implements Runnable {

public static final int ANIMATION_SPEED = 10;

public static final String IMAGE_NAME_PARAM = "imageName";

private int mBallX, mBallY, mBallSpeedX, mBallSpeedY;

private Image mBallImage;

private Image mImageBuffer;

private Graphics mImageBufferGraphics;

private Thread mAnimationThread;

private boolean mAnimationThreadInterrupted = false;

/**

* Applet's init() method. Makes some initializations

* and loads the ball image. This method is called before

* creating the animation thread so no synchronization

* is needed.

*/

public void init() {

// Load the ball image from the server

String imageName = getParameter(IMAGE_NAME_PARAM);



if (imageName == null) {

System.err.println("Applet parameter " +

IMAGE_NAME_PARAM + " is missing.");

System.exit(-1);

}

mBallImage = getImage(getCodeBase(), imageName);



// Wait for the image to load completely

MediaTracker tracker = new MediaTracker(this);

tracker.addImage(mBallImage,0);

try {

tracker.waitForAll();

} catch (InterruptedException ie) { }

if (tracker.statusAll(true) != MediaTracker.COMPLETE) {

System.err.println("Can not load " + imageName);

System.exit(-1);

}

// Initialize the ball image coordinates and speed

mBallX = 1;

mBallY = 1;

mBallSpeedX = 1;

mBallSpeedY = 1;



// Create an image buffer for the animation

mImageBuffer = createImage(

getSize().width, getSize().height);

mImageBufferGraphics = mImageBuffer.getGraphics();

}

/**

* Applet's paint() method. Draws the ball on its current

* position. This method can be called in the same time

* from both the applet's thread and from the animation

* thread so it should be thread safe (synchronized).

*/

public void paint(Graphics aGraphics) {

synchronized (this) {

if (mAnimationThread != null) {

// Paint in the buffer

mImageBufferGraphics.fillRect(

0, 0, getSize().width, getSize().height);

mImageBufferGraphics.drawImage(

mBallImage, mBallX, mBallY, this);

// Copy the buffer contents to the screen

aGraphics.drawImage(mImageBuffer, 0, 0, this);

}

}

}



/**

* Applet's start() method. Creates the animation thread

* and starts it if it is not already running. This method

* can be called only from the applet's thread so it does

* not require synchronization.

*/

public void start() {

if (mAnimationThread == null) {

mAnimationThreadInterrupted = false;

mAnimationThread = new Thread(this);

mAnimationThread.start();

}

}

/**



* Applet's stop() method. Asks the animation thread to

* stop its execution and waits until it is really stopped.

* This method is called only from the applet's thread so

* it does not need synchronization except when accessing

* the variable mAnimationThreadInterrupted that is common

* for applet's thread and animation thread.

*/

public void stop() {

synchronized (this) {

mAnimationThreadInterrupted = true;

}

try {

mAnimationThread.join();

} catch (InterruptedException ie) { }

mAnimationThread = null;

}

/**

* Animation thread's run() method. Continuously changes

* the ball position and redraws it and thus an animation

* effect is achived. This method runs in a separate thread

* that is especially created for the animation. A

* synchronization is needed only when accessing variables

* that are common for the applet's thread and animation

* thread.

*/

public void run() {

// Calculate the animation area size

int maxX, maxY;

synchronized (this) {

maxX = this.getSize().width -

mBallImage.getWidth(this);

maxY = this.getSize().height -

mBallImage.getHeight(this);

}

// Perform continuously animation



while (true) {

synchronized (this) {

// Check if the thread should stop

if (mAnimationThreadInterrupted)

break;

// Calculate the new ball coordinates

if ((mBallX >= maxX) || (mBallX <= 0))

mBallSpeedX = -mBallSpeedX;

mBallX = mBallX + mBallSpeedX;

if ((mBallY >= maxY) || (mBallY <= 0))

mBallSpeedY = -mBallSpeedY;

mBallY = mBallY + mBallSpeedY;

}

// Redraw the applet contents

paint(getGraphics());

// Wait some time to slow down the animation speed

try {

Thread.sleep(ANIMATION_SPEED);

} catch (Exception ex) {}

}

}



}

Как работи аплета за анимация


Създаването на анимация по принцип не е много проста работа, защото изисква управление на нишки. Необходимо е добро познаване на жизнения цикъл на аплетите, познаване на библиотеката AWT, умения за работа с нишки и синхронизация на достъпа до общи ресурси.

Нашият примерен аплет за анимация работи по следния начин: При инициализация, в метода init(), аплетът зарежда картинката, която ще се движи (в нашия случай това е топка), инициализира координатите и посоката й на движение и създава специален буфер за чертане за целите на анимацията.

При стартиране на аплета, когато се извиква методът му start(), се създава една нишка, която се грижи за анимацията. Всичко, което тя прави е да променя през определено време (в случая 10 милисекунди) координатите по x и по y на топката съгласно текущата посока на движение, да сменя посоката на движение при удар в стена и след всяка промяна на координатите на топката да пречертава цялото съдържание на аплета. Методът start() няма нужда от синхронизация, защото когато се изпълнява единствената работеща нишка е нишката на аплета.

При извикване на stop() метода аплетът спира нишката и я изчаква да приключи изпълнението си. Когато този метод се извика е възможно да работят едновременно две нишки – нишката на аплета и нишката за анимация и затова е необходима синхронизация при достъпа до общи за двете нишки променливи.

Пречертаването на аплета (paint(…) метода) работи с буфериране за да се избегне трепкането, което би се получило ако се изтрие съдържането на аплета и след това се начертае върху него движещият се обект на текущата му позиция. Пречертаването е операция, която може да се извика едновременно от две различни нишки. Нишката на аплета може по всяко време да извика пречертаване заради засичане на аплета с друг прозорец или по някаква друга причина, а нишката за анимация също по всяко време да извика пречертаване заради нуждата от движение на топката. За да не се засичат две пречертавания, понеже те биха използвали един и същ работен буфер, е необходимо пречертаването да е синхронизирана операция.

Техниката „двойно буфериране”


Пречертаването на аплета работи със специален буфер. Този буфер се използва за да се избегне премигването и да се получи наистина плавно движение. При всяко пречертаване на аплета буферът се изчиства с fillRect(), след това в него се начертава топката на текущата й позиция и на екрана се изобразява съдържанието на този буфер. Тази техника за избягване на премигването при създаване на анимация се нарича „двойно буфериране” (double buffering). При стартиране на аплета се създава обект от класа Image и се работи чрез неговия Graphics обект. Вместо да се рисува директно върху аплета, се рисува в буфера и след това нарисуваният вече кадър от буфера се прехвърля върху повърхността на аплета.

Името на файла, който съдържа картинката, се задава като параметър на аплета и се взема с метода getParameter(). Параметрите на аплетите служат за задаване на различни настройки без да е необходима прекомпилация, ако се налага ако тези настройки бъдат променени. За задаването им има специален таг, който се влага в така – тага
.

Стартиране на аплета за анимация


Ето един примерен HTML код, който стартира нашия аплет и задава за параметъра име на картинка imageName стойността ball.jpg:

BallAppletTest.html

<html>

<head><title>Ball Applet – Test Pagetitle>head>

<body>

<applet code="BallApplet.class" width="200" height="150">

<param name="imageName" value="ball.jpg">

applet>

body>

html>

Разбира се, в директорията, където е записан този html файл е необходимо да запишем компилирания аплет BallApplet.class, както и файла с топката, която ще подскача в аплета – ball.jpg.

В инициализационната си част аплетът взима параметъра imageName и зарежда картинката с това име от същата директория, от която е зареден аплетът. URL, сочещо към тази директория може да се получи чрез метода getCodeBase(). Такъв е правилният начин за извличане на ресурс от аплет – не чрез абсолютен URL, а чрез релативен URL, зададен спрямо директорията, от която е зареден аплетът.

След като е извикан методът за зареждане на картинка тя е започва да се зарежда от зададения URL. Понеже, както знаем, работата с картинки в AWT е асинхронна, е необходимо да изчакаме картинката с топката да се зареди напълно преди да се обръщаме към нея. За целта се използва класът MediaTracker, чрез който може да се проследи състоянието на започнали да се зареждат картинки.

Аплетът за анимация в действие


Ето как изглежда резултата от нашия аплет, видян през Internet Explorer:

За да изглежда добре е необходимо картинката, която представлява топката (ball.jpg) да е по-малка от размерите на аплета и да бъде на черен фон.



Каталог: books -> inetjava
books -> В обятията на шамбала
books -> Книга се посвещава с благодарност на децата ми. Майка ми и жена ми ме научиха да бъда мъж
books -> Николай Слатински “Надеждата като лабиринт” София, Издателство “виденов & син”, 1993 год
books -> София, Издателство “Българска книжница”, 2004 год. Рецензенти доц д. ик н. Димитър Йончев, проф д-р Нина Дюлгерова Научен редактор проф д-р Петър Иванов
books -> Николай Слатински “Измерения на сигурността” София, Издателство “Парадигма”, 2000 год
books -> Книга 2 щастие и успех предисловие
books -> Превръщане на числа от една бройна система в друга
books -> Тантриското преобразяване


Сподели с приятели:
1   ...   6   7   8   9   10   11   12   13   14




©obuch.info 2024
отнасят до администрацията

    Начална страница