Namo

6. java.AWT paketas: darbas su langais, įvykiais ir meniu

java.awt (awt - Abstract Windowing Toolkit) paketas yra vienas didžiausių. Jame patalpintos klasės skirtos kurti vartotojo aplinką. Šiame skyrelyje susipažinsime su langų kūrimo priemonėmis. Java langai savo funkcionalumu primena jums gerai pažįstamus "Windows" langus. Šiame pakete taip pat talpinamos klasės skirtos langų, pelės ir klaviatūros įvykiams apdoroti.

java.awt pakete taip pat yra standartinių grafikos elementų piešimo klasės. Garso, vaizdų ir animacijos organizavimas taip pat priskirtini java.awt paketui. Neatskiriama šio paketo dalis yra mygtukai, sąrašai, vėliavėlės ir t.t. Daugelis įskiepių metodų taip pat paveldima iš java.awt paketo klasių hierarchijos.

Langų sukūrimas

6-1 paveikslėlis iliustruoja langų klasių hierarchija šios klasės blokų galiojimo pirmumo medį.

6-1 paveikslėlis. Langų klasių hierarchijos medis.

Neskaitant standartinės Object klasės, hierarchijos viršuje yra abstrakti Component klasė. Abstrakti klasė pasižymi tuo, kad ji negali turėti egzempliorių (negalima apibrėžti objektus su  new  operatoriumi) ir joje yra bent vienas abstraktus metodas. Component klasė yra labai plati. Visų jos laukų ir metodų aprašymą rasite Java specifikacijos Component skyrelyje. Išvardinsime tik dalį dažniau naudojamų šios klasės metodų, kurių paskirtis suprantama iš pavadinimo:
add(PopupMenu popup), addComponentListener(ComponentListener l), addKeyListener(KeyListener l) , addMouseListener(MouseListener l), addMouseMotionListener(MouseMotionListener l) , addMouseWheelListener(MouseWheelListener l) , createImage(ImageProducer producer), createImage(int width, int height) , disableEvents(long eventsToDisable) , enableEvents(long eventsToEnable) , getBounds(), getCursor() , getFont() , getFontMetrics(Font font) , getGraphics() , getHeight() , getWidth() , imageUpdate(Image img, int infoflags, int x, int y, int w, int h), isEnabled() , paint(Graphics g) , paintAll(Graphics g) , remove(MenuComponent popup) , repaint() , repaint(long tmilisec, int x, int y, int width, int height) , setCursor(Cursor cursor) , setEnabled(boolean b) , setFont(Font f) , setVisible(boolean b) , update(Graphics g) ,

Kitos langų klasės būdamos Component vaikais paveldi visus jos metodus ir interfeisus. Tai patogu, nes galima įsisavinti Component elementų panaudojimą su kuria nors viena jos poklase, pavyzdžiui Buttons (mygtukai) ir kitose poklasėse naudojimas nieko nesiskirs. Kiek žemiau langų klasių hierarchijoje stovi Container klasė. Ji skirta stačiakampėje srityje išdėstyti atskirus grafinės vartotojo aplinkos elementus (pvz. mygtukus, išsirenkamuosius sąrašus ir pan.). Su atskirų elementų išdėstymo būdais galite susipažinti Java specifikacijos LayoutManager skyrelyje.

Toliau langų hierarchijoje stovi greta Panel ir Window klasės. Panel klasę naudoja Applet (įskiepių) klasė. Todėl čia jos plačiau neaptarsime. Window klasė skirta aukštutinio lygio langui. Vienas jo vaikų - Frame langas turi standartinį naudingų laukų ir metodų sąrašą ir praktiškai dažniausiai naudojamas. Šios klasės egzempliorius galima inicijuoti su antrašte arba be. Pavyzdžiui

Frame manoRemelis = new Frame(); Frame manoVardinisRemelis = new Frame("Tiesiog langas");

Sukūrus lango egzempliorių dažnai naudinga nurodyti jo dydį.
Pvz.:

manoRemelis.setSize(400,300);

Rėmelio dydis aprašomas nurodant grafinio ekrano taškelių skaičių  x  ir  y  kryptimis. Atkreipkite dėmesį, kad metodas setSize(int X, int Y) yra paskelbtas Component klasėje. Jei norite nurodyti ne tik dydį, bet ir rėmelio vietą ekrane, naudokite setLocation(int OX, int OY) metodą.
Pvz.:

manoRemelis.setLocation(50,50);

Padėties koordinatės nurodo viršutiniojo kairiojo rėmelio taško koordinates. Kompiuteriuose naudojama kiek neįprasta koordinačių sistema. Jos pradžios taškas laikomas kairysis viršutinis ekrano taškelis.

Metodas setBounds(int OX, int OY, int X, int Y) apjungia setLocation(int OX, int OY) ir setSize(int X, int Y) metodus į vieną.
Pvz.:

manoRemelis.setLocation(50,50); manoRemelis.setSize(400,300);

ir

manoRemelis.setBounds(50,50,400,300);

darbo rezultatas bus tas pats. Jeigu nenorite, kad vartotojas keistų jūsų rėmelio dydį, galite panaudoti tokį metodą:

manoRemelis.setResizable(false);

Rėmelį, kaip ir bet kurį langą, galima rodyti ekrane arba paslėpti. Pavyzdžiui, jei norite parodyti  manoRemelis  rėmelį, užrašykite komandą

manoRemelis.setVisible(true);

Atkreipkite dėmesį, kad nutylimoji rėmelio matomumo reikšmė yra  false  ir todėl bent kartą setVisible(true) turėsite panaudoti. Kiek kitokia show() metodo paskirtis. Jis naudojamas perpiešti ekrane išdėstytus langus taip, kad jūsų pasirinktas langas atsidurtų pačiame viršuje. Jei prieš show() metodo vykdymą langas nebuvo matomas, šis metodas padarys rėmelį matomu.

Rėmelis laikinai paslepiamas neatlaisvinant jo užimamų resursų su metodu hide() arba setVisible(false), o galutinai sunaikinamas atlaisvinant jo užimamus resursus su metodu dispose() .

Apjungiant keletą išvardintų metodų panaudojimą į vieną vietą gausime tokią paprastą vieno rėmelio sukūrimo Java klasę:

import java.awt.*; public class tiesiogRemelis{ public static final void main(String[] Arg){ // Paskelbiame rėmelio egzempliorių Frame manoRemelis = new Frame("Kuklus remelis"); // Nurodome jo vietą ir dydį ekrane manoRemelis.setLocation(50,50); manoRemelis.setSize(400,300); // Padarome rėmelį matomu viršuje kitų langų atžvilgiu manoRemelis.show(); } // main } // tiesiogRemelis

6-1 pvz. Paprasto rėmelio sukūrimo Java klasės pavyzdys.
tiesiogRemelis.java

6-2 paveikslėlis iliustruoja sukompiliuotos ir paleistos komandine eilute java tiesiogRemelis darbo rezultatą.

6-2 paveikslėlis. Paprasto rėmelio pavyzdys.

Šis rėmelis pasižymės standartinėmis langų savybėmis. Jis turi pavadinimą "kuklus remelis", su pele galėsite keisti jo vietą ir dydį, jis turės standartinius lango paslėpimo ir sunaikinimo mygtukus. Tačiau šio pavyzdžio lango sunaikinimo mygtukas neveiks. Kad sunaikinimo mygtukas atliktų norimus veiksmus reikia numatyti įvykių apdorojimą ir parašyti papildomus įvykių apdorojimo metodus. Apie tai kalbėsime vėliau.

Įvykių delegavimo mechanizmas

Java įvykių apdorojimas organizuojamas interfeisų  pagrindu. Kompiuterio periferijos įrenginiai - klaviatūra, pelė - reaguoja į vartotojo veiksmus ir persiunčia ("deleguoja") juos programinei įrangai. Java tai vadinama  įvykių delegavimo mechanizmu .

Bet kuris vartotojo veiksmas vadinamas  įvykiu  ( event ). Įvykių apdorojimas ir sudaro vartotojo interfeiso pagrindą. Skiriami dviejų rūšių įvykiai:  aparatūriniai  ir  semantiniai .

Aparatūriniai įvykiai yra išaukiami vartotojo mechaninių veiksmų. Pavyzdžiui klaviatūros mygtuko paspaudimas, pelės klavišo nuspaudimas, pelės ratuko pasukimas yra aparatūriniai įvykiai. Semantiniai įvykiai remiasi aparatūriniais įvykiais ir priklauso nuo tuo metu kompiuteryje naudojamų programų. Semantinių įvykių pavyzdžiai yra "Save" ar "File" meniu punktų išsirinkimo veiksmai. Aišku, kad atlikti semantinį įvykį, reikia apdoroti aibę paprastesnių įvykių.

Įvykių delegavimo modelyje naudojama ir įvykio  šaltinio  sąvoka. Šaltiniu gali būti langas, meniu punktas, valdymo mygtukas. Įvykis šiais atvejais generuojamas, kai pasikeičia šių elementų būsena.

Įvykių apdorojimui realizuoti naudojamas "klausymo" ( listener ) mechanizmas. Taigi gauname tokią grandinę: šaltinis generuoja įvykį, kuris yra perduodamas vienam ar keliems "klausytojams". Gavę pranešimą apie įvykį, klausymo metodai atlieka juose numatytus veiksmus ir grąžina valdymą atgal. Pavyzdžiui gana dažnai paspaudus viršutiniame dešiniajame rėmelio kampe patalpintą mygtuką rėmelis yra panaikinamas. Tai reiškia, kad buvo numatytas semantinio įvykio generavimas ir yra realizuotas jo apdorojimas.

Taigi kuriant vartotojo interfeisą yra numatoma grupė elementų, kurie domisi vartotojo veiksmai. Tokie elementai paskelbiami įvairių įvykių klausytojais ( listener ). Jei vartotoja atliko veiksmus generuojančius įvykį, to konkretaus tipo įvykio klausytojai atlieka juose numatytas operacijas, skirtas apdoroti įvykį.

Toliau susipažinsime su įvykių klasėmis ir interfeisais.

Įvykių klasės ir interfeisai

Yra dvi įvykių superklasės. Viena yra java.util paketo klasė EventObject.
Joje yra tik du metodai: getSource() ir toString(), kurie naudojami identifikuoti įvykio šaltinį. Pirmasis metodas grąžina įvykį generavusį šaltinį, o antrasis šaltinį identifikuoja tekstu.

AWT paketas turi savo įvykių apdorojimo hierarchiją. Šios hierarchijos viršūnėje yra java.awt paketo klasė AWTEvent. Įvykio tipas nustatomas getID() metodu.

Ir vienos ir kitos grupės įvykiai naudoja java.awt paketą Event. Joje skirtingo charakterio įvykiams skiriamos atskiros klasės. Išvardinsime ir trumpai apibūdinsime šias klases.

ActionEvent klasės įvykiai generuojami nuspaudus mygtuką, pasirinkus meniu punktą ir su pele išsirinkus sąrašo elementą.
Svarbiausi klasės metodai: getActionCommand() ir getSource() (pastarasis paveldėtas iš java.util.EventObject klasės).

AdjustmentEvent klasės įvykius geruoja ekrano perstūmimo slanksniuotė.
Svarbiausi metodai: getValue() ir getAdjusttable.

ComponentEvent klasės įvykiai geruojami aparatūriniu būdu, kai pasikeičia komponentės dydis, pozicija ir matomumas.
Šios klasės getComponent() metodas grąžina informaciją apie tai kokioje komponentėje įvyko įvykis.

ContainerEvent klasės įvykiai geruojami aparatūriniu įvykiu papildžius arba pašalinus iš konteinerio kokią nors komponentę. Šios klasės konstruktorius yra

public ContainerEvent(Component source, int id, Component child);

getChild() metodas grąžina nuorodą į komponentę, kuri buvo pridedama arba šalinama iš konteinerio. getContainer() metodas grąžins nuorodą į konteinerį, kuris buvo įvykio šaltinis. FocusEvent klasės aparatūriniu būdu generuojami įvykiai, kai komponentė gavo arba prarado dėmesį. Pavyzdžiui duomenis komponentėje galima įvesti tik tuo atveju, kai į ją atkreiptas dėmesys. Ši klasė turi du konstruktorius:

public FocusEvent(Component source, int id); // ir public FocusEvent(Component source, int id, boolean temporary);

Jei dėmesio perkėlimas yra pastovus (pvz. perėjimas į kitą duomenų laukelį), dėmesys pereina į kitą komponentę. Priešingu atveju laikinai nukreipus dėmesį į kitą veiksmą ir jį atlikus, dėmesys grįžta į komponentę. Pavyzdžiui paslėpus langą ir vėl jį aktyvavus dėmesys grįš į tą komponentę, kuri turėjo dėmesį prieš paslepiant langą.

InputEvent yra abstrakti klasė. Šios klasės aparatūriniai įvykiai generuojami nuspaudus arba atleidus klaviatūros bei pelės klavišus. Priklausomai nuo įvykio šaltinio yra generuojami šios klasės vaikų įvykiai KeyEvent arba MouseEvent.
isShiftDown(), isControlDown(), isAltDown() metodai naudojami nustatyti specialiųjų klavišų būseną.

ItemEvent klasės semantinio tipo įvykiai generuojami išsirinkus sąrašo elementą, pakeitus vėliavėlės būseną, pakeitus meniu punktą.
Dažniau naudojami klasės metodai: getItemSelectable() ir getItem(). Pirmasis metodas grąžina nuorodą į objektą, iš kurio buvo generuotas įvykis, o antrasis komponentę, kurią įvykis pakeitė.

KeyEvent klasės įvykiai generuojami klaviatūros aparatūriniu būdu.

MouseEvent yra analogiškas KeyEvent, tik aparatūrinio įvykio šaltinis šiuo atveju yra atliekami pele vartotojo veiksmai.

TextEvent klasės semantiniai įvykiai generuojami įvedant tekstą į teksto lauką ar sritį.
Klasės konstruktorius atrodo taip:

public TextEvent(Object source, int id);

 source  komponentės objektas, kuris generavo šį įvykį.

WindowEvent klasės aparatūriniai įvykiai generuojami lango viduje. Klasės konstruktorius yra

public WindowEvent(Window source, int id);

 source  - komponentės objektas (langas), kuris generavo šį įvykį.
 id  - sveikasis skaičius identifikuojantis įvykį.
Bene dažniausiai naudojamas metodas yra getWindow(), grąžinantis nuorodą į įvykio šaltinio objektą.

Analogiški charakteringų įvykių klasėms ir jų "klausymo" interfeisai. Šių interfeisų sąraše: ActionListener, AdjustmentListener, ComponentListener, ContainerListener, FocusListener, ItemListener, KeyListener, MouseListener, TextListener, WindowListener, trūksta tik InputEvent aprašymo.

Su įvykių generavimo ir jų apdorojimo praktiniu pavyzdžiu galite susipažinti vartotojo aplinkos užduoties aprašyme.

Rėmelio (Frame) įvykių apdorojimas

Rėmelyje (lange) vykstantys įvykiai yra klasės WindowEvent objektai. Kad reaguoti į šios klasės įvykius, pakete java.awt.event apibrėžtas WindowListener interfeisas. Jei savo programoje paskelbsite, kad kuri nors klasė implementuoja ( implements ) WindowListener, tai privalėsite realizuoti visus šio interfeiso metodus. Trumpai charakterizuosime kiekvieną interfeiso metodą: