Java и обработка на събития

Повечето програми, за да бъдат полезни, трябва да отговарят на команди от потребителя. За целта Java програмите разчитат на събития, които описват действията на потребителя.

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

Да се ​​управлява от събития

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

Анкетирането свършва работата, но е склонно да бъде тромаво, когато се използва в съвременни приложения поради две свързани причини: Първо, използването на анкета има тенденция да изтласка целия код за обработка на събития на едно място (вътре в големия цикъл); второ, получените взаимодействия в рамките на голямата верига са склонни да бъдат сложни. В допълнение, анкетирането изисква програма да се намира в цикъл, консумирайки цикли на процесора, докато чака потребителят да направи нещо - сериозна загуба на ценен ресурс.

AWT решава тези проблеми, възприемайки различна парадигма, която лежи в основата на всички съвременни прозоречни системи: програмирано от събития. В рамките на AWT всички потребителски действия принадлежат към абстрактен набор от неща, наречени събития . Събитието описва достатъчно подробно конкретно действие на потребителя. Вместо програмата активно да събира генерирани от потребителя събития, времето за изпълнение на Java уведомява програмата, когато се случи интересно събитие. За програми, които се справят с взаимодействието на потребителите по този начин, се казва, че се управляват от събития .

Класът на събитието

Класът на събитието е основният играч в играта на събитието. Той се опитва да улови основните характеристики на всички генерирани от потребителя събития. Таблица 1 изброява членовете на публичните данни, предоставени от клас Събитие.

Тип Име Описание
Обект цел Препратка към компонента, който първоначално е получил събитието.
дълго кога Моментът във времето, в който се е случило събитието.
инт документ за самоличност Типът на събитието (вижте раздел Типове събития за повече информация).
инт х Координатата x, при която се е случило действието, спрямо компонента, който в момента обработва събитието. За дадено събитие координатата x ще се промени по стойност, когато събитието се придвижва нагоре по йерархията на компонентите. Началото на координатната равнина е в горния ляв ъгъл на компонента.
инт у Координатата y, при която се е случило действието спрямо компонента, който в момента обработва събитието. За дадено събитие координатата y ще се промени по стойност, когато събитието се придвижва нагоре по йерархията на компонентите. Началото на координатната равнина е в горния ляв ъгъл на компонента.
инт ключ За събития от клавиатурата, клавишът на току-що натиснатия бутон. Стойността му обикновено ще бъде Unicode стойността на символа, който ключът представлява. Други възможности включват стойности за специалните бутони HOME, END, F1, F2 и т.н.
инт модификатори Аритметично или комбинирана комбинация от стойностите SHIFT_MASK, CTRL_MASK, META_MASK и ALT_MASK. Стойността му представлява съответно състоянието на клавишите shift, control, meta и alt.
инт clickCount Броят на последователните кликвания на мишката. Този член с данни е важен само за събития MOUSE_DOWN.
Обект аргумент Аргумент, зависим от събитие. За обекти на бутон този обект е обект String, който съдържа текстурния етикет на бутона.
Таблица 1: Членове на публични данни, предоставени от клас Събитие

Както ще обясня в раздела, озаглавен Разпращане и разпространение на събития, екземпляр на клас Събитие обикновено се създава от системата за изпълнение на Java. Възможно е обаче една програма да създава и изпраща събития към компоненти чрез техния postEvent()метод.

Типове събития

Както бе споменато по-горе, класът Събитие е модел на събитие от потребителския интерфейс. Събитията естествено попадат в категории въз основа на вида на събитието (видът на събитието е посочен от idчлена на данните). Таблица 2 изброява всички събития, дефинирани от AWT, сортирани по категории.

Таблица 2: Събития, дефинирани от AWT, сортирани по категории

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

За да видите този аплет, ви е необходим браузър с активиран Java

Фигура 1: Генериране на събитие в действие

Изпращане и разпространение на събития

Помислете за аплета на фигура 2. Той се състои от два екземпляра от клас Button, вградени в екземпляр от класа Panel. Този екземпляр на класа Panel сам е вграден в друг екземпляр на класа Panel. Последният екземпляр на класа Panel се намира под екземпляр на клас TextArea и двата екземпляра са вградени в екземпляр на класа Applet. Фигура 3 представя елементите, от които е съставен този аплет, разположени като дърво, с екземпляри TextArea и Button като листа и екземпляр на аплет като корен. (За повече информация относно йерархичното оформление на компонентите в потребителския интерфейс прочетете въведението от миналия месец към AWT.)

За да видите този аплет, ви е необходим браузър с активиран Java

Фигура 2: Класове, вградени в класове

Фигура 3: Дърво на елементите на аплетите (йерархия)

Когато потребителят взаимодейства с аплета на Фигура 2, системата за изпълнение на Java създава екземпляр на клас Събитие и изпълва своите членове с данни с информация, описваща действието. Тогава системата за изпълнение на Java позволява на аплета да обработва събитието. Той започва с компонента, който първоначално е получил събитието (например бутона, върху който е щракнат), и се придвижва нагоре по дървото на компонентите, компонент по компонент, докато достигне контейнера в горната част на дървото. По пътя всеки компонент има възможност да игнорира събитието или да реагира на него по един (или повече) от следните начини:

  • Променете членовете на данните на екземпляра на събитието
  • Действайте и извършете някои изчисления въз основа на информацията, съдържаща се в събитието
  • Посочете на системата за изпълнение на Java, че събитието не трябва да се разпространява по-нагоре по дървото

Системата за изпълнение на Java предава информация за събитие на компонент чрез handleEvent()метода на компонента . Всички валидни handleEvent()методи трябва да са във формата

публично булево handleEvent (Събитие e) 

Манипулаторът на събития изисква единична информация: препратка към екземпляра на класа на събитието, съдържащ информация за току-що настъпилото събитие.

Стойността, върната от handleEvent()метода, е важна. Той показва на системата за изпълнение на Java дали събитието е било обработено изцяло в рамките на манипулатора на събития. Истинската стойност показва, че събитието е обработено и разпространението трябва да спре. Фалшивата стойност показва, че събитието е игнорирано, не може да бъде обработено или е обработено непълно и трябва да продължи нагоре по дървото.

Consider the following description of an imaginary user's interaction with the applet in Figure 2. The user clicks on the button labeled "One." The Java language run-time system gathers information about the event (the number of clicks, the location of the click, the time the click occurred, and the component that received the click) and packages that information in an instance of the Event class. The Java run-time system then begins at the component that was clicked (in this case, the Button labeled "One") and, via a call to the component's handleEvent() method, offers the component a chance to react to the event. If the component does not handle the event or handles the event incompletely (indicated by a return value of false), the Java run-time system offers the Event instance to the next higher component in the tree -- in this case an instance of the Panel class. The Java run-time system continues in this manner until the event is handled or the run-time system runs out of components to try. Figure 4 illustrates the path of this event as the applet attempts to handle it.

Figure 4: The path of an event

Each component making up the applet in Figure 2 adds a line to the TextArea object that indicates it received an event. It then allows the event to propagate to the next component in the tree. Listing 1 contains the code for a typical handleEvent() method. The complete source code for this applet is available here.

public boolean handleEvent(Event evt) { if (evt.id == Event.ACTION_EVENT) { ta.appendText("Panel " + str + " saw action...\n"); } else if (evt.id == Event.MOUSE_DOWN) { ta.appendText("Panel " + str + " saw mouse down...\n"); }

return super.handleEvent(evt); }

Listing 1: A typical handleEvent() method

Event helper methods

The handleEvent() method is one place a programmer can put application code for handling events. Occasionally, however, a component will only be interested in events of a certain type (for example, mouse events). In these cases, the programmer can place the code in a helper method, rather than placing it in the handleEvent() method.

Here is a list of the helper methods available to programmers. There are no helper methods for certain types of events.

action(Event evt, Object what)

gotFocus(Event evt, Object what)

lostFocus(Event evt, Object what)

mouseEnter(Event evt, int x, int y)

mouseExit(Event evt, int x, int y)

mouseMove(Event evt, int x, int y)

mouseUp(Event evt, int x, int y)

mouseDown(Event evt, int x, int y)

mouseDrag(Event evt, int x, int y)

keyDown(Event evt, int key)

keyUp(Event evt, int key)

false to indicate that the helper method did not handle the event.

The implementation of the handleEvent() method provided by class Component invokes each helper method. For this reason, it is important that the redefined implementations of the handleEvent() method in derived classes always end with the statement

return super.handleEvent(e);

The code in Listing 2 illustrates this rule.

public boolean handleEvent(Event e) { if (e.target instanceof MyButton) { // do something... return true; }

return super.handleEvent(e); }

Listing 2: Rule for ending statement in handleEvent() method

Failure to follow this simple rule will prevent the proper invocation of helper methods.

Figure 5 contains an applet that handles mouse events solely through code placed in helper methods. The source code is available here.

Event evt The next event in a linked list of events.
Window events
Window events are generated in response to changes in the state of a window, frame, or dialog.
Event ID
WINDOW_DESTROY 201
WINDOW_EXPOSE 202
WINDOW_ICONIFY 203
WINDOW_DEICONIFY 204
WINDOW_MOVED 205
Keyboard events
Keyboard events are generated in response to keys pressed and released while a component has input focus.
Event ID
KEY_PRESS 401
KEY_RELEASE 402
KEY_ACTION 403
KEY_ACTION_RELEASE 404
Mouse events
Mouse events are generated in response to mouse actions occurring within the boundary of a component.
Event ID
MOUSE_DOWN 501
MOUSE_UP 502
MOUSE_MOVE 503
MOUSE_ENTER 504
MOUSE_EXIT 505
MOUSE_DRAG 506
Scroll events
Scroll events are generated in response to manipulation of scrollbars.
Event ID
SCROLL_LINE_UP 601
SCROLL_LINE_DOWN 602
SCROLL_PAGE_UP 603
SCROLL_PAGE_DOWN 604
SCROLL_ABSOLUTE 605
List events
List events are generated in response to selections made to a list.
Event ID
LIST_SELECT 701
LIST_DESELECT 702
Miscellaneous events
Miscellaneous events are generated in response to a variety of actions.
Event ID
ACTION_EVENT 1001
LOAD_FILE 1002
SAVE_FILE 1003
GOT_FOCUS 1004
LOST_FOCUS 1005
Тод Съндстед програмира, откакто компютрите стават достъпни в настолни модели. Въпреки че първоначално се интересуваше от изграждането на разпределени обектни приложения в C ++, Тод се премести на езика за програмиране Java, когато Java стана очевиден избор за такъв тип неща. В допълнение към писането, Тод предоставя консултантски услуги за интернет и уеб приложения на компании в югоизточната част на САЩ.

Научете повече за тази тема

  • Урокът за Java от Мери Кампионе и Кати Уолрат. Онлайн проектната версия е достъпна на //java.sun.com/tutorial/index.html.

Тази история „Java и обработка на събития“ първоначално е публикувана от JavaWorld.